[
  {
    "path": ".claudeignore",
    "content": "gradle/\n.git/\n.github/\n*.jar\n*.class\n"
  },
  {
    "path": ".gitattributes",
    "content": "#\n# https://help.github.com/articles/dealing-with-line-endings/\n#\n# These are explicitly windows files and should use crlf\n*.bat           text eol=crlf\n\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ncustom: https://bg-software.com/patreon\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yaml",
    "content": "name: Bug Report\ndescription: Report a Bug or an Issue in the plugin.\nlabels: [ 'Bug Report', 'Pending' ]\nassignees: OmerBenGera\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ## SuperiorSkyblock2 Issues Tracker\n        You may be able to find the answer on our [Wiki](https://wiki.bg-software.com/#/superiorskyblock/), or get a quick answer to basic questions on our [Discord](https://bg-software.com/discord/).\n        Be sure to check for existing [Issues](https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues).\n        <br />\n\n  - id: minecraft\n    type: textarea\n    validations:\n      required: true\n    attributes:\n      label: 'Minecraft''s Version'\n      description: |\n        The minecraft version your server run on. Use /version to find which version you use.\n        Make sure you give the exact output of the command.\n      placeholder: |\n        [Insert minecraft version and server jar.]\n\n  - id: plugin\n    type: textarea\n    validations:\n      required: true\n    attributes:\n      label: 'Plugin''s Version'\n      description: |\n        The version of the plugin. Use /version SuperiorSkyblock2 and find which version you use.\n        Make sure you give the exact output of the command.\n      placeholder: |\n        [Insert plugin version and if it is a dev build.]\n\n  - id: description\n    type: textarea\n    validations:\n      required: true\n    attributes:\n      label: 'Describe the bug'\n      description: |\n        A clear and concise description of what the bug is.\n      placeholder: |\n        [Insert what exactly the problem is.]\n\n  - id: reproduction\n    type: textarea\n    validations:\n      required: true\n    attributes:\n      label: 'To Reproduce'\n      description: |\n        Steps to reproduce the bug.\n      placeholder: |\n        [Insert what exactly happened and the steps to reproduce the issue.]\n\n  - id: extra\n    type: textarea\n    attributes:\n      label: 'Additional Information'\n      description: |\n        Additional information that can help understanding the issue.\n        Config file, clips, etc are more than welcome.\n      placeholder: |\n        Drag and drop an image or video onto this field to upload it. Otherwise please use pastebin for configs.\n\n  - type: markdown\n    attributes:\n      value: |\n        ## Thank you for helping improve SuperiorSkyblock2!\n        Please remember to check back for any questions being asked and reply back as soon as you can!\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Feature Requests\n    url: https://github.com/OmerBenGera/SuperiorSkyblock2/discussions\n    about: Create feature requests, any posted in issue tracker will be removed.\n"
  },
  {
    "path": ".github/workflows/gemini.yml",
    "content": "name: Gemini Issue Fixer\non:\n  issues:\n    types: [opened, edited]\n  issue_comment:\n    types: [created]\n\njobs:\n  gemini-fix:\n    if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@gemini')\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n      issues: write\n      id-token: write\n    steps:\n      - uses: actions/checkout@v4\n      - name: Set up Python\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.10'\n      - name: Install Aider (The Agent Engine)\n        run: |\n          python -m pip install --upgrade pip\n          pip install aider-chat\n      - name: Run Gemini Fix\n        env:\n          GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          git config --global user.name \"Gemini AI\"\n          git config --global user.email \"gemini-ai@github.com\"\n          \n          BRANCH_NAME=\"bugfix/issue-${{ github.event.issue.number }}\"\n          git checkout -b \"$BRANCH_NAME\"\n          \n          aider --model gemini/gemini-3-flash-preview \\\n            --yes \\\n            --commit \\\n            --message \"Analyze the following issue and provide a fix in a new branch with a PR. Make changes to the source code and commit the changes to the branch $$BRANCH_NAME. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}\"\n          \n          git push origin \"$BRANCH_NAME\"\n          \n          gh pr create \\\n            --title \"Fix: ${{ github.event.issue.title }}\" \\\n            --body \"Automated fix for #${{ github.event.issue.number }} generated by Gemini.\" \\\n            --base dev \\\n            --head \"$BRANCH_NAME\""
  },
  {
    "path": ".gitignore",
    "content": "# Ignore Gradle project-specific cache directory\n.gradle\ngradle.properties\n\n# Ignore Gradle build output directory\nbuild\n\n# Ignore intellij files\n.idea\n*.iml\n\n# Ignore output generated files\ntarget\nout"
  },
  {
    "path": "API/build.gradle",
    "content": "plugins {\n    id 'maven-publish'\n}\n\njava {\n    withSourcesJar()\n}\n\ngroup 'API'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R1:latest\"\n}\n\n\npublishing {\n    publications {\n        maven(MavenPublication) {\n            groupId = 'com.bgsoftware'\n            artifactId = 'SuperiorSkyblockAPI'\n            version = parent.version\n\n            from components.java\n        }\n    }\n\n    repositories {\n        String mavenUsername = System.getenv('mavenUsername');\n        String mavenPassword = System.getenv('mavenPassword');\n\n        if (mavenUsername != null && mavenPassword != null) {\n            maven {\n                url 'https://repo.bg-software.com/repository/api/'\n                credentials {\n                    username mavenUsername\n                    password mavenPassword\n                }\n            }\n        }\n    }\n\n}\n\ntask generateAPIDocs(type: Javadoc) {\n    source = sourceSets.main.allJava\n}"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java",
    "content": "package com.bgsoftware.superiorskyblock.api;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.CommandsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.KeysManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.MenusManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.MissionsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.ModulesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.PlayersManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.RolesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.SchematicManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager;\nimport com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\nimport org.bukkit.plugin.Plugin;\n\npublic interface SuperiorSkyblock extends Plugin {\n\n    /**\n     * Get the grid of the core.\n     */\n    GridManager getGrid();\n\n    /**\n     * Get the stacked-blocks manager of the core.\n     */\n    StackedBlocksManager getStackedBlocks();\n\n    /**\n     * Get the blocks manager of the core.\n     */\n    BlockValuesManager getBlockValues();\n\n    /**\n     * Get the schematics manager of the core.\n     */\n    SchematicManager getSchematics();\n\n    /**\n     * Get the players manager of the core.\n     */\n    PlayersManager getPlayers();\n\n    /**\n     * Get the roles manager of the core.\n     */\n    RolesManager getRoles();\n\n    /**\n     * Get the missions manager of the core.\n     */\n    MissionsManager getMissions();\n\n    /**\n     * Get the menus manager of the core.\n     */\n    MenusManager getMenus();\n\n    /**\n     * Get the keys manager of the core.\n     */\n    KeysManager getKeys();\n\n    /**\n     * Get the providers manager of the core.\n     */\n    ProvidersManager getProviders();\n\n    /**\n     * Get the upgrades manager of the core.\n     */\n    UpgradesManager getUpgrades();\n\n    /**\n     * Get the commands manager of the core.\n     */\n    CommandsManager getCommands();\n\n    /**\n     * Get the settings of the plugin.\n     */\n    SettingsManager getSettings();\n\n    /**\n     * Get the objects factory of the plugin.\n     */\n    FactoriesManager getFactory();\n\n    /**\n     * Get the modules manager of the plugin.\n     */\n    ModulesManager getModules();\n\n    /**\n     * Get the script engine of the plugin.\n     */\n    IScriptEngine getScriptEngine();\n\n    /**\n     * Set the script engine of the plugin.\n     *\n     * @param scriptEngine The script engine to set.\n     *                     When null, the default java script engine will be set instead.\n     */\n    void setScriptEngine(@Nullable IScriptEngine scriptEngine);\n\n    /**\n     * Get the events dispatcher of the plugin.\n     *\n     * @return The events dispatcher, or null if the default events dispatcher is used.\n     */\n    @Nullable\n    IEventsDispatcher getEventsDispatcher();\n\n    /**\n     * Sets a custom events dispatcher for the plugin.\n     *\n     * @param eventsDispatcher The new events dispatcher to set.\n     *                         When null, the default events dispatcher will be used instead.\n     */\n    void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java",
    "content": "package com.bgsoftware.superiorskyblock.api;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.CommandsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.KeysManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.MenusManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.MissionsManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.ModulesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.PlayersManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.RolesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.SchematicManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.entity.Player;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\n\npublic class SuperiorSkyblockAPI {\n\n    private static SuperiorSkyblock plugin;\n\n    /**\n     * Private constructor to prevent people from creating an instance of this class.\n     */\n    private SuperiorSkyblockAPI() {\n\n    }\n\n    /*\n     * General Methods\n     */\n\n    /**\n     * Get the plugin instance.\n     */\n    public static SuperiorSkyblock getSuperiorSkyblock() {\n        return plugin;\n    }\n\n    /**\n     * Set the plugin's instance for the API.\n     * Do not use this method on your own, as it may cause an undefined behavior when using the API.\n     *\n     * @param plugin The instance of the plugin to set to the API.\n     */\n    public static void setPluginInstance(SuperiorSkyblock plugin) {\n        if (SuperiorSkyblockAPI.plugin != null) {\n            throw new UnsupportedOperationException(\"You cannot initialize the plugin instance after it was initialized.\");\n        }\n\n        SuperiorSkyblockAPI.plugin = plugin;\n    }\n\n    /**\n     * Get the version of the API.\n     * Everytime a change is made to the API, the version of it changes.\n     */\n    public static int getAPIVersion() {\n        return 16;\n    }\n\n    /*\n     *  Player Methods\n     */\n\n    /**\n     * Get the superior player object from a player instance.\n     */\n    public static SuperiorPlayer getPlayer(Player player) {\n        return plugin.getPlayers().getSuperiorPlayer(player.getUniqueId());\n    }\n\n    /**\n     * Get the superior player object by a player's name.\n     */\n    @Nullable\n    public static SuperiorPlayer getPlayer(String name) {\n        return plugin.getPlayers().getSuperiorPlayer(name);\n    }\n\n    /**\n     * Get the superior player object from a player's uuid.\n     *\n     * @param uuid player uuid\n     * @return The superior player object. null if doesn't exist.\n     */\n    public static SuperiorPlayer getPlayer(UUID uuid) {\n        return plugin.getPlayers().getSuperiorPlayer(uuid);\n    }\n\n    /*\n     *  Island Methods\n     */\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer owner of the island\n     * @param schemName      the schematic of the island to be pasted\n     * @param bonus          The default island bonus level\n     * @param biome          The default island biome\n     * @param islandName     The island name\n     */\n    public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName) {\n        plugin.getGrid().createIsland(superiorPlayer, schemName, bonus, biome, islandName);\n    }\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonus          A starting worth for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     * @param offset         Should the island have an offset for it's values? If disabled, the bonus will be given.\n     */\n    public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName, boolean offset) {\n        plugin.getGrid().createIsland(superiorPlayer, schemName, bonus, biome, islandName, offset);\n    }\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonusWorth     A starting worth for the island.\n     * @param bonusLevel     A starting level for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     * @param offset         Should the island have an offset for it's values? If disabled, the bonus will be given.\n     */\n    public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset) {\n        plugin.getGrid().createIsland(superiorPlayer, schemName, bonusWorth, bonusLevel, biome, islandName, offset);\n    }\n\n    /**\n     * Delete an island\n     */\n    public static void deleteIsland(Island island) {\n        plugin.getGrid().deleteIsland(island);\n    }\n\n    /**\n     * Get an island by it's name.\n     */\n    @Nullable\n    public static Island getIsland(String islandName) {\n        return plugin.getGrid().getIsland(islandName);\n    }\n\n    /**\n     * Get an island by it's uuid.\n     */\n    @Nullable\n    public static Island getIslandByUUID(UUID uuid) {\n        return plugin.getGrid().getIslandByUUID(uuid);\n    }\n\n    /**\n     * Get the spawn island.\n     */\n    public static Island getSpawnIsland() {\n        return plugin.getGrid().getSpawnIsland();\n    }\n\n    /**\n     * Get the world of an island by the world's dimension.\n     */\n    @Nullable\n    public static World getIslandsWorld(Island island, Dimension dimension) {\n        return plugin.getGrid().getIslandsWorld(island, dimension);\n    }\n\n    /**\n     * Get an island at a location.\n     */\n    @Nullable\n    public static Island getIslandAt(Location location) {\n        return plugin.getGrid().getIslandAt(location);\n    }\n\n    /**\n     * Calculate all island worths on the server\n     */\n    public static void calcAllIslands() {\n        plugin.getGrid().calcAllIslands();\n    }\n\n    /*\n     *  Schematic Methods\n     */\n\n    /**\n     * Get a schematic object by its name\n     */\n    @Nullable\n    public static Schematic getSchematic(String name) {\n        return plugin.getSchematics().getSchematic(name);\n    }\n\n    /*\n     *  Providers Methods\n     */\n\n    /**\n     * Set custom spawners provider for the plugin.\n     *\n     * @param spawnersProvider The spawner provider to set.\n     */\n    public static void setSpawnersProvider(SpawnersProvider spawnersProvider) {\n        plugin.getProviders().setSpawnersProvider(spawnersProvider);\n    }\n\n    /*\n     *  Commands Methods\n     */\n\n    /**\n     * Register a sub-command.\n     *\n     * @param superiorCommand The sub command to register.\n     */\n    public static void registerCommand(SuperiorCommand superiorCommand) {\n        plugin.getCommands().registerCommand(superiorCommand);\n    }\n\n    /*\n     *  Main Method\n     */\n\n    /**\n     * Get the grid of the core.\n     */\n    public static GridManager getGrid() {\n        return plugin.getGrid();\n    }\n\n    /**\n     * Get the stacked-blocks manager of the core.\n     */\n    public static StackedBlocksManager getStackedBlocks() {\n        return plugin.getStackedBlocks();\n    }\n\n    /**\n     * Get the blocks manager of the core.\n     */\n    public static BlockValuesManager getBlockValues() {\n        return plugin.getBlockValues();\n    }\n\n    /**\n     * Get the schematics manager of the core.\n     */\n    public static SchematicManager getSchematics() {\n        return plugin.getSchematics();\n    }\n\n    /**\n     * Get the players manager of the core.\n     */\n    public static PlayersManager getPlayers() {\n        return plugin.getPlayers();\n    }\n\n    /**\n     * Get the roles manager of the core.\n     */\n    public static RolesManager getRoles() {\n        return plugin.getRoles();\n    }\n\n    /**\n     * Get the missions manager of the core.\n     */\n    public static MissionsManager getMissions() {\n        return plugin.getMissions();\n    }\n\n    /**\n     * Get the menus manager of the core.\n     */\n    public static MenusManager getMenus() {\n        return plugin.getMenus();\n    }\n\n    /**\n     * Get the keys manager of the core.\n     */\n    public static KeysManager getKeys() {\n        return plugin.getKeys();\n    }\n\n    /**\n     * Get the providers manager of the core.\n     */\n    public static ProvidersManager getProviders() {\n        return plugin.getProviders();\n    }\n\n    /**\n     * Get the upgrades manager of the core.\n     */\n    public static UpgradesManager getUpgrades() {\n        return plugin.getUpgrades();\n    }\n\n    /**\n     * Get the commands manager of the core.\n     */\n    public static CommandsManager getCommands() {\n        return plugin.getCommands();\n    }\n\n    /**\n     * Get the settings of the plugin.\n     */\n    public static SettingsManager getSettings() {\n        return plugin.getSettings();\n    }\n\n    /**\n     * Get the objects factory of the plugin.\n     */\n    public static FactoriesManager getFactory() {\n        return plugin.getFactory();\n    }\n\n    /**\n     * Get the modules manager of the plugin.\n     */\n    public static ModulesManager getModules() {\n        return plugin.getModules();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/commands/SuperiorCommand.java",
    "content": "package com.bgsoftware.superiorskyblock.api.commands;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.List;\nimport java.util.Locale;\n\npublic interface SuperiorCommand {\n\n    /**\n     * Get the aliases of the sub command.\n     */\n    List<String> getAliases();\n\n    /**\n     * Get the required permission to use the sub command.\n     * If no permission is required, can be empty.\n     */\n    String getPermission();\n\n    /**\n     * Get the usage of the sub command.\n     *\n     * @param locale The locale of the player.\n     */\n    String getUsage(Locale locale);\n\n    /**\n     * Get the description of the sub command.\n     *\n     * @param locale The locale of the player.\n     */\n    String getDescription(Locale locale);\n\n    /**\n     * Get the minimum arguments required for the command.\n     * For example, the command /is example PLAYER_NAME has 2 arguments.\n     */\n    int getMinArgs();\n\n    /**\n     * Get the maximum arguments required for the command.\n     * For example, the command /is example PLAYER_NAME has 2 arguments.\n     */\n    int getMaxArgs();\n\n    /**\n     * Can the command be executed from console?\n     * If true, sender cannot be casted directly into a player. Otherwise, it can be.\n     */\n    boolean canBeExecutedByConsole();\n\n\n    /**\n     * Should the command be displayed in /is help (or /is admin for admin commands)?\n     */\n    boolean displayCommand();\n\n    /**\n     * The method to be executed when the command is running.\n     *\n     * @param plugin The instance of the plugin.\n     * @param sender The sender who ran the command.\n     * @param args   The arguments of the command.\n     */\n    void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args);\n\n    /**\n     * Get the tab-complete arguments of the command.\n     *\n     * @param plugin The instance of the plugin.\n     * @param sender The sender who ran the command.\n     * @param args   The arguments of the command.\n     */\n    List<String> tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.config;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.math.RoundingMode;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic interface SettingsManager {\n\n    /**\n     * The amount of time between auto-calculations that the plugin runs.\n     * If set to 0, it means the task is disabled.\n     * Config path: calc-interval\n     */\n    long getCalcInterval();\n\n    /**\n     * All settings related to the database of the plugin.\n     * Config path: database\n     */\n    Database getDatabase();\n\n    /**\n     * The main command of the plugin.\n     * Aliases can be added by adding \",\" after the command name, and split them using \",\".\n     * Config path: island-command\n     */\n    String getIslandCommand();\n\n    /**\n     * The maximum island size.\n     * Config path: max-island-size\n     */\n    int getMaxIslandSize();\n\n    /**\n     * All the default values for new islands that are created.\n     * Config path: default-values\n     */\n    DefaultValues getDefaultValues();\n\n    /**\n     * The default height islands will generate.\n     * Config path: islands-height\n     */\n    int getIslandHeight();\n\n    /**\n     * Whether world borders are enabled for islands or not.\n     * Config path: world-borders\n     */\n    boolean isWorldBorders();\n\n    /**\n     * All settings related to the stacked-blocks system of the plugin.\n     * Config path: stacked-blocks\n     */\n    StackedBlocks getStackedBlocks();\n\n    /**\n     * The formula used to calculate a block's level when it has a worth defined but no level specified.\n     * The formula can contain a placeholder: `{}`, which is replaced with the block worth.\n     * Config path: block-level-formula\n     */\n    String getIslandLevelFormula();\n\n    /**\n     * Whether island levels should be rounded or not.\n     * Config path: rounded-island-level\n     */\n    boolean isRoundedIslandLevels();\n\n    /**\n     * The rounding mode used for the island level when rounded-island-level feature is enabled.\n     * Config path: island-level-rounding-mode\n     */\n    RoundingMode getIslandLevelRoundingMode();\n\n    /**\n     * Whether to automatic track block counts when players place and break blocks.\n     * Config path: auto-blocks-tracking\n     */\n    boolean isAutoBlocksTracking();\n\n    /**\n     * The default island-top sorting type.\n     * Config path: island-top-order\n     */\n    String getIslandTopOrder();\n\n    /**\n     * The default global-warps sorting type.\n     * Config path: global-warps-order\n     */\n    String getGlobalWarpsOrder();\n\n    /**\n     * Whether coop members are enabled.\n     * Config path: coop-members\n     */\n    boolean isCoopMembers();\n\n    /**\n     * Should players be able to edit island privileges for other players?\n     * Config path: edit-player-permissions\n     */\n    boolean isEditPlayerPermissions();\n\n    /**\n     * All settings related to the island-roles.\n     * Config path: island-roles\n     */\n    IslandRoles getIslandRoles();\n\n    /**\n     * The line that determines if a sign is created as an island warp.\n     * Config path: sign-warp-line\n     */\n    String getSignWarpLine();\n\n    /**\n     * The lines to be set for warp signs.\n     * Config path: sign-warp\n     */\n    List<String> getSignWarp();\n\n    /**\n     * All settings related to the visitors-sign.\n     * Config path: visitors-sign\n     */\n    VisitorsSign getVisitorsSign();\n\n    /**\n     * All settings related to the worlds of the plugin.\n     * Config path: worlds\n     */\n    Worlds getWorlds();\n\n    /**\n     * All settings related to the spawn island.\n     * Config path: spawn\n     */\n    Spawn getSpawn();\n\n    /**\n     * A list of permissions players will have in the islands world, outside of islands.\n     * Config path: world-permissions\n     */\n    Collection<String> getWorldPermissions();\n\n    /**\n     * All settings related to the void teleportation.\n     * Config path: void-teleport\n     */\n    VoidTeleport getVoidTeleport();\n\n    /**\n     * Get all the interactable blocks.\n     *\n     * @deprecated See {@link #getInteractablesMap}\n     */\n    @Deprecated\n    List<String> getInteractables();\n\n    /**\n     * Get all the interactable blocks and their interact privilege.\n     */\n    Interactables getInteractablesMap();\n\n    /**\n     * Get all the safe blocks.\n     */\n    Collection<Key> getSafeBlocks();\n\n    /**\n     * Whether visitors should take damage on islands or not.\n     * Config path: visitors-damage\n     */\n    boolean isVisitorsDamage();\n\n    /**\n     * Whether coop players should take damage on islands or not.\n     * Config-path: coop-damage\n     */\n    boolean isCoopDamage();\n\n    /**\n     * The default number of disbands players receive when they first join the server.\n     * If -1, then the disbands limit is disabled.\n     * Config-path: default-disband-count\n     */\n    int getDisbandCount();\n\n    /**\n     * Whether the members list shown in island top should include the leader or not.\n     * Config-path: island-top-include-leader\n     */\n    boolean isIslandTopIncludeLeader();\n\n    /**\n     * Default placeholders to be returned when no island exists.\n     * Config-path: default-placeholders\n     */\n    Map<String, String> getDefaultPlaceholders();\n\n    /**\n     * Whether confirmation menu should be opened before banning a player from an island or not.\n     * Config-path: ban-confirm\n     */\n    boolean isBanConfirm();\n\n    /**\n     * Whether confirmation menu should be opened before disbanding an island or not.\n     * Config-path: disband-confirm\n     */\n    boolean isDisbandConfirm();\n\n    /**\n     * Whether confirmation menu should be opened before kicking an island member from an island or not.\n     * Config-path: kick-confirm\n     */\n    boolean isKickConfirm();\n\n    /**\n     * Whether confirmation menu should be opened before leaving an island or not.\n     * Config-path: leave-confirm\n     */\n    boolean isLeaveConfirm();\n\n    /**\n     * Whether confirmation menu should be opened before transfering an island or not.\n     * Config-path: transfer-confirm\n     */\n    boolean isTransferConfirm();\n\n    /**\n     * The spawners-provider to use.\n     * If set to AUTO, the plugin will automatically detect an available spawners provider and use it.\n     * Config-path: spawners-provider\n     */\n    String getSpawnersProvider();\n\n    /**\n     * The stacked-blocks provider to use.\n     * If set to AUTO, the plugin will automatically detect an available stacked-blocks provider and use it.\n     * Config-path: stacked-blocks-provider\n     */\n    String getStackedBlocksProvider();\n\n    /**\n     * Whether inventory of island members should be cleared when their island is disbanded or not.\n     * Return true if clear-on-disband contains both ENDER_CHEST and INVENTORY.\n     * This method will be deleted in the future!\n     *\n     * @deprecated See {@link #getClearActionsOnDisband()}\n     */\n    @Deprecated\n    boolean isDisbandInventoryClear();\n\n    /**\n     * All settings related to island-names.\n     * Config path: island-names\n     */\n    IslandNames getIslandNames();\n\n    /**\n     * Whether to teleport players to their island when they create it or not.\n     * Config path: teleport-on-create\n     */\n    boolean isTeleportOnCreate();\n\n    /**\n     * Whether to teleport players to their island when they join it or not.\n     * Config-path: teleport-on-join\n     */\n    boolean isTeleportOnJoin();\n\n    /**\n     * Whether to teleport players to the spawn when they are kicked from their island or not.\n     * Config-path: teleport-on-kick\n     */\n    boolean isTeleportOnKick();\n\n    /**\n     * Whether to teleport players to the spawn when they leave an island or not.\n     * Config-path: teleport-on-leave\n     */\n    boolean isTeleportOnLeave();\n\n    /**\n     * Whether to clear players' inventories when they join a new island or not.\n     * Return true if clear-on-join contains both ENDER_CHEST and INVENTORY.\n     * This method will be deleted in the future!\n     *\n     * @deprecated See {@link #getClearActionsOnJoin()}\n     */\n    @Deprecated\n    boolean isClearOnJoin();\n\n    /**\n     * Get the list of clear actions to perform on island members when their island is disbanded.\n     * Config-path: clear-on-disband\n     */\n    List<ClearAction> getClearActionsOnDisband();\n\n    /**\n     * Get the list of clear actions to perform on players when they accept an invite.\n     * Config-path: clear-on-join\n     */\n    List<ClearAction> getClearActionsOnJoin();\n\n    /**\n     * Get the list of clear actions to perform on players when they are kicked from their island.\n     * Config-path: clear-on-kick\n     */\n    List<ClearAction> getClearActionsOnKick();\n\n    /**\n     * Get the list of clear actions to perform on players when they leave an island.\n     * Config-path: clear-on-leave\n     */\n    List<ClearAction> getClearActionsOnLeave();\n\n    /**\n     * Whether players can rate their own island or not.\n     * Config-path: rate-own-island\n     */\n    boolean isRateOwnIsland();\n\n    /**\n     * Whether players can change island rating or not.\n     * Config-path: change-island-rating\n     */\n    boolean isChangeIslandRating();\n\n    /**\n     * All the default island-flags that will be enabled for new islands.\n     * Config-path: default-settings\n     */\n    List<String> getDefaultSettings();\n\n    /**\n     * Whether redstone should be disabled on islands when all of the members of the island are offline or not.\n     * Config-path: disable-redstone-offline\n     */\n    boolean isDisableRedstoneOffline();\n\n    /**\n     * All settings related to afk-integrations.\n     * Config path: afk-integrations\n     */\n    AFKIntegrations getAFKIntegrations();\n\n    /**\n     * Cooldowns of commands for players.\n     * Represented by a map with keys as the command labels, and values as pairs\n     * containing the cooldown and a bypass permission.\n     * Config-path: commands-cooldown\n     */\n    Map<String, Pair<Integer, String>> getCommandsCooldown();\n\n    /**\n     * Cooldown between upgrades.\n     * If -1, then there is no cooldown.\n     * Config-path: upgrade-cooldown\n     */\n    long getUpgradeCooldown();\n\n    /**\n     * The numbers-formatting of the plugin.\n     * Config-path: number-format\n     */\n    String getNumbersFormat();\n\n    /**\n     * The date-formatting of the plugin.\n     * Config-path: date-format\n     */\n    String getDateFormat();\n\n    /**\n     * Whether menus with only one item inside them should be skipped or not.\n     * Config-path: skip-one-item-menus\n     */\n    boolean isSkipOneItemMenus();\n\n    /**\n     * Whether visitors on islands should get teleported to spawn when pvp is enabled on the island they were on or not.\n     * Config-path: teleport-on-pvp-enable\n     */\n    boolean isTeleportOnPvPEnable();\n\n    /**\n     * Whether visitors should be immuned to PvP for a few seconds when they visit an island that has pvp enabled or not.\n     * Config-path: immune-to-pvp-when-teleport\n     */\n    boolean isImmuneToPvPWhenTeleport();\n\n    /**\n     * List of blocked commands that visitors cannot run on islands.\n     * Config-path: blocked-visitors-commands\n     */\n    List<String> getBlockedVisitorsCommands();\n\n    /**\n     * All settings related to default-containers in schematics.\n     * Currently, getting contents of containers is not available using the API.\n     * Config path: island-names\n     */\n    DefaultContainers getDefaultContainers();\n\n    /**\n     * Lines that should be set for signs of schematics.\n     * If empty, no signs will be changed.\n     * Config-path: default-signs\n     */\n    List<String> getDefaultSign();\n\n    /**\n     * List of commands to be executed for events.\n     * Represented by a map with keys as event names and values as a list of commands.\n     * Config-path: event-commands\n     */\n    Map<String, List<String>> getEventCommands();\n\n    /**\n     * Delay before teleporting to an island warp, in milliseconds.\n     * If 0, no delay will be.\n     * Config-path: warps-warmup\n     */\n    long getWarpsWarmup();\n\n    /**\n     * Delay before teleporting to island home, in milliseconds.\n     * If 0, no delay will be.\n     * Config-path: home-warmup\n     */\n    long getHomeWarmup();\n\n    /**\n     * Delay before teleporting to another island, in milliseconds.\n     * If 0, no delay will be.\n     * Config-path: visit-warmup\n     */\n    long getVisitWarmup();\n\n    /**\n     * Whether liquids should receive a physics update when placed in schematics or not.\n     * Config-path: liquid-update\n     */\n    boolean isLiquidUpdate();\n\n    /**\n     * Whether lights should be set when placing schematics or not.\n     * Config-path: lights-update\n     */\n    boolean isLightsUpdate();\n\n    /**\n     * List of worlds that pvp is allowed between island-members.\n     * Config-path: pvp-worlds\n     */\n    List<String> getPvPWorlds();\n\n    /**\n     * Whether the plugin should force players to stay in islands in the islands worlds or not.\n     * Config-path: stop-leaving\n     */\n    boolean isStopLeaving();\n\n    /**\n     * Whether players can open the values-menu by right-clicking on islands in the islands top menu or not.\n     * Config-path: values-menu\n     */\n    boolean isValuesMenu();\n\n    /**\n     * List of crops that can get affected by the crops-growth multiplier.\n     * Config-path: crops-to-grow\n     */\n    List<String> getCropsToGrow();\n\n    /**\n     * Time between each iteration of the crops task.\n     * Config-path: crops-interval\n     */\n    int getCropsInterval();\n\n    /**\n     * Whether players can only go back to the previous menu by clicking the back-button or not.\n     * Config-path: only-back-button\n     */\n    boolean isOnlyBackButton();\n\n    /**\n     * Whether players can build outside their islands or not.\n     * When enabled, island-sizes to be {@link #getMaxIslandSize()} * 1.5,\n     * and islands will be connected to each other.\n     * Config-path: build-outside-island\n     */\n    boolean isBuildOutsideIsland();\n\n    /**\n     * The default language to be set for new players.\n     * Config-path: default-language\n     */\n    String getDefaultLanguage();\n\n    /**\n     * Whether new players should have world-borders enabled by default or not.\n     * Config-path: default-world-border\n     */\n    boolean isDefaultWorldBorder();\n\n    /**\n     * Whether new players should be able to stack blocks by default or not.\n     * Config-path: default-blocks-stacker\n     */\n    boolean isDefaultStackedBlocks();\n\n    /**\n     * Whether new players should have /is open their island panel by default or not.\n     * Config-path: default-toggled-panel\n     */\n    boolean isDefaultToggledPanel();\n\n    /**\n     * Whether new players should have island fly enabled by default or not.\n     * Config-path: default-island-fly\n     */\n    boolean isDefaultIslandFly();\n\n    /**\n     * The default border-color for new players.\n     * Config-path: default-border-color\n     */\n    String getDefaultBorderColor();\n\n    /**\n     * Whether obsidian should turn into a lava-bucket when clicking on it with an empty bucket in hand or not.\n     * Config-path: obsidian-to-lava\n     */\n    boolean isObsidianToLava();\n\n    /**\n     * The sync-worth status of the plugin.\n     * Config-path: sync-worth\n     */\n    BlockValuesManager.SyncWorthStatus getSyncWorth();\n\n    /**\n     * Whether island-worth can be negative or not.\n     * Config-path: negative-worth\n     */\n    boolean isNegativeWorth();\n\n    /**\n     * Whether island-level can be negative or not.\n     * Config-path: negative-level\n     */\n    boolean isNegativeLevel();\n\n    /**\n     * List of plugin-events that should not be fired.\n     * Config-path: disabled-events\n     */\n    List<String> getDisabledEvents();\n\n    /**\n     * List of commands that should be disabled within the plugin.\n     * Config-path: disabled-commands\n     */\n    List<String> getDisabledCommands();\n\n    /**\n     * List of plugins that their hooks should not be enabled.\n     * Config-path: disabled-hooks\n     */\n    List<String> getDisabledHooks();\n\n    /**\n     * Whether the schematic-name argument should be when executing /is create or not.\n     * Config-path: schematic-name-argument\n     */\n    boolean isSchematicNameArgument();\n\n    /**\n     * All settings related to island-chests.\n     * Config path: island-chests\n     */\n    IslandChests getIslandChests();\n\n    /**\n     * Custom aliases for commands of the plugin.\n     * Represented by a map with keys as commands, and values as aliases.\n     * Config-path: command-aliases\n     */\n    Map<String, List<String>> getCommandAliases();\n\n    /**\n     * List of valuable-blocks.\n     * Config-path: valuable-blocks\n     */\n    Set<Key> getValuableBlocks();\n\n    /**\n     * List of preview-island locations.\n     * Represented by a map with keys as schematic names, and values as locations for the preview islands.\n     * Config-path: preview-islands\n     *\n     * @deprecated See {@link #getIslandPreviews()}\n     */\n    @Deprecated\n    Map<String, Location> getPreviewIslands();\n\n    /**\n     * All settings related to the island previews.\n     * Config path: island-previews\n     */\n    IslandPreviews getIslandPreviews();\n\n    /**\n     * Whether vanished players should be hidden from command tab completes or not.\n     * Config-path: tab-complete-hide-vanished\n     */\n    boolean isTabCompleteHideVanished();\n\n    /**\n     * Whether drops multiplier should only affect entities that are killed by players or not.\n     * Config-path: drops-upgrade-players-multiply\n     */\n    boolean isDropsUpgradePlayersMultiply();\n\n    /**\n     * The delay set for the ISLAND_PROTECTED message.\n     *\n     * @deprecated See {@link #getMessageDelays()}\n     */\n    @Deprecated\n    long getProtectedMessageDelay();\n\n    /**\n     * A list of messages that should have a delay, in milliseconds.\n     * Represented by a map with string as the message name, and values as the delays.\n     * Config-path: message-delays\n     */\n    Map<String, Long> getMessageDelays();\n\n    /**\n     * Whether the warp categories system is enabled or not.\n     * Config-path: warp-categories\n     */\n    boolean isWarpCategories();\n\n    /**\n     * Whether the plugin should listen for the physics event or not.\n     * Config-path: physics-listener\n     */\n    boolean isPhysicsListener();\n\n    /**\n     * Amount of money to be charged from players when they use an island warp.\n     * If set to 0, no money will be charged.\n     * Config-path: charge-on-warp\n     */\n    double getChargeOnWarp();\n\n    /**\n     * Whether island warps should be public by default or not.\n     * Config-path: public-warps\n     */\n    boolean isPublicWarps();\n\n    /**\n     * Whether islands should be locked by default or not.\n     * Config-path: locked-islands\n     */\n    boolean isLockedIslands();\n\n    /**\n     * Cooldown between recalculations of an island, in seconds.\n     * If set to 0, no cooldown is set.\n     * Config-path: recalc-task-timeout\n     */\n    long getRecalcTaskTimeout();\n\n    /**\n     * Whether to detect the player's language automatically when he first joins the server.\n     * Config-path: auto-language-detection\n     */\n    boolean isAutoLanguageDetection();\n\n    /**\n     * Automatically uncoop players when there are no island members left online that can remove uncoop players.\n     * Config-path: auto-uncoop-when-alone\n     */\n    boolean isAutoUncoopWhenAlone();\n\n    /**\n     * Get the way to sort members in the top islands menu.\n     * Config-path: island-top-members-sorting\n     */\n    TopIslandMembersSorting getTopIslandMembersSorting();\n\n    /**\n     * Limit of the amount of bossbar tasks each player can have at the same time.\n     * Config-path: bossbar-limit\n     */\n    int getBossbarLimit();\n\n    /**\n     * Whether to delete unsafe warps when players try to teleport to them automatically.\n     * Config-path: delete-unsafe-warps\n     */\n    boolean getDeleteUnsafeWarps();\n\n    /**\n     * Get the list of actions to perform when a player respawns.\n     * Config-path: player-respawn\n     */\n    List<RespawnAction> getPlayerRespawn();\n\n    /**\n     * Get the threshold between saves for block counts.\n     * Config-path: block-counts-save-threshold\n     */\n    BigInteger getBlockCountsSaveThreshold();\n\n    /**\n     * Support for chat-signing in 1.19+.\n     * Config-path: chat-signing-support\n     */\n    boolean getChatSigningSupport();\n\n    /**\n     * Amount of commands to be listed in the `/is help` and `/is admin` commands.\n     * Config-path: commands-per-page\n     */\n    int getCommandsPerPage();\n\n    /**\n     * Whether players should receive a help instead of a `INVALID_COMMAND` message\n     * when using a command that doesn't exist or not.\n     * Config-path: help-on-invalid-command\n     */\n    boolean isHelpOnInvalidCommand();\n\n    /**\n     * Whether players should receive a help instead of a `NO_COMMAND_PERMISSION` message\n     * when using a command they don't have permission for or not.\n     * Config-path: help-on-no-permission\n     */\n    boolean isHelpOnNoPermission();\n\n    /**\n     * Whether the plugin should cache schematics for faster placement of schematics.\n     * Config-path: cache-schematics\n     */\n    boolean isCacheSchematics();\n\n    /**\n     * Custom entity categories to be used by the plugin.\n     * Config-path: entity-categories\n     */\n    @Deprecated\n    Map<String, KeySet> getEntityCategories();\n\n    /**\n     * Custom entity categories to be used by the plugin.\n     */\n    EntityCategories getEntityCategoriesMap();\n\n    interface Database {\n\n        /**\n         * Get the database-type to use (SQLite or MySQL).\n         * Config-path: database.type\n         */\n        String getType();\n\n        /**\n         * Whether the datastore folder should be back-up on startup.\n         * Config-path: database.backup\n         */\n        boolean isBackup();\n\n        /**\n         * The address used to connect to the database.\n         * Used for MySQL only.\n         * Config-path: database.address\n         */\n        String getAddress();\n\n        /**\n         * The port used to connect to the database.\n         * Used for MySQL only.\n         * Config-path: database.port\n         */\n        int getPort();\n\n        /**\n         * Get the name of the database.\n         * Used for MySQL only.\n         * Config-path: database.db-name\n         */\n        String getDBName();\n\n        /**\n         * The username used to connect to the database.\n         * Used for MySQL only.\n         * Config-path: database.user-name\n         */\n        String getUsername();\n\n        /**\n         * The password used to connect to the database.\n         * Used for MySQL only.\n         * Config-path: database.password\n         */\n        String getPassword();\n\n        /**\n         * The prefix used for tables in the database.\n         * Used for MySQL only.\n         * Config-path: database.prefix\n         */\n        String getPrefix();\n\n        /**\n         * Whether the database uses SSL or not.\n         * Used for MySQL only.\n         * Config-path: database.useSSL\n         */\n        boolean hasSSL();\n\n        /**\n         * Whether public-key-retrieval is allowed in the database or not.\n         * Used for MySQL only.\n         * Config-path: database.allowPublicKeyRetrieval\n         */\n        boolean hasPublicKeyRetrieval();\n\n        /**\n         * The wait-timeout of the database, in milliseconds.\n         * Used for MySQL only.\n         * Config-path: database.waitTimeout\n         */\n        long getWaitTimeout();\n\n        /**\n         * The max-lifetime of the database, in milliseconds.\n         * Used for MySQL only.\n         * Config-path: database.maxLifetime\n         */\n        long getMaxLifetime();\n\n    }\n\n    interface DefaultValues {\n\n        /**\n         * The default island size for new islands.\n         * Config-path: default-values.island-size\n         */\n        int getIslandSize();\n\n        /**\n         * The default block limits for new islands.\n         * Represented by a map with keys as the block types, and values as the limits.\n         * Config-path: default-values.block-limits\n         */\n        Map<Key, Integer> getBlockLimits();\n\n        /**\n         * The default entity limits for new islands.\n         * Represented by a map with keys as the entity types, and values as the limits.\n         * Config-path: default-values.entity-limits\n         */\n        Map<Key, Integer> getEntityLimits();\n\n        /**\n         * The default warps limit for new islands.\n         * Config-path: default-values.warps-limit\n         */\n        int getWarpsLimit();\n\n        /**\n         * The default team limit for new islands.\n         * Config-path: default-values.team-limit\n         */\n        int getTeamLimit();\n\n        /**\n         * The default coops limit for new islands.\n         * Config-path: default-values.coop-limit\n         */\n        int getCoopLimit();\n\n        /**\n         * The default crop-growth multiplier for new islands.\n         * Config-path: default-values.crop-growth\n         */\n        double getCropGrowth();\n\n        /**\n         * The default spawner-rates multiplier for new islands.\n         * Config-path: default-values.spawner-rates\n         */\n        double getSpawnerRates();\n\n        /**\n         * The default mob-drops multiplier for new islands.\n         * Config-path: default-values.mob-drops\n         */\n        double getMobDrops();\n\n        /**\n         * The default bank-limit for new islands.\n         * Config-path: default-values.bank-limit\n         */\n        BigDecimal getBankLimit();\n\n        /**\n         * The default generator-rates for new islands.\n         * Represented by an array of maps with keys as the blocks, and values as the rates.\n         * The maps are sorted by the {@link Dimension} they belong to.\n         * Config-path: default-values.generator\n         *\n         * @deprecated See {@link #getGeneratorsMap()}\n         */\n        @Deprecated\n        Map<Key, Integer>[] getGenerators();\n\n        /**\n         * The default generator-rates for new islands.\n         * Represented by maps with keys as the blocks, and values as the rates.\n         * Config-path: default-values.generator\n         */\n        Map<Dimension, Map<Key, Integer>> getGeneratorsMap();\n\n        /**\n         * The default role-limits for new islands.\n         * Represented by a map with keys as the role ids, and values as the limit.\n         * Config-path: default-values.role-limits\n         */\n        Map<Integer, Integer> getRoleLimits();\n\n        /**\n         * The default island effects for new islands.\n         * Represented by a map with keys as the effect types, and values as the effect levels.\n         * Config-path: default-values.island-effects\n         */\n        Map<PotionEffectType, Integer> getIslandEffects();\n\n    }\n\n    interface StackedBlocks {\n\n        /**\n         * Whether stacked blocks are enabled on the server or not.\n         * Config-path: stacked-blocks.enabled\n         */\n        boolean isEnabled();\n\n        /**\n         * The custom hologram names for stacked blocks.\n         * Config-path: stacked-blocks.custom-name\n         */\n        String getCustomName();\n\n        /**\n         * List of worlds that blocks cannot be stacked in.\n         * Config-path: stacked-blocks.disabled-worlds\n         */\n        List<String> getDisabledWorlds();\n\n        /**\n         * List of whitelisted block types that can be stacked together.\n         * Config-path: stacked-blocks.whitelisted\n         */\n        Set<Key> getWhitelisted();\n\n        /**\n         * Limits for stacked-blocks\n         * Represented by a map with keys as block types, and values as limits.\n         * Config-path: stacked-blocks.limits\n         */\n        Map<Key, Integer> getLimits();\n\n        /**\n         * Whether stacked blocks should be auto-collected to players' inventories or not.\n         * Config-path: stacked-blocks.auto-collect\n         */\n        boolean isAutoCollect();\n\n        /**\n         * All the settings related to the deposit-menu of stacked blocks.\n         * Config path: default-values.deposit-menu\n         */\n        DepositMenu getDepositMenu();\n\n\n        interface DepositMenu {\n\n            /**\n             * Whether the deposit-menu is enabled or not.\n             * Config path: default-values.deposit-menu.enabled\n             */\n            boolean isEnabled();\n\n            /**\n             * The title of the deposit menu.\n             * Config path: default-values.deposit-menu.title\n             */\n            String getTitle();\n\n        }\n\n    }\n\n    interface IslandRoles {\n\n        /**\n         * The configuration section of the island-roles.\n         * Config path: island-roles\n         */\n        ConfigurationSection getSection();\n\n    }\n\n    interface VisitorsSign {\n\n        /**\n         * Whether a visitors sign is required for others to visit islands.\n         * Config-path: visitors-sign.required-for-visit\n         */\n        boolean isRequiredForVisit();\n\n        /**\n         * The line that determines if the sign is used as a visitors home location.\n         * Config-path: visitors-sign.line\n         */\n        String getLine();\n\n        /**\n         * The line that is displayed when the visitors sign is active.\n         * Config-path: visitors-sign.active\n         */\n        String getActive();\n\n        /**\n         * The line that is displayed when the visitors sign is inactive.\n         * Config-path: visitors-sign.inactive\n         */\n        String getInactive();\n\n        /**\n         * The format in which the island description lines will be saved.\n         * Config-path: visitors-sign.description-line-format\n         */\n        String getDescriptionLineFormat();\n\n    }\n\n    interface Worlds {\n\n        /**\n         * The default world dimension.\n         * Config-path: worlds.default-world\n         */\n        Dimension getDefaultWorldDimension();\n\n        /**\n         * The default world environment.\n         * Config-path: worlds.default-world\n         *\n         * @deprecated See {@link #getDefaultWorldDimension()}\n         */\n        @Deprecated\n        World.Environment getDefaultWorld();\n\n        /**\n         * The name of the overworld world.\n         * Config-path: worlds.world-name\n         */\n        String getWorldName();\n\n        /**\n         * The name of the default world.\n         */\n        String getDefaultWorldName();\n\n        /**\n         * All settings related to the overworld world.\n         * Config-path: worlds.normal\n         *\n         * @deprecated See {@link #getDimensionConfig(Dimension)}\n         */\n        @Deprecated\n        Normal getNormal();\n\n        /**\n         * All settings related to the nether world.\n         * Config-path: worlds.nether\n         *\n         * @deprecated See {@link #getDimensionConfig(Dimension)}\n         */\n        @Deprecated\n        Nether getNether();\n\n        /**\n         * All settings related to the end world.\n         * Config-path: worlds.end\n         *\n         * @deprecated See {@link #getDimensionConfig(Dimension)}\n         */\n        @Deprecated\n        End getEnd();\n\n        /**\n         * All settings related to a dimension.\n         * Config-path: worlds.<dimension>\n         */\n        @Nullable\n        DimensionConfig getDimensionConfig(Dimension dimension);\n\n        /**\n         * The difficulty of the islands worlds.\n         * Config-path: worlds.difficulty\n         */\n        String getDifficulty();\n\n        /**\n         * The sea level of island worlds.\n         * Config path: worlds.sea-level-height\n         */\n        int getSeaLevelHeight();\n\n        interface DimensionConfig {\n\n            /**\n             * Whether this dimension is enabled or not.\n             * Config-path: worlds.dimensions.<dimension>.enabled\n             */\n            boolean isEnabled();\n\n            /**\n             * Whether this dimension is unlocked by default or not.\n             * Config-path: worlds.dimensions.<dimension>.unlock\n             */\n            boolean isUnlocked();\n\n            /**\n             * Whether the schematic for this dimension should be offset or not.\n             * Config-path: worlds.dimensions.<dimension>.schematic-offset\n             */\n            boolean isSchematicOffset();\n\n            /**\n             * Get the default biome for this dimension.\n             * Config-path: worlds.dimensions.<dimension>.biome\n             */\n            String getBiome();\n\n            /**\n             * Get the world's name for this dimension.\n             * Config-path: worlds.dimensions.<dimension>.name\n             */\n            String getName();\n\n            /**\n             * Get the destination of a specific portal type {@link PortalType}\n             * Config-path: worlds.dimensions.<dimension>.portals\n             *\n             * @param portalType The portal type to get\n             * @return The destination of that portal type, or null if doesn't exist.\n             */\n            @Nullable\n            Dimension getPortalDestination(PortalType portalType);\n\n        }\n\n        interface Normal extends DimensionConfig {\n\n        }\n\n        interface Nether extends DimensionConfig {\n\n        }\n\n        interface End extends DimensionConfig {\n\n            /**\n             * Whether ender-dragon fights should be enabled for islands or not.\n             * Config-path: worlds.end.dragon-fight.enabled\n             */\n            boolean isDragonFight();\n\n            /**\n             * Get the offset of the portal from the center of the island.\n             * Config-path: worlds.end.dragon-fight.portal-offset\n             */\n            BlockOffset getPortalOffset();\n\n        }\n\n    }\n\n    interface Spawn {\n\n        /**\n         * The location of the spawn island.\n         * Config-path: spawn.location\n         */\n        String getLocation();\n\n        /**\n         * Whether the spawn island has a protection or not.\n         * Config-path: spawn.protection\n         */\n        boolean isProtected();\n\n        /**\n         * List of island-flags that will be enabled for the spawn island.\n         * Config-path: spawn.settings\n         */\n        List<String> getSettings();\n\n        /**\n         * List of permissions that will be given to players for the spawn island.\n         * Config-path: spawn.permissions\n         */\n        List<String> getPermissions();\n\n        /**\n         * Whether the spawn island has a world border or not.\n         * Config-path: spawn.world-border\n         */\n        boolean isWorldBorder();\n\n        /**\n         * The size of the spawn island.\n         * Config-path: spawn.size\n         */\n        int getSize();\n\n        /**\n         * Whether players should take damage in the spawn island or not.\n         * Config-path: spawn.players-damage\n         */\n        boolean isPlayersDamage();\n\n    }\n\n    interface VoidTeleport {\n\n        /**\n         * Whether island members should be teleported when they fall into void on their island or not.\n         * Config-path: void-teleport.members\n         */\n        boolean isMembers();\n\n        /**\n         * Whether visitors should be teleported when they fall into void on other islands or not.\n         * Config-path: void-teleport.visitors\n         */\n        boolean isVisitors();\n\n    }\n\n    interface IslandNames {\n\n        /**\n         * Whether an island name is required for creating a new island or not.\n         * Config-path: island-names.required-for-creation\n         */\n        boolean isRequiredForCreation();\n\n        /**\n         * The maximum length for island-names.\n         * Config-path: island-names.max-length\n         */\n        int getMaxLength();\n\n        /**\n         * The minimum length for island-names.\n         * Config-path: island-names.min-length\n         */\n        int getMinLength();\n\n        /**\n         * List of names that cannot be used.\n         * Config-path: island-names.filtered-names\n         */\n        List<String> getFilteredNames();\n\n        /**\n         * Whether island-names should support colors or not.\n         * Config-path: island-names.color-support\n         */\n        boolean isColorSupport();\n\n        /**\n         * Whether island names should be displayed in the island-top menu or not.\n         * Config-path: island-names.island-top\n         */\n        boolean isIslandTop();\n\n        /**\n         * Whether the plugin should prevent from choosing player names as island names or not.\n         * Config-path: island-names.prevent-player-names\n         */\n        boolean isPreventPlayerNames();\n\n        /**\n         * Whether the name change announcement should be sent to all players or not.\n         * Config-path: island-names.announce-change-to-all\n         */\n        boolean isAnnounceChangeToAll();\n\n    }\n\n    interface AFKIntegrations {\n\n        /**\n         * Whether redstone should be disabled when all island members are afk or not.\n         * Config-path: afk-integrations.disable-redstone\n         */\n        boolean isDisableRedstone();\n\n        /**\n         * Whether mob spawning should be disabled when all island members are afk or not.\n         * Config-path: afk-integrations.disable-spawning\n         */\n        boolean isDisableSpawning();\n\n    }\n\n    interface DefaultContainers {\n\n        /**\n         * Whether the default-containers system is enabled or not.\n         * Config-path: default-containers.enabled\n         */\n        boolean isEnabled();\n\n    }\n\n    interface IslandChests {\n\n        /**\n         * The title to be shown for island chests.\n         * Config-path: island-chests.chest-title\n         */\n        String getChestTitle();\n\n        /**\n         * The default pages new islands will have.\n         * Config-path: island-chests.default-pages\n         */\n        int getDefaultPages();\n\n        /**\n         * The default size for chests.\n         * Config-path: island-chests.default-size\n         */\n        int getDefaultSize();\n\n    }\n\n    interface IslandPreviews {\n\n        /**\n         * The game mode that will be set for the player when they enter preview mode.\n         * Config-path: island-previews.game-mode\n         */\n        GameMode getGameMode();\n\n        /**\n         * The maximum distance a player can move before the preview mode is canceled.\n         * Config-path: island-previews.max-distance\n         */\n        int getMaxDistance();\n\n        /**\n         * A list of commands that cannot be executed by players in preview mode.\n         * Config-path: island-previews.blocked-commands\n         */\n        List<String> getBlockedCommands();\n\n        /**\n         * List of island preview locations.\n         * Represented by a map with keys as schematic names, and values as locations for the preview islands.\n         * Config-path: island-previews.locations\n         */\n        Map<String, Location> getLocations();\n\n    }\n\n    interface Interactables {\n\n        /**\n         * Get all the interactables from the interactables file.\n         */\n        Set<Key> getInteractables();\n\n        /**\n         * Get all the interactables for a specific {@link IslandPrivilege}\n         */\n        @Nullable\n        Set<Key> getInteractables(IslandPrivilege islandPrivilege);\n\n        /**\n         * Get the required {@link IslandPrivilege} for a specific key.\n         */\n        @Nullable\n        IslandPrivilege getRequiredPrivilege(Key key);\n\n    }\n\n    interface EntityCategories {\n\n        /**\n         * Get all the categories from the entity-categories file.\n         */\n        List<EntityCategory> getCategories();\n\n        /**\n         * Get the entity categories for a specific entity key.\n         *\n         * @param key The entity's key\n         */\n        List<EntityCategory> getCategories(Key key);\n\n        /**\n         * Get an entity category by its name\n         *\n         * @param name The name of the category.\n         */\n        @Nullable\n        EntityCategory getCategoryByName(String name);\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.api.data;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic interface DatabaseBridge {\n\n    /**\n     * Load all the objects from the database.\n     *\n     * @param table:         The table to load the objects from.\n     * @param resultConsumer Consumer that receives each object from the database.\n     */\n    void loadAllObjects(String table, Consumer<Map<String, Object>> resultConsumer);\n\n    /**\n     * Start saving data for the object.\n     * If this method is not called, data should not be saved when saveRow is called.\n     *\n     * @deprecated See {@link #setDatabaseBridgeMode(DatabaseBridgeMode)}\n     */\n    @Deprecated\n    default void startSavingData() {\n        setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n    }\n\n    /**\n     * Set whether to execute operations in batches or not.\n     */\n    void batchOperations(boolean batchOperations);\n\n    /**\n     * Update the object in the database.\n     *\n     * @param table   The name of the table in the database.\n     * @param filter  The filter of the column.\n     * @param columns All columns to be saved with their values.\n     */\n    void updateObject(String table, @Nullable DatabaseFilter filter, Pair<String, Object>... columns);\n\n    /**\n     * Insert the object in the database.\n     *\n     * @param table   The name of the table in the database.\n     * @param columns All columns to be saved with their values.\n     */\n    void insertObject(String table, Pair<String, Object>... columns);\n\n    /**\n     * Delete the object from the database.\n     *\n     * @param table  The name of the table in the database.\n     * @param filter The filter of the column.\n     */\n    void deleteObject(String table, @Nullable DatabaseFilter filter);\n\n    /**\n     * Load data from the database for this object.\n     *\n     * @param table          The table to get the data from.\n     * @param filter         The filter of the column.\n     * @param resultConsumer Consumer that receives data for each row.\n     */\n    void loadObject(String table, @Nullable DatabaseFilter filter, Consumer<Map<String, Object>> resultConsumer);\n\n    /**\n     * Set the mode for the database bridge.\n     *\n     * @param databaseBridgeMode The {@link DatabaseBridgeMode} mode to set.\n     */\n    void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode);\n\n    /**\n     * Get the current mode of the database bridge.\n     */\n    DatabaseBridgeMode getDatabaseBridgeMode();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseBridgeMode.java",
    "content": "package com.bgsoftware.superiorskyblock.api.data;\n\n/**\n * Represents the mode the database-bridge object is in.\n */\npublic enum DatabaseBridgeMode {\n\n    /**\n     * When this mode is selected, the database-bridge should run queries to the database.\n     */\n    SAVE_DATA,\n\n    /**\n     * When this mode is selected, the database-bridge should not execute updates to the database.\n     * Reading from the database should still work.\n     */\n    IDLE\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseFilter.java",
    "content": "package com.bgsoftware.superiorskyblock.api.data;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic abstract class DatabaseFilter {\n\n    private static DatabaseFilterEmpty EMPTY_FILTER;\n\n    public static DatabaseFilter fromFilter(String filterKey, Object filterValue) {\n        return new DatabaseFilterSingle(filterKey, filterValue);\n    }\n\n    public static DatabaseFilter fromFilters(List<Pair<String, Object>> filters) {\n        if (filters.isEmpty()) {\n            if (EMPTY_FILTER == null)\n                EMPTY_FILTER = new DatabaseFilterEmpty();\n\n            return EMPTY_FILTER;\n        } else if (filters.size() == 1) {\n            Pair<String, Object> filter = filters.get(0);\n            return fromFilter(filter.getKey(), filter.getValue());\n        } else {\n            return new DatabaseFilterList(filters);\n        }\n    }\n\n    protected DatabaseFilter() {\n    }\n\n    public abstract void forEach(BiConsumer<String, Object> consumer);\n\n    public abstract Collection<Pair<String, Object>> getFilters();\n\n    private static class DatabaseFilterList extends DatabaseFilter {\n\n        private final Collection<Pair<String, Object>> filters;\n\n        DatabaseFilterList(Collection<Pair<String, Object>> filters) {\n            this.filters = filters;\n        }\n\n        @Override\n        public void forEach(BiConsumer<String, Object> consumer) {\n            filters.forEach(pair -> consumer.accept(pair.getKey(), pair.getValue()));\n        }\n\n        @Override\n        public Collection<Pair<String, Object>> getFilters() {\n            return Collections.unmodifiableCollection(filters);\n        }\n\n    }\n\n    private static class DatabaseFilterEmpty extends DatabaseFilter {\n\n        @Override\n        public void forEach(BiConsumer<String, Object> consumer) {\n            // Do nothing.\n        }\n\n        @Override\n        public Collection<Pair<String, Object>> getFilters() {\n            return Collections.emptyList();\n        }\n\n    }\n\n    private static class DatabaseFilterSingle extends DatabaseFilter {\n\n        private final String filterKey;\n        private final Object filterValue;\n\n        DatabaseFilterSingle(String filterKey, Object filterValue) {\n            this.filterKey = filterKey;\n            this.filterValue = filterValue;\n        }\n\n        @Override\n        public void forEach(BiConsumer<String, Object> consumer) {\n            consumer.accept(filterKey, filterValue);\n        }\n\n        @Override\n        public Collection<Pair<String, Object>> getFilters() {\n            return Collections.singleton(new Pair<>(filterKey, filterValue));\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/data/IDatabaseBridgeHolder.java",
    "content": "package com.bgsoftware.superiorskyblock.api.data;\n\npublic interface IDatabaseBridgeHolder {\n\n    /**\n     * Get the current database bridge of the object.\n     */\n    DatabaseBridge getDatabaseBridge();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.entity;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\n\npublic interface EntityCategory {\n\n    /**\n     * Get the name of the entity category.\n     */\n    String getName();\n\n    /**\n     * Get the entities this category contains.\n     */\n    KeySet getEntities();\n\n    /**\n     * Get the required {@link IslandPrivilege} to spawn entities from this category on an island.\n     */\n    @Nullable\n    IslandPrivilege getSpawnPrivilege();\n\n    /**\n     * Get the required {@link IslandPrivilege} to damage entities from this category on an island.\n     */\n    @Nullable\n    IslandPrivilege getDamagePrivilege();\n\n    /**\n     * Get the required {@link IslandPrivilege} to interact with entities from this category on an island.\n     */\n    @Nullable\n    IslandPrivilege getInteractPrivilege();\n\n    /**\n     * Get the required {@link IslandFlag} for entities from this category to spawn on an island from a spawner.\n     */\n    @Nullable\n    IslandFlag getSpawnerSpawningIslandFlag();\n\n    /**\n     * Get the required {@link IslandFlag} for entities from this category to spawn on an island naturally.\n     */\n    @Nullable\n    IslandFlag getNaturalSpawningIslandFlag();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/BankAction.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\npublic enum BankAction {\n\n    WITHDRAW_COMPLETED,\n    WITHDRAW_FAILED,\n\n    DEPOSIT_COMPLETED,\n    DEPOSIT_FAILED\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/BorderColor.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\n/**\n * Used to determine what's the color of the border of players.\n */\npublic enum BorderColor {\n\n    RED,\n    GREEN,\n    BLUE;\n\n    public static BorderColor safeValue(String name, BorderColor def) {\n        try {\n            return BorderColor.valueOf(name);\n        } catch (IllegalArgumentException ex) {\n            return def;\n        }\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/HitActionResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\npublic enum HitActionResult {\n\n    NOT_ONLINE,\n    PVP_WARMUP,\n    ISLAND_PVP_DISABLE,\n    VISITOR_DAMAGE,\n    COOP_DAMAGE,\n\n    TARGET_NOT_ONLINE,\n    TARGET_PVP_WARMUP,\n    TARGET_ISLAND_PVP_DISABLE,\n    TARGET_VISITOR_DAMAGE,\n    TARGET_COOP_DAMAGE,\n\n    ISLAND_TEAM_PVP,\n\n    SUCCESS\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\n/**\n * Used to determine the reason why a member was removed from an island.\n */\npublic enum MemberRemoveReason {\n\n    /**\n     * The member was removed because the island was disbanded.\n     */\n    DISBAND,\n\n    /**\n     * The member was removed because another player kicked them from the island.\n     */\n    KICK,\n\n    /**\n     * The member was removed because they left the island.\n     */\n    LEAVE\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\nimport java.util.Locale;\n\n/**\n * Used to determine what rating has a player given to an island.\n */\npublic enum Rating {\n\n    UNKNOWN,\n    ZERO_STARS,\n    ONE_STAR,\n    TWO_STARS,\n    THREE_STARS,\n    FOUR_STARS,\n    FIVE_STARS;\n\n    private static String ALL_RATING_NAMES;\n\n    /**\n     * Get a string of all the rating names.\n     */\n    public static String getValuesString() {\n        if (ALL_RATING_NAMES == null) {\n            StringBuilder namesBuilder = new StringBuilder();\n            for (Rating rating : Rating.values())\n                namesBuilder.append(\", \").append(rating.toString().toLowerCase(Locale.ENGLISH));\n            ALL_RATING_NAMES = namesBuilder.length() == 0 ? \"\" : namesBuilder.substring(2);\n        }\n\n        return ALL_RATING_NAMES;\n    }\n\n    /**\n     * Get a rating by it's value.\n     */\n    public static Rating valueOf(int value) {\n        return values()[value + 1];\n    }\n\n    /**\n     * Get the integer value of the rating.\n     */\n    public int getValue() {\n        return ordinal() - 1;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/SyncStatus.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\n\n/**\n * Sync status for {@link IslandFlag} and {@link IslandPrivilege} in islands.\n */\npublic enum SyncStatus {\n\n    /**\n     * The target is enabled and is not synced.\n     */\n    ENABLED,\n\n    /**\n     * The target is disabled and is not synced.\n     */\n    DISABLED,\n\n    /**\n     * The target is synced with upgrades and default config values.\n     */\n    SYNCED\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/TopIslandMembersSorting.java",
    "content": "package com.bgsoftware.superiorskyblock.api.enums;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.Comparator;\n\npublic enum TopIslandMembersSorting {\n\n    /**\n     * Sort members in the top-islands menu by their names.\n     */\n    NAMES,\n\n    /**\n     * Sort members in the top-islands menu by their roles.\n     */\n    ROLES;\n\n    private Comparator<SuperiorPlayer> comparator = null;\n\n    TopIslandMembersSorting() {\n    }\n\n    public void setComparator(Comparator<SuperiorPlayer> comparator) {\n        if (this.comparator != null)\n            throw new IllegalArgumentException(\"You cannot set a comparator after it was already been set.\");\n\n        this.comparator = comparator;\n    }\n\n    public Comparator<SuperiorPlayer> getComparator() {\n        if (this.comparator == null)\n            throw new RuntimeException(this + \" was not initialized.\");\n\n        return comparator;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/AttemptPlayerSendMessageEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * AttemptPlayerSendMessageEvent is called when a message is attempted to be sent to {@link SuperiorPlayer}\n * The event is called before it checks if {@link SuperiorPlayer} can get the message.\n * In this time there is no {@link IMessageComponent} yet, as it is created only once the message can be sent\n * to the receiver.\n */\npublic class AttemptPlayerSendMessageEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer receiver;\n    private final String messageType;\n    private final Object[] args;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param receiver    The receiver of the message.\n     * @param messageType The name of the message, similar to the one from lang file.\n     */\n    public AttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object[] args) {\n        super(!Bukkit.isPrimaryThread());\n        this.receiver = receiver;\n        this.messageType = messageType;\n        this.args = args;\n    }\n\n    /**\n     * Get the receiver of the message.\n     */\n    public SuperiorPlayer getReceiver() {\n        return receiver;\n    }\n\n    /**\n     * Get the name of the message, similar to the one from lang file.\n     */\n    public String getMessageType() {\n        return messageType;\n    }\n\n    /**\n     * Get an argument of the message.\n     *\n     * @param index The index of the argument.\n     * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds.\n     */\n    public Object getArgument(int index) {\n        return args[index];\n    }\n\n    /**\n     * Set an argument for the message.\n     *\n     * @param index The index of the argument.\n     * @param value The value to be set.\n     * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds.\n     */\n    public void setArgument(int index, Object value) {\n        Preconditions.checkNotNull(value, \"Argument's value cannot be null.\");\n        args[index] = value;\n    }\n\n    /**\n     * Get the length of the arguments array.\n     */\n    public int getArgumentsLength() {\n        return args.length;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/BlockStackEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.block.BlockEvent;\n\npublic class BlockStackEvent extends BlockEvent implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final Player player;\n    private final int originalCount;\n    private final int newCount;\n    private boolean cancelled = false;\n\n    public BlockStackEvent(Block block, Player player, int originalCount, int newCount) {\n        super(block);\n        this.player = player;\n        this.originalCount = originalCount;\n        this.newCount = newCount;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    public Player getPlayer() {\n        return player;\n    }\n\n    public int getOriginalCount() {\n        return originalCount;\n    }\n\n    public int getNewCount() {\n        return newCount;\n    }\n\n    public int getIncreaseAmount() {\n        return newCount - originalCount;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/BlockUnstackEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.block.BlockEvent;\n\npublic class BlockUnstackEvent extends BlockEvent implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final Player player;\n    private final int originalCount;\n    private final int newCount;\n    private boolean cancelled = false;\n\n    public BlockUnstackEvent(Block block, Player player, int originalCount, int newCount) {\n        super(block);\n        this.player = player;\n        this.originalCount = originalCount;\n        this.newCount = newCount;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    @Nullable\n    public Player getPlayer() {\n        return player;\n    }\n\n    public int getOriginalCount() {\n        return originalCount;\n    }\n\n    public int getNewCount() {\n        return newCount;\n    }\n\n    public int getDecreaseAmount() {\n        return originalCount - newCount;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBanEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandBanEvent is called when a player is banned from his island.\n */\npublic class IslandBanEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer targetPlayer;\n\n    private boolean cancelled;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who banned the other player.\n     * @param targetPlayer   The player that was banned.\n     * @param island         The island that the player was banned from.\n     */\n    public IslandBanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.targetPlayer = targetPlayer;\n    }\n\n    /**\n     * Get the player who banned the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that was banned.\n     */\n    public SuperiorPlayer getTarget() {\n        return targetPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBankDepositEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandBankDepositEvent is called when money is deposited to the bank.\n */\npublic class IslandBankDepositEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final BigDecimal amount;\n    private String failureReason = null;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who deposited the money.\n     * @param island         The island that the money was deposited to.\n     * @param amount         The amount that was deposited.\n     */\n    public IslandBankDepositEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.amount = amount;\n    }\n\n    /**\n     * Get the player who deposited the money.\n     * When null, then the console deposited the money using the admin command.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the amount that was deposited.\n     */\n    public BigDecimal getAmount() {\n        return amount;\n    }\n\n    /**\n     * Get the failure reason of the transaction.\n     */\n    @Nullable\n    public String getFailureReason() {\n        return failureReason;\n    }\n\n    /**\n     * Set a failure reason for the transaction.\n     *\n     * @param failureReason The new failure reason to set.\n     */\n    public void setFailureReason(@Nullable String failureReason) {\n        this.failureReason = failureReason != null && failureReason.isEmpty() ? null : failureReason;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return this.failureReason != null;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        setFailureReason(cancelled ? \"Generic event cancel.\" : null);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBankWithdrawEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandBankDepositEvent is called when money is deposited to the bank.\n */\npublic class IslandBankWithdrawEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final BigDecimal amount;\n    private String failureReason = null;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who withdrawn the money.\n     * @param island         The island that the money was withdrawn from.\n     * @param amount         The amount that was withdrawn.\n     */\n    public IslandBankWithdrawEvent(SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.amount = amount;\n    }\n\n    /**\n     * Get the player who withdrawn the money.\n     * When null, then the console deposited the money using the admin command.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the amount that was deposited.\n     */\n    public BigDecimal getAmount() {\n        return amount;\n    }\n\n    /**\n     * Get the failure reason of the transaction.\n     */\n    @Nullable\n    public String getFailureReason() {\n        return failureReason;\n    }\n\n    /**\n     * Set a failure reason for the transaction.\n     *\n     * @param failureReason The new failure reason to set.\n     */\n    public void setFailureReason(@Nullable String failureReason) {\n        this.failureReason = failureReason != null && failureReason.isEmpty() ? null : failureReason;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return this.failureReason != null;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        setFailureReason(cancelled ? \"Generic event cancel.\" : null);\n    }\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBiomeChangeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.block.Biome;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCreateEvent is called when a new island is created.\n */\npublic class IslandBiomeChangeEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private Biome biome;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who changed the biome of the island.\n     * @param island         The island object that was changed.\n     * @param biome          The name of the new biome.\n     */\n    public IslandBiomeChangeEvent(SuperiorPlayer superiorPlayer, Island island, Biome biome) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.biome = biome;\n    }\n\n    /**\n     * Get the player who upgraded the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new biome.\n     */\n    public Biome getBiome() {\n        return biome;\n    }\n\n    /**\n     * Set the new biome.\n     */\n    public void setBiome(Biome biome) {\n        this.biome = biome;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBankLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandChangeBankLimitEvent is called when the bank-limit of the island is changed.\n */\npublic class IslandChangeBankLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private BigDecimal bankLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the bank limit of the island.\n     *                       If set to null, it means the limit was changed by console.\n     * @param island         The island that the bank limit was changed for.\n     * @param bankLimit      The new bank limit of the island\n     */\n    public IslandChangeBankLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, BigDecimal bankLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.bankLimit = bankLimit;\n    }\n\n    /**\n     * Get the player that changed the bank limit of the island.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new bank limit of the island.\n     */\n    public BigDecimal getBankLimit() {\n        return bankLimit;\n    }\n\n    /**\n     * Set the new bank limit for the island.\n     *\n     * @param bankLimit The new bank limit to set.\n     */\n    public void setBankLimit(BigDecimal bankLimit) {\n        Preconditions.checkNotNull(bankLimit, \"Cannot set the bank limit to null.\");\n        Preconditions.checkArgument(bankLimit.compareTo(BigDecimal.ZERO) >= 0, \"Cannot set the bank limit to a negative limit.\");\n        this.bankLimit = bankLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBlockLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeBlockLimitEvent is called when a block-limit of an island is changed.\n */\npublic class IslandChangeBlockLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key block;\n\n    private int blockLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the block limit of an island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the block limit was changed for.\n     * @param block          The block that the limit was changed for.\n     * @param blockLimit     The new block limit of the block\n     */\n    public IslandChangeBlockLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, int blockLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.block = block;\n        this.blockLimit = blockLimit;\n    }\n\n    /**\n     * Get the player that changed the block limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the block that the limit was changed for.\n     */\n    public Key getBlock() {\n        return block;\n    }\n\n    /**\n     * Get the new block limit of the block.\n     */\n    public int getBlockLimit() {\n        return blockLimit;\n    }\n\n    /**\n     * Set the new block limit of the block.\n     *\n     * @param blockLimit The new block limit to set.\n     */\n    public void setBlockLimit(int blockLimit) {\n        Preconditions.checkArgument(blockLimit >= 0, \"Cannot set the block limit to a negative limit.\");\n        this.blockLimit = blockLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBorderSizeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeBorderSizeEvent is called when the border-size of the island is changed.\n */\npublic class IslandChangeBorderSizeEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private int borderSize;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the border size of the island.\n     *                       If set to null, it means the limit was changed by console.\n     * @param island         The island that the border size was changed for.\n     * @param borderSize     The new border size of the island\n     */\n    public IslandChangeBorderSizeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int borderSize) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.borderSize = borderSize;\n    }\n\n    /**\n     * Get the player that changed the border-size of the island.\n     * If null, it means the size was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new border size of the island.\n     */\n    public int getBorderSize() {\n        return borderSize;\n    }\n\n    /**\n     * Set the new border size for the island.\n     *\n     * @param borderSize The new border size to set.\n     */\n    public void setBorderSize(int borderSize) {\n        Preconditions.checkArgument(borderSize >= 1, \"Cannot set the border size to values lower than 1.\");\n        this.borderSize = borderSize;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeCoopLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeCoopLimitEvent is called when the coop-limit of the island is changed.\n */\npublic class IslandChangeCoopLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private int coopLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the coop limit of the island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the coop limit was changed for.\n     * @param coopLimit      The new coop limit of the island\n     */\n    public IslandChangeCoopLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int coopLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.coopLimit = coopLimit;\n    }\n\n    /**\n     * Get the player that changed the coop limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new coop limit of the island.\n     */\n    public int getCoopLimit() {\n        return coopLimit;\n    }\n\n    /**\n     * Set the new coop limit for the island.\n     *\n     * @param coopLimit The new coop limit to set.\n     */\n    public void setCoopLimit(int coopLimit) {\n        Preconditions.checkArgument(coopLimit >= 0, \"Cannot set the coop limit to a negative limit.\");\n        this.coopLimit = coopLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeCropGrowthEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeCropGrowthEvent is called when the crop-growth multiplier of the island is changed.\n */\npublic class IslandChangeCropGrowthEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private double cropGrowth;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the crop-growth multiplier of the island.\n     *                       If set to null, it means the crop-growth multiplier was changed via the console.\n     * @param island         The island that the crop-growth multiplier was changed for.\n     * @param cropGrowth     The new crop-growth multiplier of the island\n     */\n    public IslandChangeCropGrowthEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double cropGrowth) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.cropGrowth = cropGrowth;\n    }\n\n    /**\n     * Get the player that changed the crop-growth multiplier.\n     * If null, it means the crop-growth multiplier was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new crop-growth multiplier of the island.\n     */\n    public double getCropGrowth() {\n        return cropGrowth;\n    }\n\n    /**\n     * Set the new crop-growth multiplier for the island.\n     *\n     * @param cropGrowth The crop-growth multiplier to set.\n     */\n    public void setCropGrowth(double cropGrowth) {\n        Preconditions.checkArgument(cropGrowth >= 0, \"Cannot set the crop growth to a negative multiplier.\");\n        this.cropGrowth = cropGrowth;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeDescriptionEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeDescriptionEvent is called when an island changes its description.\n */\npublic class IslandChangeDescriptionEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private String description;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that its description was changed.\n     * @param superiorPlayer The player that changed the description of the island.\n     * @param description    The new description of the island.\n     */\n    public IslandChangeDescriptionEvent(Island island, SuperiorPlayer superiorPlayer, String description) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.description = description;\n    }\n\n    /**\n     * Get the player that changed the description of the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new description of the island.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * Set the new description of the island.\n     *\n     * @param description The new description to set.\n     */\n    public void setIslandName(String description) {\n        Preconditions.checkNotNull(description, \"Island descriptions cannot be null.\");\n        this.description = description;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeDiscordEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeDiscordEvent is called when the discord of the island is changed.\n */\npublic class IslandChangeDiscordEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private String discord;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the discord of the island.\n     * @param island         The island that the discord was changed for.\n     * @param discord        The new discord of the island\n     */\n    public IslandChangeDiscordEvent(SuperiorPlayer superiorPlayer, Island island, String discord) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.discord = discord;\n    }\n\n    /**\n     * Get the player that changed the discord of the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new discord of the island.\n     */\n    public String getDiscord() {\n        return discord;\n    }\n\n    /**\n     * Set the new discord for the island.\n     *\n     * @param discord The new discord to set.\n     */\n    public void setDiscord(String discord) {\n        Preconditions.checkNotNull(discord, \"Cannot set the discord of the island to null.\");\n        this.discord = discord;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeEffectLevelEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.potion.PotionEffectType;\n\n/**\n * IslandChangeEffectLevelEvent is called when an effect of an island is changed.\n */\npublic class IslandChangeEffectLevelEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final PotionEffectType effectType;\n\n    private int effectLevel;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the effect level of an island.\n     *                       If set to null, it means the level was changed via the console.\n     * @param island         The island that the effect level was changed for.\n     * @param effectType     The effect that the level was changed for.\n     * @param effectLevel    The new level of the effect.\n     */\n    public IslandChangeEffectLevelEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PotionEffectType effectType, int effectLevel) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.effectType = effectType;\n        this.effectLevel = effectLevel;\n    }\n\n    /**\n     * Get the player that changed the effect level.\n     * If null, it means the level was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the effect that the level was changed for.\n     */\n    public PotionEffectType getEffectType() {\n        return effectType;\n    }\n\n    /**\n     * Get the new level of the effect.\n     */\n    public int getEffectLevel() {\n        return effectLevel;\n    }\n\n    /**\n     * Set the new level of the effect.\n     *\n     * @param effectLevel The new effect level to set.\n     */\n    public void setEffectLevel(int effectLevel) {\n        Preconditions.checkArgument(effectLevel >= 0, \"Cannot set the effect level to a negative level.\");\n        this.effectLevel = effectLevel;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeEntityLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeEntityLimitEvent is called when an entity-limit of an island is changed.\n */\npublic class IslandChangeEntityLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key entity;\n\n    private int entityLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the entity limit of an island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the entity limit was changed for.\n     * @param entity         The entity that the limit was changed for.\n     * @param entityLimit    The new entity limit of the entity.\n     */\n    public IslandChangeEntityLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key entity, int entityLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.entity = entity;\n        this.entityLimit = entityLimit;\n    }\n\n    /**\n     * Get the player that changed the entity limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the entity that the limit was changed for.\n     */\n    public Key getEntity() {\n        return entity;\n    }\n\n    /**\n     * Get the new entity limit of the entity.\n     */\n    public int getEntityLimit() {\n        return entityLimit;\n    }\n\n    /**\n     * Set the new entity limit of the entity..\n     *\n     * @param entityLimit The new entity limit to set.\n     */\n    public void setEntityLimit(int entityLimit) {\n        Preconditions.checkArgument(entityLimit >= 0, \"Cannot set the entity limit to a negative limit.\");\n        this.entityLimit = entityLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeGeneratorRateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeGeneratorRateEvent is called when a generator-rate of an island is changed.\n */\npublic class IslandChangeGeneratorRateEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key block;\n    private final Dimension dimension;\n\n    private int generatorRate;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the generator-rate of an island.\n     *                       If set to null, it means the rate was changed via the console.\n     * @param island         The island that the generator-rate was changed for.\n     * @param block          The block that the rate was changed for.\n     * @param environment    The environment of the world that the rate was changed for.\n     * @param generatorRate  The new generator-rate of the block.\n     */\n    @Deprecated\n    public IslandChangeGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block,\n                                          World.Environment environment, int generatorRate) {\n        this(superiorPlayer, island, block, Dimension.getByName(environment.name()), generatorRate);\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the generator-rate of an island.\n     *                       If set to null, it means the rate was changed via the console.\n     * @param island         The island that the generator-rate was changed for.\n     * @param block          The block that the rate was changed for.\n     * @param dimension      The dimension of the world that the rate was changed for.\n     * @param generatorRate  The new generator-rate of the block.\n     */\n    public IslandChangeGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block,\n                                          Dimension dimension, int generatorRate) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.block = block;\n        this.dimension = dimension;\n        this.generatorRate = generatorRate;\n    }\n\n    /**\n     * Get the player that changed the generator-rate.\n     * If null, it means the level was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the block that the generator-rate was changed for.\n     */\n    public Key getBlock() {\n        return block;\n    }\n\n    /**\n     * Get the environment of the world that the rate was changed for.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the environment of the world that the rate was changed for.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    /**\n     * Get the new generator-rate of the block.\n     */\n    public int getGeneratorRate() {\n        return generatorRate;\n    }\n\n    /**\n     * Set the new generator-rate of the block.\n     *\n     * @param generatorRate The new generator-rate to set.\n     */\n    public void setGeneratorRate(int generatorRate) {\n        Preconditions.checkArgument(generatorRate >= 0, \"Cannot set the generator-rate to a negative rate.\");\n        this.generatorRate = generatorRate;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeLevelBonusEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandChangeLevelBonusEvent is called when the level-bonus of the island is changed.\n */\npublic class IslandChangeLevelBonusEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Reason reason;\n\n    private BigDecimal levelBonus;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the level bonus of the island.\n     *                       If set to null, it means the bonus was changed by console.\n     * @param island         The island that the level bonus was changed for.\n     * @param reason         The reason for changing the level bonus.\n     * @param levelBonus     The new level bonus of the island\n     */\n    public IslandChangeLevelBonusEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Reason reason, BigDecimal levelBonus) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.reason = reason;\n        this.levelBonus = levelBonus;\n    }\n\n    /**\n     * Get the player that changed the level bonus.\n     * If null, it means the bonus was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the reason for changing the level bonus.\n     */\n    public Reason getReason() {\n        return reason;\n    }\n\n    /**\n     * Get the new level bonus of the island.\n     */\n    public BigDecimal getLevelBonus() {\n        return levelBonus;\n    }\n\n    /**\n     * Set the new level bonus for the island.\n     *\n     * @param levelBonus The new level bonus to set.\n     */\n    public void setLevelBonus(BigDecimal levelBonus) {\n        Preconditions.checkNotNull(levelBonus, \"Cannot set the level bonus to null.\");\n        this.levelBonus = levelBonus;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * The reason for changing the level bonus.\n     */\n    public enum Reason {\n\n        /**\n         * The level bonus was changed due to a command by a player or console.\n         */\n        COMMAND,\n\n        /**\n         * The level bonus was changed due to schematic that was placed in the world for the island.\n         */\n        SCHEMATIC\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeMembersLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandChangeMembersLimitEvent is called when the members limit of an island is changed.\n */\npublic class IslandChangeMembersLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private int membersLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the members limit of an island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the members limit was changed for.\n     * @param membersLimit   The new members limit of an island.\n     */\n    public IslandChangeMembersLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int membersLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.membersLimit = membersLimit;\n    }\n\n    /**\n     * Get the player that changed the members limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new members limit of the island.\n     */\n    public int getMembersLimit() {\n        return membersLimit;\n    }\n\n    /**\n     * Set the new members limit of the island.\n     *\n     * @param membersLimit The new members limit to set.\n     */\n    public void setMembersLimit(int membersLimit) {\n        Preconditions.checkArgument(membersLimit >= 0, \"Cannot set the members limit to a negative limit.\");\n        this.membersLimit = membersLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeMobDropsEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeMobDropsEvent is called when the mob-drops multiplier of the island is changed.\n */\npublic class IslandChangeMobDropsEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private double mobDrops;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the mob-drops multiplier of the island.\n     *                       If set to null, it means the mob-drops multiplier was changed via the console.\n     * @param island         The island that the mob-drops multiplier was changed for.\n     * @param mobDrops       The new mob drops of the island\n     */\n    public IslandChangeMobDropsEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double mobDrops) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.mobDrops = mobDrops;\n    }\n\n    /**\n     * Get the player that changed the mob-drops multiplier.\n     * If null, it means the mob-drops multiplier was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new mob-drops multiplier of the island.\n     */\n    public double getMobDrops() {\n        return mobDrops;\n    }\n\n    /**\n     * Set the new mob-drops multiplier for the island.\n     *\n     * @param mobDrops The mob-drops multiplier to set.\n     */\n    public void setMobDrops(double mobDrops) {\n        Preconditions.checkArgument(mobDrops >= 0, \"Cannot set the mob-drops to a negative multiplier.\");\n        this.mobDrops = mobDrops;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangePaypalEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangePaypalEvent is called when the paypal of the island is changed.\n */\npublic class IslandChangePaypalEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private String paypal;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the paypal of the island.\n     * @param island         The island that the paypal was changed for.\n     * @param paypal         The new paypal of the island\n     */\n    public IslandChangePaypalEvent(SuperiorPlayer superiorPlayer, Island island, String paypal) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.paypal = paypal;\n    }\n\n    /**\n     * Get the player that changed the paypal of the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new paypal of the island.\n     */\n    public String getPaypal() {\n        return paypal;\n    }\n\n    /**\n     * Set the new paypal for the island.\n     *\n     * @param paypal The new paypal to set.\n     */\n    public void setPaypal(String paypal) {\n        Preconditions.checkNotNull(paypal, \"Cannot set the discord of the island to null.\");\n        this.paypal = paypal;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangePlayerPrivilegeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangePlayerPrivilegeEvent is called when a privilege is changed for a player on an island.\n */\npublic class IslandChangePlayerPrivilegeEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer privilegedPlayer;\n    private final boolean privilegeEnabled;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island           The island that the privilege was changed in.\n     * @param superiorPlayer   The player that changed the privilege to the other player.\n     * @param privilegedPlayer The player that the privilege was changed for.\n     * @param privilegeEnabled Whether the privilege was enabled or disabled for the player.\n     */\n    public IslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.privilegedPlayer = privilegedPlayer;\n        this.privilegeEnabled = privilegeEnabled;\n    }\n\n    /**\n     * Get the player that changed the privilege to the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that the privilege was changed for.\n     */\n    public SuperiorPlayer getPrivilegedPlayer() {\n        return privilegedPlayer;\n    }\n\n    /**\n     * Check whether the privilege was enabled to {@link #getPrivilegedPlayer()}\n     */\n    public boolean isPrivilegeEnabled() {\n        return privilegeEnabled;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeRoleLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeRoleLimitEvent is called when a role-limit of an island is changed.\n */\npublic class IslandChangeRoleLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final PlayerRole playerRole;\n\n    private int roleLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the role limit of an island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the role limit was changed for.\n     * @param playerRole     The role that the limit was changed for.\n     * @param roleLimit      The new role limit of the role.\n     */\n    public IslandChangeRoleLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole, int roleLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.playerRole = playerRole;\n        this.roleLimit = roleLimit;\n    }\n\n    /**\n     * Get the player that changed the role limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the role that the limit was changed for.\n     */\n    public PlayerRole getPlayerRole() {\n        return playerRole;\n    }\n\n    /**\n     * Get the new role limit of the role.\n     */\n    public int getRoleLimit() {\n        return roleLimit;\n    }\n\n    /**\n     * Set the new role limit for the role.\n     *\n     * @param roleLimit The new role limit to set.\n     */\n    public void setRoleLimit(int roleLimit) {\n        Preconditions.checkArgument(roleLimit >= 0, \"Cannot set the role limit to a negative limit.\");\n        this.roleLimit = roleLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeRolePrivilegeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeRolePrivilegeEvent is called when a privilege is changed for a role on an island.\n */\npublic class IslandChangeRolePrivilegeEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final PlayerRole playerRole;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the privilege was changed in.\n     * @param superiorPlayer The player that changed the privilege to the other role.\n     *                       If null, the privilege was changed by the console.\n     * @param playerRole     The role that the privilege was changed for.\n     */\n    public IslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.playerRole = playerRole;\n    }\n\n    /**\n     * Get the player that changed the privilege to the other player.\n     * If null, the privilege was changed by the console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the role that the privilege was changed for.\n     */\n    public PlayerRole getPlayerRole() {\n        return playerRole;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeSpawnerRatesEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandChangeSpawnerRatesEvent is called when the spawner-rates multiplier of the island is changed.\n */\npublic class IslandChangeSpawnerRatesEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private double spawnerRates;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the spawner-rates multiplier of the island.\n     *                       If set to null, it means the spawner-rates multiplier was changed via the console.\n     * @param island         The island that the spawner-rates multiplier was changed for.\n     * @param spawnerRates   The new spawner-rates multiplier of the island\n     */\n    public IslandChangeSpawnerRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double spawnerRates) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.spawnerRates = spawnerRates;\n    }\n\n    /**\n     * Get the player that changed the spawner-rates multiplier.\n     * If null, it means the spawner-rates multiplier was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new spawner-rates multiplier of the island.\n     */\n    public double getSpawnerRates() {\n        return spawnerRates;\n    }\n\n    /**\n     * Set the new spawner-rates multiplier for the island.\n     *\n     * @param spawnerRates The spawner-rates multiplier to set.\n     */\n    public void setSpawnerRates(double spawnerRates) {\n        Preconditions.checkArgument(spawnerRates >= 0, \"Cannot set the spawner rate to a negative multiplier.\");\n        this.spawnerRates = spawnerRates;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpCategoryIconEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.inventory.ItemStack;\n\n/**\n * IslandChangeWarpCategoryIconEvent is called when the icon of a warp-category was changed.\n */\npublic class IslandChangeWarpCategoryIconEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final WarpCategory warpCategory;\n\n    @Nullable\n    private ItemStack icon;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the icon of the warp-category.\n     * @param island         The island of the warp-category.\n     * @param warpCategory   The warp-category that its icon was changed.\n     * @param icon           The new icon of the warp-category.\n     *                       If null, default icon will be set.\n     */\n    public IslandChangeWarpCategoryIconEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory, @Nullable ItemStack icon) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.warpCategory = warpCategory;\n        this.icon = icon == null ? null : icon.clone();\n    }\n\n    /**\n     * Get the player that changed the icon of the warp-category.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp-category that its icon was changed.\n     */\n    public WarpCategory getWarpCategory() {\n        return warpCategory;\n    }\n\n    /**\n     * Get the new icon of the warp-category.\n     */\n    @Nullable\n    public ItemStack getIcon() {\n        return icon == null ? null : icon.clone();\n    }\n\n    /**\n     * Set the new icon for the warp-category.\n     * If set to null, default icon will be set.\n     *\n     * @param icon The new icon to set.\n     */\n    public void setIcon(@Nullable ItemStack icon) {\n        this.icon = icon == null ? null : icon.clone();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpCategorySlotEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeWarpCategorySlotEvent is called when the slot of a warp-category was changed.\n */\npublic class IslandChangeWarpCategorySlotEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final WarpCategory warpCategory;\n    private final int maxSlot;\n\n    private int slot;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the slot of the warp-category.\n     * @param island         The island of the warp-category.\n     * @param warpCategory   The warp-category that its slot was changed.\n     * @param slot           The new slot of the warp-category.\n     * @param maxSlot        The maximum slot that the warp category can occupy.\n     */\n    public IslandChangeWarpCategorySlotEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory,\n                                             int slot, int maxSlot) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.warpCategory = warpCategory;\n        this.slot = slot;\n        this.maxSlot = maxSlot;\n    }\n\n    /**\n     * Get the player that changed the slot of the warp-category.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp-category that its slot was changed.\n     */\n    public WarpCategory getWarpCategory() {\n        return warpCategory;\n    }\n\n    /**\n     * Get the new slot of the warp-category.\n     */\n    public int getSlot() {\n        return slot;\n    }\n\n    /**\n     * Set the new slot for the warp-category.\n     *\n     * @param slot The new slot to set.\n     */\n    public void setSlot(int slot) {\n        Preconditions.checkArgument(slot < maxSlot, \"Cannot set the slot to outside of the inventory space.\");\n        Preconditions.checkState(island.getWarpCategory(slot) == null, \"Cannot change the slot of\" +\n                \" the category to an already existing another category's slot\");\n\n        this.slot = slot;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpIconEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.inventory.ItemStack;\n\n/**\n * IslandChangeWarpIconEvent is called when the icon of a warp was changed.\n */\npublic class IslandChangeWarpIconEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    @Nullable\n    private ItemStack icon;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the icon of the warp.\n     * @param island         The island of the warp.\n     * @param islandWarp     The warp that its icon was changed.\n     * @param icon           The new icon of the warp.\n     *                       If null, default icon will be set.\n     */\n    public IslandChangeWarpIconEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, @Nullable ItemStack icon) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n        this.icon = icon == null ? null : icon.clone();\n    }\n\n    /**\n     * Get the player that changed the icon of the warp.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that its icon was changed.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    /**\n     * Get the new icon of the warp.\n     */\n    @Nullable\n    public ItemStack getIcon() {\n        return icon == null ? null : icon.clone();\n    }\n\n    /**\n     * Set the new icon for the warp.\n     * If set to null, default icon will be set.\n     *\n     * @param icon The new icon to set.\n     */\n    public void setIcon(@Nullable ItemStack icon) {\n        this.icon = icon == null ? null : icon.clone();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpLocationEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeWarpLocationEvent is called when the location of a warp was changed.\n */\npublic class IslandChangeWarpLocationEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    private Location location;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the location of the warp.\n     * @param island         The island of the warp.\n     * @param islandWarp     The warp that its location was changed.\n     * @param location       The new location of the warp.\n     */\n    public IslandChangeWarpLocationEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, Location location) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n        this.location = location.clone();\n    }\n\n    /**\n     * Get the player that changed the location of the warp.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that its location was changed.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    /**\n     * Get the new location of the warp.\n     */\n    public Location getLocation() {\n        return location.clone();\n    }\n\n    /**\n     * Set the new location for the warp.\n     *\n     * @param location The new location to set.\n     */\n    public void setLocation(Location location) {\n        Preconditions.checkNotNull(location, \"Cannot set warp location to null.\");\n        Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n        Preconditions.checkState(island.isInsideRange(location), \"Warp locations must be inside the island's area.\");\n\n        this.location = location.clone();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpsLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChangeWarpsLimitEvent is called when the warps limit of an island is changed.\n */\npublic class IslandChangeWarpsLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private int warpsLimit;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the warps limit of an island.\n     *                       If set to null, it means the limit was changed via the console.\n     * @param island         The island that the warps limit was changed for.\n     * @param warpsLimit     The new warps limit of an island.\n     */\n    public IslandChangeWarpsLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int warpsLimit) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.warpsLimit = warpsLimit;\n    }\n\n    /**\n     * Get the player that changed the warps limit.\n     * If null, it means the limit was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new warps limit of the island.\n     */\n    public int getWarpsLimit() {\n        return warpsLimit;\n    }\n\n    /**\n     * Set the new warps limit of the island.\n     *\n     * @param warpsLimit The new warps limit to set.\n     */\n    public void setWarpsLimit(int warpsLimit) {\n        Preconditions.checkArgument(warpsLimit >= 0, \"Cannot set the warps limit to a negative limit.\");\n        this.warpsLimit = warpsLimit;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWorthBonusEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandChangeWorthBonusEvent is called when the worth-bonus of the island is changed.\n */\npublic class IslandChangeWorthBonusEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Reason reason;\n\n    private BigDecimal worthBonus;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the worth bonus of the island.\n     *                       If set to null, it means the bonus was changed by console.\n     * @param island         The island that the worth bonus was changed for.\n     * @param reason         The reason for changing the worth bonus.\n     * @param worthBonus     The new worth bonus of the island\n     */\n    public IslandChangeWorthBonusEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Reason reason, BigDecimal worthBonus) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.reason = reason;\n        this.worthBonus = worthBonus;\n    }\n\n    /**\n     * Get the player that changed the worth bonus.\n     * If null, it means the bonus was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the reason for changing the worth bonus.\n     */\n    public Reason getReason() {\n        return reason;\n    }\n\n    /**\n     * Get the new worth bonus of the island.\n     */\n    public BigDecimal getWorthBonus() {\n        return worthBonus;\n    }\n\n    /**\n     * Set the new worth bonus for the island.\n     *\n     * @param worthBonus The new worth bonus to set.\n     */\n    public void setWorthBonus(BigDecimal worthBonus) {\n        Preconditions.checkNotNull(worthBonus, \"Cannot set the worth bonus to null.\");\n        this.worthBonus = worthBonus;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * The reason for changing the worth bonus.\n     */\n    public enum Reason {\n\n        /**\n         * The worth bonus was changed due to a command by a player or console.\n         */\n        COMMAND,\n\n        /**\n         * The worth bonus was changed due to schematic that was placed in the world for the island.\n         */\n        SCHEMATIC\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChatEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandChatEvent is called when a player talks in islands chat.\n */\npublic class IslandChatEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private String message;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the player talks in.\n     * @param superiorPlayer The player who sent the message.\n     * @param message        The message that was sent.\n     */\n    public IslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.message = message;\n    }\n\n    /**\n     * Get the player who banned the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the message that the player sent.\n     */\n    public String getMessage() {\n        return message;\n    }\n\n    /**\n     * Set a new message that will be sent.\n     *\n     * @param message The new message to send.\n     */\n    public void setMessage(String message) {\n        Preconditions.checkNotNull(message, \"message parameter cannot be null.\");\n        Preconditions.checkArgument(!message.isEmpty(), \"message cannot be empty.\");\n        this.message = message;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChunkResetEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport org.bukkit.World;\n\n/**\n * IslandChunkResetEvent is called when a chunk is reset inside an island.\n */\npublic class IslandChunkResetEvent extends IslandEvent {\n\n    private final World world;\n    private final int chunkX;\n    private final int chunkZ;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island The island that the chunk was reset in.\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    public IslandChunkResetEvent(Island island, World world, int chunkX, int chunkZ) {\n        super(island);\n        this.world = world;\n        this.chunkX = chunkX;\n        this.chunkZ = chunkZ;\n    }\n\n    /**\n     * Get the world of the chunk.\n     */\n    public World getWorld() {\n        return world;\n    }\n\n    /**\n     * Get the x-coords of the chunk.\n     */\n    public int getChunkX() {\n        return chunkX;\n    }\n\n    /**\n     * Get the z-coords of the chunk.\n     */\n    public int getChunkZ() {\n        return chunkZ;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandClearFlagsEvent is called when flags are cleared on an island.\n */\npublic class IslandClearFlagsEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the flags were cleared in.\n     * @param superiorPlayer The player that cleared the flags, or null if it was done by console.\n     */\n    public IslandClearFlagsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that cleared the flags to the island, or null if it was done by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearGeneratorRatesEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandClearGeneratorRatesEvent is called when clearing generator-rates of an island.\n */\npublic class IslandClearGeneratorRatesEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Dimension dimension;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that cleared the generator-rates of an island.\n     *                       If set to null, it means the rates were cleared via the console.\n     * @param island         The island that the generator-rates were cleared for.\n     * @param environment    The environment of the world that the rates were cleared for.\n     */\n    @Deprecated\n    public IslandClearGeneratorRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, World.Environment environment) {\n        this(superiorPlayer, island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that cleared the generator-rates of an island.\n     *                       If set to null, it means the rates were cleared via the console.\n     * @param island         The island that the generator-rates were cleared for.\n     * @param dimension      The dimension of the world that the rates were cleared for.\n     */\n    public IslandClearGeneratorRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Dimension dimension) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the player that cleared the generator-rates.\n     * If null, it means the rates were cleared by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the environment of the world that the rates were cleared for.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the environment of the world that the rates were cleared for.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearPlayerPrivilegesEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandClearPlayerPrivilegesEvent is called when privileges of a player is cleared on an island.\n */\npublic class IslandClearPlayerPrivilegesEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer privilegedPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island           The island that the privileges were cleared in.\n     * @param superiorPlayer   The player that cleared the privileges to the other player.\n     * @param privilegedPlayer The player that the privileges were cleared for.\n     */\n    public IslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.privilegedPlayer = privilegedPlayer;\n    }\n\n    /**\n     * Get the player that cleared the privileges to the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that the privileges were cleared for.\n     */\n    public SuperiorPlayer getPrivilegedPlayer() {\n        return privilegedPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRatingsEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandClearRatingsEvent is called when all ratings of an island are cleared.\n */\npublic class IslandClearRatingsEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that cleared the ratings of the island.\n     *                       If null, the ratings were cleared by console.\n     * @param island         The island that was cleared from ratings.\n     */\n    public IslandClearRatingsEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that cleared the ratings of the island.\n     * If null, the ratings were cleared by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandClearRolesPrivilegesEvent is called when privileges of roles are cleared on an island.\n */\npublic class IslandClearRolesPrivilegesEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the privileges were cleared in.\n     * @param superiorPlayer The player that cleared the privileges, or null if it was done by console.\n     */\n    public IslandClearRolesPrivilegesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that cleared the privileges to the island, or null if it was done by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCloseEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCloseEvent is called when the island is closed for visitors.\n */\npublic class IslandCloseEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that closed the island.\n     *                       If null, then the island was opened by console.\n     * @param island         The island that was closed.\n     */\n    public IslandCloseEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that closed the island.\n     * If null, then the island was opened by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCloseWarpEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCloseWarpEvent is called when closing the warp to the public.\n */\npublic class IslandCloseWarpEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that closed the warp to the public.\n     * @param island         The island of the warp.\n     * @param islandWarp     The warp that was closed.\n     */\n    public IslandCloseWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n    }\n\n    /**\n     * Get the player that closed the warp to the public.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that was closed.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCoopPlayerEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCoopPlayerEvent is called when a player is making another player coop on their island.\n */\npublic class IslandCoopPlayerEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer player;\n    private final SuperiorPlayer target;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island The island that the leadership of it is transferred.\n     * @param player The player who cooped the target.\n     * @param target The player that will be cooped.\n     */\n    public IslandCoopPlayerEvent(Island island, SuperiorPlayer player, SuperiorPlayer target) {\n        super(island);\n        this.player = player;\n        this.target = target;\n    }\n\n    /**\n     * Get the player who cooped the target.\n     */\n    public SuperiorPlayer getPlayer() {\n        return player;\n    }\n\n    /**\n     * Get the player that will be cooped.\n     */\n    public SuperiorPlayer getTarget() {\n        return target;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCreateEvent is called when a new island is created.\n */\npublic class IslandCreateEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final String schematic;\n    private boolean teleport;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @param island         The island object that was created.\n     * @deprecated See IslandCreateEvent(SuperiorPlayer, Island, String)\n     */\n    @Deprecated\n    public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) {\n        this(superiorPlayer, island, \"\");\n    }\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @param island         The island object that was created.\n     * @param schematic      The schematic that was used.\n     */\n    public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic) {\n        this(superiorPlayer, island, schematic, true);\n    }\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @param island         The island object that was created.\n     * @param schematic      The schematic that was used.\n     * @param teleport       Whether the player should be teleported after creation.\n     */\n    public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic, boolean teleport) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.schematic = schematic;\n        this.teleport = teleport;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the schematic that was used.\n     */\n    public String getSchematic() {\n        return schematic;\n    }\n\n    /**\n     * Check if the player should get teleported when the process finishes.\n     */\n    public boolean canTeleport() {\n        return teleport;\n    }\n\n    /**\n     * Set whether or not the player should be teleported to the island when the process finishes.\n     */\n    public void setTeleport(boolean teleport) {\n        this.teleport = teleport;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateWarpCategoryEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCreateWarpCategoryEvent is called when a new warp-category is created on an island.\n */\npublic class IslandCreateWarpCategoryEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final String categoryName;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that created the warp-category.\n     * @param island         The island that the warp-category was created on.\n     * @param categoryName   The name of the new warp-category.\n     */\n    public IslandCreateWarpCategoryEvent(SuperiorPlayer superiorPlayer, Island island, String categoryName) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.categoryName = categoryName;\n    }\n\n    /**\n     * Get the player that created the warp-category.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the name of the new warp-category.\n     */\n    public String getCategoryName() {\n        return categoryName;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateWarpEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandCreateWarpEvent is called when a new warp is created on an island.\n */\npublic class IslandCreateWarpEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final String warpName;\n    private final Location location;\n    private final boolean openToPublic;\n    @Nullable\n    private final WarpCategory warpCategory;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that created the warp.\n     * @param island         The island that the warp was created on.\n     * @param warpName       The name of the new warp.\n     * @param location       The location of the new warp.\n     * @param openToPublic   Whether the island is open to the public.\n     * @param warpCategory   The category of the new warp.\n     *                       If null, it means the warp will be added to the first found category;\n     *                       if no category exists, new one will be created for the warp.\n     */\n    public IslandCreateWarpEvent(SuperiorPlayer superiorPlayer, Island island, String warpName, Location location,\n                                 boolean openToPublic, @Nullable WarpCategory warpCategory) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.warpName = warpName;\n        this.location = location.clone();\n        this.openToPublic = openToPublic;\n        this.warpCategory = warpCategory;\n    }\n\n    /**\n     * Get the player that created the warp.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the name of the new warp.\n     */\n    public String getWarpName() {\n        return warpName;\n    }\n\n    /**\n     * Get the location of the new warp.\n     */\n    public Location getLocation() {\n        return location.clone();\n    }\n\n    /**\n     * Get whether the warp is opened to the public.\n     */\n    public boolean isOpenToPublic() {\n        return openToPublic;\n    }\n\n    /**\n     * Get the category of the new warp.\n     * If null, it means the warp will be added to the first found category;\n     * if no category exists, new one will be created for the warp.\n     */\n    @Nullable\n    public WarpCategory getWarpCategory() {\n        return warpCategory;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDeleteWarpEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandDeleteWarpEvent is called when a warp is deleted from an island.\n */\npublic class IslandDeleteWarpEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that deleted the warp.\n     *                       If null, then the warp was deleted by the console.\n     * @param island         The island that the warp was deleted from.\n     * @param islandWarp     The warp that was deleted.\n     */\n    public IslandDeleteWarpEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n    }\n\n    /**\n     * Get the player that deleted the warp.\n     * If null, then the warp was deleted by the console or not by a command.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that was deleted.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDisableFlagEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandDisableFlagEvent is called when a flag is disabling for an island.\n */\npublic class IslandDisableFlagEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandFlag islandFlag;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that disabled the island flag for the island.\n     *                       If null, the flag was disabled by console.\n     * @param island         The island that the flag was disabled for.\n     * @param islandFlag     The flag that was disabled.\n     */\n    public IslandDisableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandFlag = islandFlag;\n    }\n\n    /**\n     * Get the player that disabled the island flag for the island.\n     * If null, the flag was disabled by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the flag that was disabled.\n     */\n    public IslandFlag getIslandFlag() {\n        return islandFlag;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDisbandEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandDisbandEvent is called when an island is disbanded.\n */\npublic class IslandDisbandEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who proceed the operation.\n     * @param island         The island that is being disbanded.\n     */\n    public IslandDisbandEvent(SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who proceed the operation.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnableFlagEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandEnableFlagEvent is called when a flag is enabled for an island.\n */\npublic class IslandEnableFlagEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandFlag islandFlag;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that enabled the island flag for the island.\n     *                       If null, the flag was enabled by console.\n     * @param island         The island that the flag was enabled for.\n     * @param islandFlag     The flag that was enabled.\n     */\n    public IslandEnableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandFlag = islandFlag;\n    }\n\n    /**\n     * Get the player that enabled the island flag for the island.\n     * If null, the flag was enabled by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the flag that was enabled.\n     */\n    public IslandFlag getIslandFlag() {\n        return islandFlag;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandEnterEvent is called when a player is walking into an island's area.\n */\npublic class IslandEnterEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final EnterCause enterCause;\n    private boolean cancelled = false;\n    private Location cancelTeleport = null;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who entered to the island's area.\n     * @param island         The island that the player entered into.\n     * @param enterCause     The cause of entering into the island.\n     */\n    public IslandEnterEvent(SuperiorPlayer superiorPlayer, Island island, EnterCause enterCause) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.enterCause = enterCause;\n    }\n\n    /**\n     * Get the player who entered to the island's area.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the cause of entering into the island.\n     */\n    public EnterCause getCause() {\n        return enterCause;\n    }\n\n    /**\n     * Get the location the player would be teleported if the event is cancelled.\n     */\n    public Location getCancelTeleport() {\n        return cancelTeleport == null ? null : cancelTeleport.clone();\n    }\n\n    /**\n     * Set the location the player would be teleported if the event is cancelled.\n     */\n    public void setCancelTeleport(Location cancelTeleport) {\n        this.cancelTeleport = cancelTeleport.clone();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * Used to determine the cause of entering.\n     */\n    public enum EnterCause {\n\n        PLAYER_MOVE,\n        PLAYER_TELEPORT,\n        PLAYER_JOIN,\n        PORTAL,\n        INVALID\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterPortalEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandEnterPortalEvent is called when a player enters a portal on an island.\n */\npublic class IslandEnterPortalEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final PortalType portalType;\n    private Dimension destination;\n    @Nullable\n    private Schematic schematic;\n    private boolean ignoreInvalidSchematic;\n\n    private boolean cancelled = false;\n\n    /**\n     * Constructor of the event\n     *\n     * @param island                 The island that the player entered the portal at.\n     * @param superiorPlayer         The player that entered the portal.\n     * @param portalType             The type of the portal used.\n     * @param destination            The destination of the portal.\n     * @param schematic              The schematic to be placed, if exists.\n     * @param ignoreInvalidSchematic Whether to ignore invalid schematics.\n     */\n    @Deprecated\n    public IslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, PortalType portalType,\n                                  World.Environment destination, @Nullable Schematic schematic,\n                                  boolean ignoreInvalidSchematic) {\n        this(island, superiorPlayer, portalType, Dimension.getByName(destination.name()),\n                schematic, ignoreInvalidSchematic);\n    }\n\n    /**\n     * Constructor of the event\n     *\n     * @param island                 The island that the player entered the portal at.\n     * @param superiorPlayer         The player that entered the portal.\n     * @param portalType             The type of the portal used.\n     * @param destination            The destination of the portal.\n     * @param schematic              The schematic to be placed, if exists.\n     * @param ignoreInvalidSchematic Whether to ignore invalid schematics.\n     */\n    public IslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, PortalType portalType,\n                                  Dimension destination, @Nullable Schematic schematic,\n                                  boolean ignoreInvalidSchematic) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.portalType = portalType;\n        this.destination = destination;\n        this.schematic = schematic;\n        this.ignoreInvalidSchematic = ignoreInvalidSchematic;\n    }\n\n    /**\n     * Get the player that entered the portal.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the type of the portal.\n     */\n    public PortalType getPortalType() {\n        return portalType;\n    }\n\n    /**\n     * Get the destination world of the portal.\n     */\n    @Deprecated\n    public World.Environment getDestination() {\n        return this.destination.getEnvironment();\n    }\n\n    /**\n     * Get the destination world of the portal.\n     */\n    public Dimension getDestinationDimension() {\n        return destination;\n    }\n\n    /**\n     * Set the destination of the teleportation.\n     *\n     * @param destination The destination to set.\n     */\n    @Deprecated\n    public void setDestination(World.Environment destination) {\n        this.setDestination(Dimension.getByName(destination.name()));\n    }\n\n    /**\n     * Set the destination of the teleportation.\n     *\n     * @param destination The destination to set.\n     */\n    public void setDestination(Dimension destination) {\n        this.destination = destination;\n    }\n\n    /**\n     * Get the schematic that will be placed before teleporting.\n     *\n     * @return The schematic that will be placed, or null if no schematic should be placed.\n     */\n    @Nullable\n    public Schematic getSchematic() {\n        return schematic;\n    }\n\n    /**\n     * Set the schematic that will be placed.\n     * Warning: If a schematic was already been placed and you set this to non-null, a new schematic will be placed\n     * on top of the already blocks.\n     *\n     * @param schematic The schematic to be placed.\n     *                  If null, no schematic will be used and {@link #isIgnoreInvalidSchematic()} will be set to true.\n     */\n    public void setSchematic(@Nullable Schematic schematic) {\n        this.schematic = schematic;\n        if (schematic == null)\n            setIgnoreInvalidSchematic(true);\n    }\n\n    /**\n     * Check whether the plugin should not send a warning if {@link #getSchematic()} is null.\n     */\n    public boolean isIgnoreInvalidSchematic() {\n        return ignoreInvalidSchematic;\n    }\n\n    /**\n     * Set whether the plugin should send a warning to the player if {@link #getSchematic()} is null.\n     *\n     * @param ignoreInvalidSchematic Whether to send a warning or not.\n     */\n    public void setIgnoreInvalidSchematic(boolean ignoreInvalidSchematic) {\n        this.ignoreInvalidSchematic = ignoreInvalidSchematic;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterProtectedEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.HandlerList;\n\n/**\n * IslandEnterProtectedEvent is called when a player is walking into an island's protected area.\n * The protected area is the area that players can build in.\n */\npublic class IslandEnterProtectedEvent extends IslandEnterEvent {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who entered to the island's area.\n     * @param island         The island that the player entered into.\n     * @param enterCause     The cause of entering into the island.\n     */\n    public IslandEnterProtectedEvent(SuperiorPlayer superiorPlayer, Island island, EnterCause enterCause) {\n        super(superiorPlayer, island, enterCause);\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * All the island events extend IslandEvent.\n */\npublic abstract class IslandEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    protected final Island island;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param island The island object that was involved in the event.\n     */\n    public IslandEvent(Island island) {\n        super(!Bukkit.isPrimaryThread());\n        this.island = island;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    /**\n     * Get the island that was involved in the event.\n     */\n    public Island getIsland() {\n        return island;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandGenerateBlockEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandGenerateBlockEvent is called when a cobblestone generator generates a block.\n */\npublic class IslandGenerateBlockEvent extends IslandEvent implements Cancellable {\n\n    private final Location location;\n\n    private Key block;\n    private boolean placeBlock = true;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island   The island that the block was generated in.\n     * @param location The location of the generated block.\n     * @param block    The block that was generated.\n     */\n    public IslandGenerateBlockEvent(Island island, Location location, Key block) {\n        super(island);\n        this.block = block;\n        this.location = location.clone();\n    }\n\n    /**\n     * Get the location of the block.\n     */\n    public Location getLocation() {\n        return location.clone();\n    }\n\n    /**\n     * Get the block that was generated.\n     */\n    public Key getBlock() {\n        return block;\n    }\n\n    /**\n     * Set the block to be generated.\n     *\n     * @param block The new block.\n     */\n    public void setBlock(Key block) {\n        Preconditions.checkNotNull(block, \"Cannot set block to null.\");\n        this.block = block;\n    }\n\n    /**\n     * Check whether the generated block should be set manually in the world.\n     */\n    public boolean isPlaceBlock() {\n        return placeBlock;\n    }\n\n    /**\n     * Set whether the generated block should be set manually in the world.\n     */\n    public void setPlaceBlock(boolean placeBlock) {\n        this.placeBlock = placeBlock;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandHomeTeleportEvent is called when a player teleports to island home.\n */\npublic class IslandHomeTeleportEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final Dimension dimension;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the player teleports to.\n     * @param superiorPlayer The player who teleports to the island home.\n     * @param dimension      The dimension that the player teleports to.\n     */\n    public IslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the player who teleports to the island home.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the dimension that the player teleports to.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandInviteEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandInviteEvent is called when a player is invited to an island.\n */\npublic class IslandInviteEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer targetPlayer;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who sent the invite request.\n     * @param targetPlayer   The player who received the invite request.\n     * @param island         The island that the player was invited into.\n     */\n    public IslandInviteEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.targetPlayer = targetPlayer;\n    }\n\n    /**\n     * Get the player who sent the invite request.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player who received the invite request.\n     */\n    public SuperiorPlayer getTarget() {\n        return targetPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandJoinEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandJoinEvent is called when a player is joining an island as a member of that island.\n */\npublic class IslandJoinEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final Cause cause;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor to the event.\n     *\n     * @param superiorPlayer The player who joined the island as a new member.\n     * @param island         The island that the player joined into.\n     * @deprecated See {@link #IslandJoinEvent(SuperiorPlayer, Island, Cause)}\n     */\n    @Deprecated\n    public IslandJoinEvent(SuperiorPlayer superiorPlayer, Island island) {\n        this(superiorPlayer, island, Cause.INVITE);\n    }\n\n    /**\n     * The constructor to the event.\n     *\n     * @param superiorPlayer The player who joined the island as a new member.\n     * @param island         The island that the player joined into.\n     * @param cause          The cause of joining the island.\n     */\n    public IslandJoinEvent(SuperiorPlayer superiorPlayer, Island island, Cause cause) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.cause = cause;\n    }\n\n    /**\n     * Get the player who joined the island as a new member.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the cause of joining the island.\n     */\n    public Cause getCause() {\n        return cause;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * The cause of joining an island.\n     */\n    public enum Cause {\n\n        /**\n         * The player accepted an invitation to the island.\n         */\n        INVITE,\n\n        /**\n         * The player was joined due to an admin, either by `/is admin add` or `/is admin join`\n         */\n        ADMIN\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandKickEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandKickEvent is called when a player is kicked from his island.\n */\npublic class IslandKickEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer targetPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who kicked the other player. If null, it means console kicked the player.\n     * @param targetPlayer   The player that was kicked.\n     * @param island         The island that the player was kicked from.\n     */\n    public IslandKickEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.targetPlayer = targetPlayer;\n    }\n\n    /**\n     * Get the player who kicked the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that was kicked.\n     */\n    public SuperiorPlayer getTarget() {\n        return targetPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLeaveEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandLeaveEvent is called when a player is walking out from the island's area.\n */\npublic class IslandLeaveEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final LeaveCause leaveCause;\n    @Nullable\n    private final Location toLocation;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who left the island's area.\n     * @param island         The island that the player left.\n     * @param leaveCause     The cause of leaving the island.\n     * @param toLocation     The location the player will be at after leaving.\n     */\n    public IslandLeaveEvent(SuperiorPlayer superiorPlayer, Island island, LeaveCause leaveCause, @Nullable Location toLocation) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.leaveCause = leaveCause;\n        this.toLocation = toLocation;\n    }\n\n    /**\n     * Get the player who left the island's area.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the cause of leaving the island.\n     */\n    public LeaveCause getCause() {\n        return leaveCause;\n    }\n\n    /**\n     * Get the location the player will be after he's leaving.\n     * If the location is null, it means the player left the game.\n     */\n    @Nullable\n    public Location getTo() {\n        return toLocation;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * Used to determine the cause of leaving.\n     */\n    public enum LeaveCause {\n\n        PLAYER_MOVE,\n        PLAYER_TELEPORT,\n        PLAYER_QUIT,\n        INVALID\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLeaveProtectedEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.event.HandlerList;\n\n/**\n * IslandLeaveProtectedEvent is called when a player is walking out from the island's protected area.\n * The protected area is the area that players can build in.\n */\npublic class IslandLeaveProtectedEvent extends IslandLeaveEvent {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who left the island's protected area.\n     * @param island         The island that the player left.\n     * @param leaveCause     The cause of leaving the island.\n     * @param toLocation     The location the player will be at after leaving.\n     */\n    public IslandLeaveProtectedEvent(SuperiorPlayer superiorPlayer, Island island, LeaveCause leaveCause, Location toLocation) {\n        super(superiorPlayer, island, leaveCause, toLocation);\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLockWorldEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandLockWorldEvent is called when a world is locked to an island.\n */\npublic class IslandLockWorldEvent extends IslandEvent implements Cancellable {\n\n    private final Dimension dimension;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island      The island that the world was locked for.\n     * @param environment The environment of the world that is locked.\n     */\n    @Deprecated\n    public IslandLockWorldEvent(Island island, World.Environment environment) {\n        this(island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island    The island that the world was locked for.\n     * @param dimension The dimension of the world that is locked.\n     */\n    public IslandLockWorldEvent(Island island, Dimension dimension) {\n        super(island);\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the environment of the world that is being locked.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the environment of the world that is being locked.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandOpenEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandOpenEvent is called when the island is opened for visitors.\n */\npublic class IslandOpenEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that opened the island.\n     *                       If null, then the island was opened by console.\n     * @param island         The island that was opened.\n     */\n    public IslandOpenEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who locked the island.\n     * If null, then the island was opened by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandOpenWarpEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandOpenWarpEvent is called when opening the warp to the public.\n */\npublic class IslandOpenWarpEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that opened the warp to the public.\n     * @param island         The island of the warp.\n     * @param islandWarp     The warp that was opened.\n     */\n    public IslandOpenWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n    }\n\n    /**\n     * Get the player that opened the warp to the public.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that was opened.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandQuitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandQuitEvent is called when a player is leaving their island.\n */\npublic class IslandQuitEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who left their island.\n     * @param island         The island that the player left.\n     */\n    public IslandQuitEvent(SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who left their island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRateEvent is called when a player rates an island.\n */\npublic class IslandRateEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer ratingPlayer;\n    private final Rating rating;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the rating of the other player.\n     *                       If null, the rating was changed by console.\n     * @param ratingPlayer   The player that its rating was changed.\n     * @param island         The island that was rated.\n     * @param rating         The rating given to the island.\n     */\n    public IslandRateEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island, Rating rating) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.ratingPlayer = ratingPlayer;\n        this.rating = rating;\n    }\n\n    /**\n     * Get the player that changed the rating of the other player.\n     * If null, the rating was changed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that its rating was changed.\n     */\n    public SuperiorPlayer getRatingPlayer() {\n        return ratingPlayer;\n    }\n\n    /**\n     * Get the rating given to the island.\n     */\n    public Rating getRating() {\n        return rating;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveBlockLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRemoveBlockLimitEvent is called when a block-limit of an island is removed.\n */\npublic class IslandRemoveBlockLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key block;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the block limit of an island.\n     *                       If set to null, it means the limit was removed via the console.\n     * @param island         The island that the block limit was removed for.\n     * @param block          The block that the limit was removed for.\n     */\n    public IslandRemoveBlockLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.block = block;\n    }\n\n    /**\n     * Get the player that removed the block limit.\n     * If null, it means the limit was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the block that the limit was removed for.\n     */\n    public Key getBlock() {\n        return block;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEffectEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.potion.PotionEffectType;\n\n/**\n * IslandRemoveEffectLevelEvent is called when an effect of an island is removed.\n */\npublic class IslandRemoveEffectEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final PotionEffectType effectType;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the effect level of an island.\n     *                       If set to null, it means the effect was removed via the console.\n     * @param island         The island that the effect level was removed for.\n     * @param effectType     The effect that was removed from the island.\n     */\n    public IslandRemoveEffectEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PotionEffectType effectType) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.effectType = effectType;\n    }\n\n    /**\n     * Get the player that removed the effect level.\n     * If null, it means the effect was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the effect that was removed from the island.\n     */\n    public PotionEffectType getEffectType() {\n        return effectType;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRemoveEntityLimitEvent is called when an entity-limit of an island is removed.\n */\npublic class IslandRemoveEntityLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key entity;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the entity limit of an island.\n     *                       If set to null, it means the limit was removed via the console.\n     * @param island         The island that the entity limit was removed for.\n     * @param entity         The entity that the limit was removed for.\n     */\n    public IslandRemoveEntityLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key entity) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.entity = entity;\n    }\n\n    /**\n     * Get the player that removed the entity limit.\n     * If null, it means the limit was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the entity that the limit was removed for.\n     */\n    public Key getEntity() {\n        return entity;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveGeneratorRateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandRemoveGeneratorRateEvent is called when a generator-rate of an island is removed.\n */\npublic class IslandRemoveGeneratorRateEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Key block;\n    private final Dimension dimension;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the generator-rate of an island.\n     *                       If set to null, it means the rate was removed via the console.\n     * @param island         The island that the generator-rate was removed for.\n     * @param block          The block that the rate was removed for.\n     * @param environment    The environment of the world that the rate was removed for.\n     */\n    @Deprecated\n    public IslandRemoveGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block,\n                                          World.Environment environment) {\n        this(superiorPlayer, island, block, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the generator-rate of an island.\n     *                       If set to null, it means the rate was removed via the console.\n     * @param island         The island that the generator-rate was removed for.\n     * @param block          The block that the rate was removed for.\n     * @param dimension      The dimension of the world that the rate was removed for.\n     */\n    public IslandRemoveGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block,\n                                          Dimension dimension) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.block = block;\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the player that removed the generator-rate.\n     * If null, it means the level was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the block that the generator-rate was removed for.\n     */\n    public Key getBlock() {\n        return block;\n    }\n\n    /**\n     * Get the environment of the world that the rate was removed for.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the environment of the world that the rate was removed for.\n     */\n    public Dimension getDimension() {\n        return dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveRatingEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRemoveRatingEvent is called when a rating of a player is removed from an island.\n */\npublic class IslandRemoveRatingEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer ratingPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the rating of the other player.\n     *                       If null, the rating was removed by console.\n     * @param ratingPlayer   The player that its rating was removed.\n     * @param island         The island that was rated.\n     */\n    public IslandRemoveRatingEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.ratingPlayer = ratingPlayer;\n    }\n\n    /**\n     * Get the player that removed the rating of the other player.\n     * If null, the rating was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that its rating was removed.\n     */\n    public SuperiorPlayer getRatingPlayer() {\n        return ratingPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveRoleLimitEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandRemoveRoleLimitEvent is called when a role-limit of an island is removed.\n */\npublic class IslandRemoveRoleLimitEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final PlayerRole playerRole;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed a role-limit from an island.\n     *                       If set to null, it means the limit was removed via the console.\n     * @param island         The island that the role-limit was removed from.\n     * @param playerRole     The role that its limit was removed.\n     */\n    public IslandRemoveRoleLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.playerRole = playerRole;\n    }\n\n    /**\n     * Get the player that removed the role-limit.\n     * If null, it means the limit was removed by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the role that its limit was removed.\n     */\n    public PlayerRole getPlayerRole() {\n        return playerRole;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRemoveVisitorHomeEvent is called when the visitor home of the island is removed.\n */\npublic class IslandRemoveVisitorHomeEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that removed the island visitor home.\n     *                       If null, then the warp was deleted by the console or another source\n     * @param island         The island that the visitor home was removed.\n     */\n    public IslandRemoveVisitorHomeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who removed the island visitor home.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRenameEvent is called when an island changes its name.\n */\npublic class IslandRenameEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private String islandName;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that was renamed.\n     * @param superiorPlayer The player that renamed the island.\n     *                       If null, the island was renamed by console.\n     * @param islandName     The new name of the island.\n     */\n    public IslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandName = islandName;\n    }\n\n    /**\n     * Get the player that changed the privilege to the other player.\n     * If null, the privilege was changed by the console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new name of the island.\n     */\n    public String getIslandName() {\n        return islandName;\n    }\n\n    /**\n     * Set the new name of the island.\n     *\n     * @param islandName The new name to set.\n     */\n    public void setIslandName(String islandName) {\n        Preconditions.checkNotNull(islandName, \"Island names cannot be null.\");\n        this.islandName = islandName;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameWarpCategoryEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRenameWarpCategoryEvent is called when renaming a warp-category.\n */\npublic class IslandRenameWarpCategoryEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final WarpCategory warpCategory;\n\n    private String categoryName;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that renamed the warp-category.\n     * @param island         The island of the warp-category.\n     * @param warpCategory   The warp-category that was renamed.\n     * @param categoryName   The new name of the warp-category.\n     */\n    public IslandRenameWarpCategoryEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory, String categoryName) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.warpCategory = warpCategory;\n        this.categoryName = categoryName;\n    }\n\n    /**\n     * Get the player that renamed the warp-category.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp-category that was renamed.\n     */\n    public WarpCategory getWarpCategory() {\n        return warpCategory;\n    }\n\n    /**\n     * Get the new name of the warp-category.\n     */\n    public String getCategoryName() {\n        return categoryName;\n    }\n\n    /**\n     * Set the new name for the warp-category.\n     *\n     * @param categoryName The new warp-category name to set.\n     */\n    public void setCategoryName(String categoryName) {\n        Preconditions.checkNotNull(categoryName, \"Cannot set warp-category name to null.\");\n        Preconditions.checkArgument(categoryName.length() <= 255, \"Category names cannot be longer than 255 chars.\");\n        Preconditions.checkState(island.getWarpCategory(categoryName) == null, \"Cannot rename warp-categories to an already existing categories.\");\n\n        this.categoryName = categoryName;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameWarpEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandRenameWarpEvent is called when renaming a warp.\n */\npublic class IslandRenameWarpEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n\n    private String warpName;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that renamed the warp.\n     * @param island         The island of the warp.\n     * @param islandWarp     The warp that was renamed.\n     * @param warpName       The new name of the warp.\n     */\n    public IslandRenameWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, String warpName) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n        this.warpName = warpName;\n    }\n\n    /**\n     * Get the player that renamed the warp.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the warp that was renamed.\n     */\n    public IslandWarp getIslandWarp() {\n        return islandWarp;\n    }\n\n    /**\n     * Get the new name of the warp.\n     */\n    public String getWarpName() {\n        return warpName;\n    }\n\n    /**\n     * Set the new name for the warp.\n     *\n     * @param warpName The new warp name to set.\n     */\n    public void setWarpName(String warpName) {\n        Preconditions.checkNotNull(warpName, \"Cannot set warp name to null.\");\n        Preconditions.checkArgument(warpName.length() <= 255, \"Warp names cannot be longer than 255 chars.\");\n        Preconditions.checkState(island.getWarp(warpName) == null, \"Cannot rename warps to an already existing warps.\");\n\n        this.warpName = warpName;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRestrictMoveEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * IslandRestrictMoveEvent is called when a player is cancelled from moving by the plugin.\n */\npublic class IslandRestrictMoveEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final RestrictReason restrictReason;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player which was restricted.\n     * @param restrictReason The reason for the restriction.\n     */\n    public IslandRestrictMoveEvent(SuperiorPlayer superiorPlayer, RestrictReason restrictReason) {\n        this.superiorPlayer = superiorPlayer;\n        this.restrictReason = restrictReason;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    /**\n     * Get the player which was restricted.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the reason for the restriction.\n     */\n    public RestrictReason getRestrictReason() {\n        return restrictReason;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public enum RestrictReason {\n\n        LEAVE_ISLAND_TO_OUTSIDE,\n        LEAVE_PROTECTED_EVENT_CANCELLED,\n        LEAVE_EVENT_CANCELLED,\n\n        BANNED_FROM_ISLAND,\n        LOCKED_ISLAND,\n        ENTER_PROTECTED_EVENT_CANCELLED,\n        ENTER_EVENT_CANCELLED,\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSchematicPasteEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport org.bukkit.Location;\n\n/**\n * IslandSchematicPasteEvent is called when a schematic is placed.\n */\npublic class IslandSchematicPasteEvent extends IslandEvent {\n\n    private final String schematic;\n    private final Location location;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param island    The island object that was created.\n     * @param schematic The schematic that was used.\n     * @param location  The location the schematic was pasted at.\n     */\n    public IslandSchematicPasteEvent(Island island, String schematic, Location location) {\n        super(island);\n        this.schematic = schematic;\n        this.location = location.clone();\n    }\n\n    /**\n     * Get the schematic that was used.\n     */\n    public String getSchematic() {\n        return schematic;\n    }\n\n    /**\n     * Get the location that the schematic was pasted at.\n     */\n    public Location getLocation() {\n        return location;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSetHomeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandSetHomeEvent is called when a new home is set to the island.\n */\npublic class IslandSetHomeEvent extends IslandEvent implements Cancellable {\n\n    private final Reason reason;\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n\n    private Location islandHome;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the home was changed for.\n     * @param islandHome     The new island home of the island.\n     * @param reason         The reason the home was changed.\n     * @param superiorPlayer The player that changed the island home, if exists\n     */\n    public IslandSetHomeEvent(Island island, Location islandHome, Reason reason, @Nullable SuperiorPlayer superiorPlayer) {\n        super(island);\n        this.islandHome = islandHome.clone();\n        this.reason = reason;\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the new island home location of the island.\n     */\n    public Location getIslandHome() {\n        return islandHome.clone();\n    }\n\n    /**\n     * Set the new home location of the island.\n     *\n     * @param islandHome The home location for the island.\n     */\n    public void setIslandHome(Location islandHome) {\n        Preconditions.checkNotNull(islandHome.getWorld(), \"Cannot set island home with null world\");\n        this.islandHome = islandHome.clone();\n    }\n\n    /**\n     * Get the reason the home was changed.\n     */\n    public Reason getReason() {\n        return reason;\n    }\n\n    /**\n     * Get the player who changed the island home, if exists.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    /**\n     * The reason the home was changed.\n     */\n    public enum Reason {\n\n        /**\n         * The home was changed through a command.\n         */\n        SET_HOME_COMMAND,\n\n        /**\n         * The home was changed because the old home was not safe.\n         */\n        SAFE_HOME\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSetVisitorHomeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandSetVisitorHomeEvent is called when a new visitor home is set to the island.\n */\npublic class IslandSetVisitorHomeEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private Location islandVisitorHome;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer    The player that changed the island visitor home.\n     * @param island            The island that the visitor home was changed for.\n     * @param islandVisitorHome The new island visitor home of the island.\n     */\n    public IslandSetVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island, Location islandVisitorHome) {\n        super(island);\n        this.islandVisitorHome = islandVisitorHome.clone();\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who changed the island home, if exists.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new island visitor home location of the island.\n     */\n    public Location getIslandVisitorHome() {\n        return islandVisitorHome.clone();\n    }\n\n    /**\n     * Set the new visitor home location of the island.\n     * Setting the visitor home location outside the island's area may lead to undefined behaviors.\n     *\n     * @param islandVisitorHome The new home visitor location for the island.\n     */\n    public void setIslandHome(Location islandVisitorHome) {\n        Preconditions.checkNotNull(islandVisitorHome.getWorld(), \"Cannot set island visitor home with null world\");\n        this.islandVisitorHome = islandVisitorHome.clone();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandTransferEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandTransferEvent is called when the leadership of an island is transferred.\n */\npublic class IslandTransferEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer oldOwner;\n    private final SuperiorPlayer newOwner;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island   The island that the leadership of it is transferred.\n     * @param oldOwner The old owner of the island.\n     * @param newOwner The new owner of the island.\n     */\n    public IslandTransferEvent(Island island, SuperiorPlayer oldOwner, SuperiorPlayer newOwner) {\n        super(island);\n        this.oldOwner = oldOwner;\n        this.newOwner = newOwner;\n    }\n\n    /**\n     * Get the old owner of the island.\n     */\n    public SuperiorPlayer getOldOwner() {\n        return oldOwner;\n    }\n\n    /**\n     * Get the new owner of the island.\n     */\n    public SuperiorPlayer getNewOwner() {\n        return newOwner;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUnbanEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandUnbanEvent is called when a player is unbanned from his island.\n */\npublic class IslandUnbanEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final SuperiorPlayer targetPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who unbanned the other player.\n     * @param targetPlayer   The player that was unbanned.\n     * @param island         The island that the player was unbanned from.\n     */\n    public IslandUnbanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.targetPlayer = targetPlayer;\n    }\n\n    /**\n     * Get the player who unbanned the other player.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the player that was unbanned.\n     */\n    public SuperiorPlayer getUnbannedPlayer() {\n        return targetPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUncoopPlayerEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n\n/**\n * IslandUncoopPlayerEvent is called when a player is making another player no longer coop on their island.\n */\npublic class IslandUncoopPlayerEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer player;\n    private final SuperiorPlayer target;\n    private final UncoopReason uncoopReason;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island       The island that the leadership of it is transferred.\n     * @param player       The player who cooped the target, if exists.\n     * @param target       The player that will no longer be coop.\n     * @param uncoopReason The reason for the action.\n     */\n    public IslandUncoopPlayerEvent(Island island, @Nullable SuperiorPlayer player, SuperiorPlayer target, UncoopReason uncoopReason) {\n        super(island);\n        this.player = player;\n        this.target = target;\n        this.uncoopReason = uncoopReason;\n    }\n\n    /**\n     * Get the player who cooped the target, if exists.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return player;\n    }\n\n    /**\n     * Get the player that will no longer be coop.\n     */\n    public SuperiorPlayer getTarget() {\n        return target;\n    }\n\n    /**\n     * Get the reason for the action.\n     */\n    public UncoopReason getUncoopReason() {\n        return uncoopReason;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    public enum UncoopReason {\n\n        PLAYER,\n        SERVER_LEAVE\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUnlockWorldEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandUnlockWorldEvent is called when a world is unlocked to an island.\n */\npublic class IslandUnlockWorldEvent extends IslandEvent implements Cancellable {\n\n    private final Dimension dimension;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island      The island that the world was unlocked for.\n     * @param environment The environment of the world that is unlocked.\n     */\n    @Deprecated\n    public IslandUnlockWorldEvent(Island island, World.Environment environment) {\n        this(island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island    The island that the world was unlocked for.\n     * @param dimension The dimension of the world that is unlocked.\n     */\n    public IslandUnlockWorldEvent(Island island, Dimension dimension) {\n        super(island);\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the environment of the world that is being unlocked.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the dimension of the world that is being unlocked.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUpgradeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Cancellable;\n\nimport java.math.BigDecimal;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * IslandCreateEvent is called when a new island is created.\n */\npublic class IslandUpgradeEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Upgrade upgrade;\n    private final UpgradeLevel upgradeLevel;\n    private final List<String> commands;\n    private final Cause cause;\n    @Nullable\n    private UpgradeCost upgradeCost;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who upgraded the island. Can be null if ran by the console.\n     * @param island         The island that was upgraded.\n     * @param upgradeName    The name of the upgrade.\n     * @param commands       The commands that will be ran upon upgrade.\n     * @param upgradeCost    The cost of the upgrade\n     * @deprecated See {@link #IslandUpgradeEvent(SuperiorPlayer, Island, Upgrade, UpgradeLevel, List, Cause, UpgradeCost)}\n     */\n    @Deprecated\n    public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, String upgradeName,\n                              List<String> commands, @Nullable UpgradeCost upgradeCost) {\n        super(island);\n        Upgrade upgrade = SuperiorSkyblockAPI.getUpgrades().getUpgrade(upgradeName);\n\n        this.superiorPlayer = superiorPlayer;\n        this.upgrade = Preconditions.checkNotNull(upgrade, \"upgrade cannot be null\");\n        this.upgradeLevel = Preconditions.checkNotNull(island.getUpgradeLevel(upgrade), \"upgradeLevel cannot be null\");\n        this.commands = new LinkedList<>(Preconditions.checkNotNull(commands, \"commands cannot be null\"));\n        this.cause = Cause.UNKONWN;\n        this.upgradeCost = upgradeCost;\n    }\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who upgraded the island.\n     *                       Can be null if ran by the console.\n     * @param island         The island that was upgraded.\n     * @param upgrade        The upgrade.\n     * @param upgradeLevel   The level that will be upgraded into.\n     * @param commands       The commands that will be running upon upgrade.\n     * @param upgradeCost    The cost of the upgrade.\n     *                       If null, there was no cost for the upgrade (For example, setupgrade command).\n     */\n    @Deprecated\n    public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Upgrade upgrade,\n                              UpgradeLevel upgradeLevel, List<String> commands, @Nullable UpgradeCost upgradeCost) {\n        this(superiorPlayer, island, upgrade, upgradeLevel, commands, Cause.UNKONWN, upgradeCost);\n    }\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who upgraded the island.\n     *                       Can be null if ran by the console.\n     * @param island         The island that was upgraded.\n     * @param upgrade        The upgrade.\n     * @param upgradeLevel   The level that will be upgraded into.\n     * @param commands       The commands that will be running upon upgrade.\n     * @param upgradeCost    The cost of the upgrade.\n     *                       If null, there was no cost for the upgrade (For example, setupgrade command).\n     * @param cause          The cause of the upgrade.\n     */\n    public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Upgrade upgrade,\n                              UpgradeLevel upgradeLevel, List<String> commands, Cause cause,\n                              @Nullable UpgradeCost upgradeCost) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.upgrade = Preconditions.checkNotNull(upgrade, \"upgrade cannot be null\");\n        this.upgradeLevel = Preconditions.checkNotNull(upgradeLevel, \"upgradeLevel cannot be null\");\n        this.commands = new LinkedList<>(Preconditions.checkNotNull(commands, \"commands cannot be null\"));\n        this.cause = Preconditions.checkNotNull(cause, \"cause cannot be null\");\n        this.upgradeCost = upgradeCost;\n    }\n\n    /**\n     * Get the player who upgraded the island.\n     * Can be null if ran by the console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the name of the upgrade.\n     */\n    public String getUpgradeName() {\n        return upgrade.getName();\n    }\n\n    /**\n     * Get the name of the upgrade.\n     */\n    public Upgrade getUpgrade() {\n        return upgrade;\n    }\n\n    /**\n     * Get the level that will be upgraded to.\n     */\n    public UpgradeLevel getUpgradeLevel() {\n        return upgradeLevel;\n    }\n\n    /**\n     * Get the commands that will be ran upon upgrade.\n     */\n    public List<String> getCommands() {\n        return commands;\n    }\n\n    /**\n     * Get the cause of this event.\n     */\n    public Cause getCause() {\n        return cause;\n    }\n\n    /**\n     * Get the upgrade cost that is used.\n     */\n    @Nullable\n    public UpgradeCost getUpgradeCost() {\n        return upgradeCost;\n    }\n\n    /**\n     * Set a new upgrade cost to be used.\n     *\n     * @param upgradeCost The new upgrade cost.\n     */\n    public void setUpgradeCost(@Nullable UpgradeCost upgradeCost) {\n        this.upgradeCost = upgradeCost;\n    }\n\n    /**\n     * Get the amount that will be withdrawn.\n     *\n     * @deprecated See getCost()\n     */\n    @Deprecated\n    public double getAmountToWithdraw() {\n        return getCost().doubleValue();\n    }\n\n    /**\n     * Set the amount that will be withdrawn.\n     *\n     * @deprecated See setCost(BigDecimal)\n     */\n    @Deprecated\n    public void setAmountToWithdraw(double amountToWithdraw) {\n        setCost(BigDecimal.valueOf(amountToWithdraw));\n    }\n\n    /**\n     * Get the amount that will be withdrawn.\n     */\n    public BigDecimal getCost() {\n        return upgradeCost == null ? BigDecimal.ZERO : upgradeCost.getCost();\n    }\n\n    /**\n     * Set the amount that will be withdrawn.\n     *\n     * @param cost The new amount to be withdrawn.\n     * @throws IllegalStateException If the upgradeCost is null. Use {@link #setUpgradeCost(UpgradeCost)} instead.\n     */\n    public void setCost(BigDecimal cost) throws IllegalStateException {\n        if (this.upgradeCost == null)\n            throw new IllegalStateException(\"Cannot set raw cost when upgradeCost is null.\");\n\n        setUpgradeCost(this.upgradeCost.clone(cost));\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n\n    public enum Cause {\n\n        /**\n         * Used when player runs '/is rankup'.\n         */\n        PLAYER_RANKUP,\n\n        /**\n         * Used when player or console runs '/is admin rankup'.\n         */\n        ADMIN_RANKUP,\n\n        /**\n         * Used when an admin or console runs '/is admin setupgrade'\n         */\n        ADMIN_SET_UPGRADE,\n\n        /**\n         * Used only for deprecated usage of the old constructors.\n         */\n        @Deprecated\n        UNKONWN\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandVisitorHomeTeleportEvent is called when a player teleports to island visitor home.\n */\npublic class IslandVisitorHomeTeleportEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final Dimension dimension;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the player teleports to.\n     * @param superiorPlayer The player who teleports to the island visitor home.\n     * @param dimension      The dimension that the player teleports to.\n     */\n    public IslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the player who teleports to the island visitor home.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the dimension that the player teleports to.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandWarpTeleportEvent is called when a player teleports to island warp.\n */\npublic class IslandWarpTeleportEvent extends IslandEvent implements Cancellable {\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IslandWarp islandWarp;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island         The island that the player teleports to.\n     * @param superiorPlayer The player who teleports to the island warp.\n     * @param islandWarp     The island warp that the player teleports to.\n     */\n    public IslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.islandWarp = islandWarp;\n    }\n\n    /**\n     * Get the player who teleports to the island warp.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the island warp that the player teleports to.\n     */\n    public IslandWarp getIslandWarp() {\n        return this.islandWarp;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorldResetEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.World;\nimport org.bukkit.event.Cancellable;\n\n/**\n * IslandWorldResetEvent is called when a world is reset of an island.\n */\npublic class IslandWorldResetEvent extends IslandEvent implements Cancellable {\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final Dimension dimension;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that reset the world of the island.\n     *                       If null, the world was reset by console.\n     * @param island         The island that the world was reset for.\n     * @param environment    The environment of the world that was reset.\n     */\n    @Deprecated\n    public IslandWorldResetEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, World.Environment environment) {\n        this(superiorPlayer, island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that reset the world of the island.\n     *                       If null, the world was reset by console.\n     * @param island         The island that the world was reset for.\n     * @param dimension      The dimension of the world that was reset.\n     */\n    public IslandWorldResetEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Dimension dimension) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n        this.dimension = dimension;\n    }\n\n    /**\n     * Get the player that reset the world of the island.\n     * If null, the world was reset by console.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the environment of the world that was reset.\n     */\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    /**\n     * Get the environment of the world that was reset.\n     */\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorthCalculatedEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandWorthCalculatedEvent is called when the worth of an island is calculated.\n */\npublic class IslandWorthCalculatedEvent extends IslandEvent {\n\n    private final BigDecimal level;\n    private final BigDecimal worth;\n    @Nullable\n    private final SuperiorPlayer player;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island The island that it's worth was calculated.\n     * @param player The player who requested the operation (may be null).\n     * @param level  The new level of the island.\n     * @param worth  The new worth value of the island.\n     */\n    public IslandWorthCalculatedEvent(Island island, @Nullable SuperiorPlayer player, BigDecimal level, BigDecimal worth) {\n        super(island);\n        this.player = player;\n        this.level = level;\n        this.worth = worth;\n    }\n\n    /**\n     * Get the player who requested the operation.\n     * Can be null if the console called the operation.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return player;\n    }\n\n    /**\n     * Get the new level of the island.\n     */\n    public BigDecimal getLevel() {\n        return level;\n    }\n\n    /**\n     * Get the new worth value of the island.\n     */\n    public BigDecimal getWorth() {\n        return worth;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorthUpdateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.math.BigDecimal;\n\n/**\n * IslandWorthUpdateEvent is called when the worth of the island is updated.\n */\npublic class IslandWorthUpdateEvent extends IslandEvent {\n\n    private final BigDecimal oldWorth;\n    private final BigDecimal oldLevel;\n    private final BigDecimal newWorth;\n    private final BigDecimal newLevel;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param island   The island that the leadership of it is transferred.\n     * @param oldWorth The old worth of the island.\n     * @param oldLevel The old level of the island.\n     * @param newWorth The new worth of the island.\n     * @param newLevel The new level of the island.\n     */\n    public IslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) {\n        super(island);\n        this.oldWorth = oldWorth;\n        this.oldLevel = oldLevel;\n        this.newWorth = newWorth;\n        this.newLevel = newLevel;\n    }\n\n    /**\n     * Get the old worth of the island.\n     */\n    public BigDecimal getOldWorth() {\n        return oldWorth;\n    }\n\n    /**\n     * Get the old level of the island.\n     */\n    public BigDecimal getOldLevel() {\n        return oldLevel;\n    }\n\n    /**\n     * Get the new worth of the island.\n     */\n    public BigDecimal getNewWorth() {\n        return newWorth;\n    }\n\n    /**\n     * Get the new level of the island.\n     */\n    public BigDecimal getNewLevel() {\n        return newLevel;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/MissionCompleteEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\n/**\n * MissionCompleteEvent is called when a player is completing a mission.\n */\npublic class MissionCompleteEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final IMissionsHolder missionsHolder;\n    private final Mission<?> mission;\n\n    private final List<ItemStack> itemRewards;\n    private final List<String> commandRewards;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who completed the mission.\n     * @param mission        The mission that was completed.\n     * @param islandMission  Flag that determines whether or not the mission is an island mission.\n     * @param itemRewards    The list of items that will be given as a reward.\n     * @param commandRewards The list of commands that will be ran as a reward.\n     */\n    @Deprecated\n    public MissionCompleteEvent(SuperiorPlayer superiorPlayer, Mission<?> mission,\n                                boolean islandMission, List<ItemStack> itemRewards, List<String> commandRewards) {\n        this(superiorPlayer, islandMission ? superiorPlayer.getIsland() : superiorPlayer, mission,\n                itemRewards, commandRewards);\n    }\n\n    public MissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder,\n                                Mission<?> mission, List<ItemStack> itemRewards, List<String> commandRewards) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.missionsHolder = missionsHolder;\n        this.mission = mission;\n        this.itemRewards = itemRewards;\n        this.commandRewards = commandRewards;\n    }\n\n    /**\n     * Get the player who completed the mission.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the mission holder that the mission was completed for.\n     */\n    public IMissionsHolder getMissionsHolder() {\n        return missionsHolder;\n    }\n\n    /**\n     * Get the mission that was completed.\n     */\n    public Mission<?> getMission() {\n        return mission;\n    }\n\n    /**\n     * Get the list of items that will be given as a reward.\n     */\n    public List<ItemStack> getItemRewards() {\n        return itemRewards;\n    }\n\n    /**\n     * Get the list of commands that will be given as a reward.\n     */\n    public List<String> getCommandRewards() {\n        return commandRewards;\n    }\n\n    /**\n     * Check whether the mission is an island mission.\n     */\n    public boolean isIslandMission() {\n        return mission.getIslandMission();\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/MissionResetEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n\n/**\n * MissionResetEvent is called when a mission is reset.\n * After the event is executed, the holder may still have the mission completed if the times the holder completed\n * the mission was above 1.\n */\npublic class MissionResetEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    @Nullable\n    private final SuperiorPlayer superiorPlayer;\n    private final IMissionsHolder missionsHolder;\n    private final Mission<?> mission;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that reset the mission.\n     *                       If null, the mission was reset by console.\n     * @param missionsHolder The holder of the mission that the mission was reset for.\n     * @param mission        The mission that was reset.\n     */\n    public MissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission<?> mission) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.missionsHolder = missionsHolder;\n        this.mission = mission;\n    }\n\n    /**\n     * Get the player who reset the mission for the holder.\n     */\n    @Nullable\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the holder of the mission that the mission was reset for.\n     */\n    public IMissionsHolder getMissionsHolder() {\n        return missionsHolder;\n    }\n\n    /**\n     * Get the mission that was reset.\n     */\n    public Mission<?> getMission() {\n        return mission;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeBorderColorEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerChangeBorderColorEvent is called when a player changes the color of the world border.\n */\npublic class PlayerChangeBorderColorEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final BorderColor borderColor;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the border color.\n     * @param borderColor    The new border color of the player.\n     */\n    public PlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.borderColor = borderColor;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new border color of the player.\n     */\n    public BorderColor getBorderColor() {\n        return borderColor;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeLanguageEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\nimport java.util.Locale;\n\n/**\n * PlayerChangeLanguageEvent is called when a player has its language changed.\n */\npublic class PlayerChangeLanguageEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final Locale language;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that changed the language.\n     * @param language       The new language of the player.\n     */\n    public PlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.language = language;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new language of the player.\n     */\n    public Locale getLanguage() {\n        return language;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeNameEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerChangeNameEvent is called when a player has his name changed.\n */\npublic class PlayerChangeNameEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final String newName;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that had his name changed.\n     * @param newName        The new name of the player.\n     */\n    public PlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.newName = newName;\n    }\n\n    /**\n     * Get the player that had his name changed.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new name of the player.\n     */\n    public String getNewName() {\n        return newName;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeRoleEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerChangeRoleEvent is called when a player has its role changed.\n */\npublic class PlayerChangeRoleEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final PlayerRole newRole;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player.\n     * @param newRole        The new role for the player.\n     */\n    public PlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newRole) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.newRole = newRole;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the new role of the player.\n     */\n    public PlayerRole getNewRole() {\n        return newRole;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerCloseMenuEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n\n/**\n * PlayerCloseMenuEvent is called when a player closes a menu.\n */\npublic class PlayerCloseMenuEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final MenuView<?, ?> openedMenuView;\n    @Nullable\n    private MenuView<?, ?> newMenuView;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that closed the menu.\n     * @param superiorMenu   The menu that was closed.\n     * @param newMenu        The new menu that will be opened.\n     *                       If null, no menu will be opened.\n     * @deprecated See {@link #PlayerCloseMenuEvent(SuperiorPlayer, MenuView, MenuView)}\n     */\n    @Deprecated\n    public PlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, ISuperiorMenu superiorMenu, @Nullable ISuperiorMenu newMenu) {\n        this(superiorPlayer, (MenuView<?, ?>) superiorMenu, newMenu);\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that closed the menu.\n     * @param openedMenuView The menu view that is opened for the player.\n     * @param newMenuView    The new menu view that will be opened.\n     *                       If null, no menu will be opened.\n     */\n    public PlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView<?, ?> openedMenuView, @Nullable MenuView<?, ?> newMenuView) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.openedMenuView = openedMenuView;\n        this.newMenuView = newMenuView;\n    }\n\n    /**\n     * Get the player that opened the menu.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the menu that was opened by the player.\n     *\n     * @deprecated See {@link #getOpenedMenuView()}\n     */\n    @Deprecated\n    public ISuperiorMenu getSuperiorMenu() {\n        return ISuperiorMenu.convertFromView(this.getOpenedMenuView());\n    }\n\n    /**\n     * Get the menu view that is opened for the player.\n     */\n    public MenuView<?, ?> getOpenedMenuView() {\n        return this.openedMenuView;\n    }\n\n    /**\n     * Get the new menu that will be opened.\n     * If null, no menu will be opened.\n     *\n     * @deprecated See {@link #getNewMenuView()}\n     */\n    @Nullable\n    @Deprecated\n    public ISuperiorMenu getNewMenu() {\n        return ISuperiorMenu.convertFromView(this.getNewMenuView());\n    }\n\n    /**\n     * Get the new menu view that will be opened.\n     * If null, no menu will be opened.\n     */\n    @Nullable\n    public MenuView<?, ?> getNewMenuView() {\n        return this.newMenuView;\n    }\n\n    /**\n     * Set the new menu that will be opened.\n     *\n     * @param newMenu The new menu that will be opened.\n     *                If null, no menu will be opened.\n     * @deprecated See {@link #setNewMenuView(MenuView)}\n     */\n    @Deprecated\n    public void setNewMenu(@Nullable ISuperiorMenu newMenu) {\n        this.setNewMenuView(newMenu);\n    }\n\n    /**\n     * Set the new menu view that will be opened.\n     *\n     * @param newMenuView The new menu that will be opened.\n     *                    If null, no menu will be opened.\n     */\n    public void setNewMenuView(@Nullable MenuView<?, ?> newMenuView) {\n        this.newMenuView = newMenuView;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerOpenMenuEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerOpenMenuEvent is called when a player opens a menu.\n */\npublic class PlayerOpenMenuEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final MenuView<?, ?> menuView;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that opened the menu.\n     * @param superiorMenu   The menu that was opened\n     * @deprecated See {@link #PlayerOpenMenuEvent(SuperiorPlayer, MenuView)}\n     */\n    @Deprecated\n    public PlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, ISuperiorMenu superiorMenu) {\n        this(superiorPlayer, (MenuView<?, ?>) superiorMenu);\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that opened the menu.\n     * @param menuView       The menu that was opened\n     */\n    public PlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView<?, ?> menuView) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n        this.menuView = menuView;\n    }\n\n    /**\n     * Get the player that opened the menu.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the menu that was opened by the player.\n     *\n     * @deprecated See {@link #getMenuView()}\n     */\n    @Deprecated\n    public ISuperiorMenu getSuperiorMenu() {\n        return ISuperiorMenu.convertFromView(menuView);\n    }\n\n    /**\n     * Get the menu view that was opened by the player.\n     */\n    public MenuView<?, ?> getMenuView() {\n        return menuView;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerReplaceEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerReplaceEvent is called when a player changes his uuid and replaced with another one.\n */\npublic class PlayerReplaceEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer oldPlayer;\n    private final SuperiorPlayer newPlayer;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param oldPlayer The old player that had his UUID changed.\n     * @param newPlayer The new player that has the new UUID.\n     */\n    public PlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.oldPlayer = oldPlayer;\n        this.newPlayer = newPlayer;\n    }\n\n    /**\n     * Get the old player that had his UUID changed.\n     */\n    public SuperiorPlayer getOldPlayer() {\n        return oldPlayer;\n    }\n\n    /**\n     * Get the new player that has the new UUID.\n     */\n    public SuperiorPlayer getNewPlayer() {\n        return newPlayer;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBlocksStackerEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleBlocksStackerEvent is called when a player toggles his blocks-stacker.\n */\npublic class PlayerToggleBlocksStackerEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the blocks-stacker.\n     */\n    public PlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the blocks-stacker.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBorderEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleBorderEvent is called when a player toggles his world border.\n */\npublic class PlayerToggleBorderEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the world border.\n     */\n    public PlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the world border.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBypassEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleBypassEvent is called when a player toggles his bypass mode.\n */\npublic class PlayerToggleBypassEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the bypass mode.\n     */\n    public PlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the bypass mode.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleFlyEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleFlyEvent is called when a player toggles his island fly.\n */\npublic class PlayerToggleFlyEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the island fly.\n     */\n    public PlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the island fly.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerTogglePanelEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerTogglePanelEvent is called when a player toggles his control panel.\n */\npublic class PlayerTogglePanelEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the control panel.\n     */\n    public PlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the control panel.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleSpyEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleSpyEvent is called when a player toggles his chat-spy.\n */\npublic class PlayerToggleSpyEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the chat-spy.\n     */\n    public PlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the chat-spy.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleTeamChatEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PlayerToggleTeamChatEvent is called when a player toggles his team chat.\n */\npublic class PlayerToggleTeamChatEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player that toggled the team chat.\n     */\n    public PlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) {\n        super(!Bukkit.isPrimaryThread());\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player that toggled the team chat.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginInitializeEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;\nimport com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PluginInitializeEvent is called when other plugins needs to register their custom data.\n */\npublic class PluginInitializeEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorSkyblock plugin;\n\n    @Nullable\n    private IslandsContainer islandsContainer;\n    @Nullable\n    private PlayersContainer playersContainer;\n\n    /**\n     * The constructor for the event.\n     * You cannot use handlers in this time, as none of them is set up.\n     *\n     * @param plugin The instance of the plugin.\n     */\n    public PluginInitializeEvent(SuperiorSkyblock plugin) {\n        this.plugin = plugin;\n    }\n\n    /**\n     * Get the instance of the plugin.\n     *\n     * @return\n     */\n    public SuperiorSkyblock getPlugin() {\n        return plugin;\n    }\n\n    /**\n     * Get the islands container that will be used for storing islands.\n     * If null, default islands container of the plugin will be used.\n     */\n    @Nullable\n    public IslandsContainer getIslandsContainer() {\n        return islandsContainer;\n    }\n\n    /**\n     * Set a new islands container to be used for storing islands.\n     *\n     * @param islandsContainer The new container.\n     */\n    public void setIslandsContainer(IslandsContainer islandsContainer) {\n        Preconditions.checkNotNull(islandsContainer, \"IslandsContainer cannot be set to null.\");\n        this.islandsContainer = islandsContainer;\n    }\n\n    /**\n     * Get the players container that will be used for storing players.\n     * If null, default players container of the plugin will be used.\n     */\n    @Nullable\n    public PlayersContainer getPlayersContainer() {\n        return playersContainer;\n    }\n\n    /**\n     * Set a new players container to be used for storing players.\n     *\n     * @param playersContainer The new container.\n     */\n    public void setPlayersContainer(PlayersContainer playersContainer) {\n        Preconditions.checkNotNull(playersContainer, \"PlayersContainer cannot be set to null.\");\n        this.playersContainer = playersContainer;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginInitializedEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PluginInitializedEvent is called when plugin enabled completely.\n */\npublic class PluginInitializedEvent extends Event {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorSkyblock plugin;\n\n    /**\n     * The constructor for the event.\n     */\n    public PluginInitializedEvent(SuperiorSkyblock plugin) {\n        this.plugin = plugin;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    public SuperiorSkyblock getPlugin() {\n        return plugin;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginLoadDataEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PluginLoadDataEvent is called right before the plugin starts to load data.\n */\npublic class PluginLoadDataEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorSkyblock plugin;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param plugin The instance of the plugin.\n     */\n    public PluginLoadDataEvent(SuperiorSkyblock plugin) {\n        this.plugin = plugin;\n    }\n\n    /**\n     * Get the instance of the plugin.\n     */\n    public SuperiorSkyblock getPlugin() {\n        return plugin;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return this.cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PostIslandCreateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\n/**\n * IslandCreateEvent is called after the island is created and the player was teleported to it.\n */\npublic class PostIslandCreateEvent extends IslandEvent {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @param island         The island object that was created.\n     */\n    public PostIslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) {\n        super(island);\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PreIslandCreateEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * PreIslandCreateEvent is called when a new island is created.\n */\npublic class PreIslandCreateEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final String islandName;\n    private boolean cancelled = false;\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @param islandName     The name that was given to the island.\n     */\n    public PreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) {\n        this.superiorPlayer = superiorPlayer;\n        this.islandName = islandName;\n    }\n\n    /**\n     * The constructor of the event.\n     *\n     * @param superiorPlayer The player who created the island.\n     * @deprecated See PreIslandCreateEvent(SuperiorPlayer, String)\n     */\n    @Deprecated\n    public PreIslandCreateEvent(SuperiorPlayer superiorPlayer) {\n        this(superiorPlayer, \"\");\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n    /**\n     * Get the player who created the island.\n     */\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    /**\n     * Get the name that was given to the island.\n     */\n    public String getIslandName() {\n        return islandName;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/events/SendMessageEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.events;\n\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\n\n/**\n * SendMessageEvent is called when a message is sent to {@link CommandSender}\n */\npublic class SendMessageEvent extends Event implements Cancellable {\n\n    private static final HandlerList handlers = new HandlerList();\n\n    private final CommandSender receiver;\n    private final String messageType;\n    private final Object[] args;\n    private IMessageComponent messageComponent;\n\n    private boolean cancelled = false;\n\n    /**\n     * The constructor for the event.\n     *\n     * @param receiver         The receiver of the message.\n     * @param messageType      The name of the message, similar to the one from lang file.\n     * @param messageComponent The message component that is being sent.\n     */\n    public SendMessageEvent(CommandSender receiver, String messageType, IMessageComponent messageComponent, Object[] args) {\n        super(!Bukkit.isPrimaryThread());\n        this.receiver = receiver;\n        this.messageType = messageType;\n        this.messageComponent = messageComponent;\n        this.args = args;\n    }\n\n    /**\n     * Get the receiver of the message.\n     */\n    public CommandSender getReceiver() {\n        return receiver;\n    }\n\n    /**\n     * Get the name of the message, similar to the one from lang file.\n     */\n    public String getMessageType() {\n        return messageType;\n    }\n\n    /**\n     * Get an argument of the message.\n     *\n     * @param index The index of the argument.\n     * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds.\n     */\n    public Object getArgument(int index) {\n        return args[index];\n    }\n\n    /**\n     * Set an argument for the message.\n     *\n     * @param index The index of the argument.\n     * @param value The value to be set.\n     * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds.\n     */\n    public void setArgument(int index, Object value) {\n        Preconditions.checkNotNull(value, \"Argument's value cannot be null.\");\n        args[index] = value;\n    }\n\n    /**\n     * Get the length of the arguments array.\n     */\n    public int getArgumentsLength() {\n        return args.length;\n    }\n\n    /**\n     * Get the message component that is sent.\n     */\n    public IMessageComponent getMessageComponent() {\n        return messageComponent;\n    }\n\n    /**\n     * Set the message component to be sent.\n     *\n     * @param messageComponent The new component to be sent.\n     */\n    public void setMessageComponent(IMessageComponent messageComponent) {\n        Preconditions.checkNotNull(messageComponent, \"Message components cannot be null.\");\n        this.messageComponent = messageComponent;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return cancelled;\n    }\n\n    @Override\n    public void setCancelled(boolean cancelled) {\n        this.cancelled = cancelled;\n    }\n\n    @Override\n    public HandlerList getHandlers() {\n        return handlers;\n    }\n\n    public static HandlerList getHandlerList() {\n        return handlers;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/BanksFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\n\npublic interface BanksFactory {\n\n    /**\n     * Create a new bank for an island.\n     *\n     * @param island   The island to create the bank for.\n     * @param original The original island bank that was created.\n     */\n    IslandBank createIslandBank(Island island, IslandBank original);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DatabaseBridgeFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic interface DatabaseBridgeFactory {\n\n    /**\n     * Create a new database bridge for an island.\n     *\n     * @param island   The island to create the database-bridge for.\n     *                 If island is null, then the database-bridge is used as a loader from the database.\n     * @param original The original database-bridge that was created.\n     */\n    DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original);\n\n    /**\n     * Create a new database bridge for a player.\n     *\n     * @param superiorPlayer The player to create the database-bridge for.\n     *                       If player is null, then the database-bridge is used as a loader from the database.\n     * @param original       The original database-bridge that was created.\n     */\n    DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original);\n\n    /**\n     * Create a new database bridge for the grid.\n     *\n     * @param gridManager The grid to create the database-bridge for.\n     *                    If grid is null, then the database-bridge is used as a loader from the database.\n     * @param original    The original database-bridge that was created.\n     */\n    DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original);\n\n    /**\n     * Create a new database bridge for the stacked-blocks manager.\n     *\n     * @param stackedBlocksManager The stacked-blocks manager to create the database-bridge for.\n     *                             If manager is null, then the database-bridge is used as a loader from the database.\n     * @param original             The original database-bridge that was created.\n     */\n    DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\n\npublic class DelegateBanksFactory implements BanksFactory {\n\n    protected final BanksFactory handle;\n\n    protected DelegateBanksFactory(BanksFactory handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public IslandBank createIslandBank(Island island, IslandBank original) {\n        return this.handle.createIslandBank(island, original);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class DelegateDatabaseBridgeFactory implements DatabaseBridgeFactory {\n\n    protected final DatabaseBridgeFactory handle;\n\n    protected DelegateDatabaseBridgeFactory(DatabaseBridgeFactory handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original) {\n        return this.handle.createIslandsDatabaseBridge(island, original);\n    }\n\n    @Override\n    public DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original) {\n        return this.handle.createPlayersDatabaseBridge(superiorPlayer, original);\n    }\n\n    @Override\n    public DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original) {\n        return this.handle.createGridDatabaseBridge(gridManager, original);\n    }\n\n    @Override\n    public DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original) {\n        return this.handle.createStackedBlocksDatabaseBridge(stackedBlocksManager, original);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\n\npublic class DelegateIslandsFactory implements IslandsFactory {\n\n    protected final IslandsFactory handle;\n\n    protected DelegateIslandsFactory(IslandsFactory handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public Island createIsland(Island original) {\n        return this.handle.createIsland(original);\n    }\n\n    @Override\n    @Deprecated\n    public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) {\n        return this.handle.createIslandCalculationAlgorithm(island);\n    }\n\n    @Override\n    @Deprecated\n    public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) {\n        return this.handle.createIslandBlocksTrackerAlgorithm(island);\n    }\n\n    @Override\n    @Deprecated\n    public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) {\n        return this.handle.createIslandEntitiesTrackerAlgorithm(island);\n    }\n\n    @Override\n    public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original) {\n        return this.handle.createIslandCalculationAlgorithm(island, original);\n    }\n\n    @Override\n    public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original) {\n        return this.handle.createIslandBlocksTrackerAlgorithm(island, original);\n    }\n\n    @Override\n    public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original) {\n        return this.handle.createIslandEntitiesTrackerAlgorithm(island, original);\n    }\n\n    @Override\n    public PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original) {\n        return this.handle.createPersistentDataContainer(island, original);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class DelegatePlayersFactory implements PlayersFactory {\n\n    protected final PlayersFactory handle;\n\n    protected DelegatePlayersFactory(PlayersFactory handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public SuperiorPlayer createPlayer(SuperiorPlayer original) {\n        return this.handle.createPlayer(original);\n    }\n\n    @Override\n    @Deprecated\n    public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) {\n        return this.handle.createPlayerTeleportAlgorithm(superiorPlayer);\n    }\n\n    @Override\n    public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original) {\n        return this.handle.createPlayerTeleportAlgorithm(superiorPlayer, original);\n    }\n\n    @Override\n    public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original) {\n        return this.handle.createPersistentDataContainer(superiorPlayer, original);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/IslandsFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\n\npublic interface IslandsFactory {\n\n    /**\n     * Create a new island.\n     *\n     * @param original The original island that was created.\n     */\n    Island createIsland(Island original);\n\n    /**\n     * Create a calculation algorithm for an island.\n     *\n     * @param island The island to set the algorithm to.\n     * @deprecated Use {@link #createIslandCalculationAlgorithm(Island, IslandCalculationAlgorithm)}\n     */\n    @Deprecated\n    default IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) {\n        throw new UnsupportedOperationException(\"Unsupported operation.\");\n    }\n\n    /**\n     * Create a blocks-tracking algorithm for an island.\n     *\n     * @param island The island to set the algorithm to.\n     * @deprecated Use {@link #createIslandBlocksTrackerAlgorithm(Island, IslandBlocksTrackerAlgorithm)}\n     */\n    @Deprecated\n    default IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) {\n        throw new UnsupportedOperationException(\"Unsupported operation.\");\n    }\n\n    /**\n     * Create an entities-tracking algorithm for an island.\n     *\n     * @param island The island to set the algorithm to.\n     * @deprecated Use {@link #createIslandEntitiesTrackerAlgorithm(Island, IslandEntitiesTrackerAlgorithm)}\n     */\n    @Deprecated\n    default IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) {\n        throw new UnsupportedOperationException(\"Unsupported operation.\");\n    }\n\n    /**\n     * Create a calculation algorithm for an island.\n     *\n     * @param island   The island to set the algorithm to.\n     * @param original The original calculation algorithm.\n     */\n    IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original);\n\n    /**\n     * Create a blocks-tracking algorithm for an island.\n     *\n     * @param island   The island to set the algorithm to.\n     * @param original The original blocks tracking algorithm.\n     */\n    IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original);\n\n    /**\n     * Create an entities-tracking algorithm for an island.\n     *\n     * @param island   The island to set the algorithm to.\n     * @param original The original entities tracking algorithm.\n     */\n    IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original);\n\n    /**\n     * Create a new persistent data container for an island.\n     *\n     * @param island   The island to create the container for.\n     * @param original The original persistent data container that was created.\n     */\n    PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/PlayersFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.factory;\n\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic interface PlayersFactory {\n\n    /**\n     * Create a new player wrapper.\n     *\n     * @param original The original player wrapper that was created.\n     */\n    SuperiorPlayer createPlayer(SuperiorPlayer original);\n\n    /**\n     * Create a teleport algorithm for a player.\n     *\n     * @param superiorPlayer The player to set the algorithm to.\n     * @deprecated Use {@link #createPlayerTeleportAlgorithm(SuperiorPlayer, PlayerTeleportAlgorithm)}\n     */\n    @Deprecated\n    default PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) {\n        throw new UnsupportedOperationException(\"Unsupported operation.\");\n    }\n\n    /**\n     * Create a teleport algorithm for a player.\n     *\n     * @param superiorPlayer The player to set the algorithm to.\n     * @param original       The original teleport algorithm.\n     */\n    PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original);\n\n    /**\n     * Create a new persistent data container for a player.\n     *\n     * @param superiorPlayer The player to create the container for.\n     * @param original       The original persistent data container that was created.\n     */\n    PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/BlockValuesManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigDecimal;\n\npublic interface BlockValuesManager {\n\n    /**\n     * Get the worth value of a key.\n     *\n     * @param key The key to check.\n     * @return The worth value.\n     */\n    BigDecimal getBlockWorth(Key key);\n\n    /**\n     * Get the level value of a key.\n     *\n     * @param key The key to check.\n     * @return The level value.\n     */\n    BigDecimal getBlockLevel(Key key);\n\n    /**\n     * Get the exact key that is used in the config.\n     *\n     * @param key The key to check.\n     * @return The key from the config.\n     */\n    Key getBlockKey(Key key);\n\n    /**\n     * Register a value for a key.\n     *\n     * @param key        The key to set custom value of.\n     * @param worthValue The custom worth value of the key.\n     * @param levelValue The custom level value of the key.\n     */\n    void registerCustomKey(Key key, @Nullable BigDecimal worthValue, @Nullable BigDecimal levelValue);\n\n    /**\n     * Register a custom key parser.\n     *\n     * @param customKeyParser The custom key parser.\n     * @param blockTypes      All the block types you want to check.\n     */\n    void registerKeyParser(CustomKeyParser customKeyParser, Key... blockTypes);\n\n    enum SyncWorthStatus {\n\n        NONE,\n        BUY,\n        SELL;\n\n        public static SyncWorthStatus of(String name) {\n            try {\n                return valueOf(name);\n            } catch (Exception ex) {\n                return NONE;\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/CommandsManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.List;\n\npublic interface CommandsManager {\n\n    /**\n     * Register a sub-command.\n     *\n     * @param superiorCommand The sub command to register.\n     */\n    void registerCommand(SuperiorCommand superiorCommand);\n\n    /**\n     * Unregister a sub-command.\n     *\n     * @param superiorCommand The sub command to register.\n     */\n    void unregisterCommand(SuperiorCommand superiorCommand);\n\n    /**\n     * Register a sub-command to the admin command.\n     *\n     * @param superiorCommand The sub command to unregister.\n     */\n    void registerAdminCommand(SuperiorCommand superiorCommand);\n\n    /**\n     * Unregister a sub-command from the admin command.\n     *\n     * @param superiorCommand The sub command to unregister.\n     */\n    void unregisterAdminCommand(SuperiorCommand superiorCommand);\n\n    /**\n     * Get all the registered sub-commands.\n     */\n    List<SuperiorCommand> getSubCommands();\n\n    /**\n     * Get all the registered sub-commands.\n     *\n     * @param includeDisabled Whether to include disabled commands.\n     */\n    List<SuperiorCommand> getSubCommands(boolean includeDisabled);\n\n    /**\n     * Get a sub command by its label.\n     *\n     * @param commandLabel The label of the sub command.\n     * @return The sub command if exists or null.\n     */\n    @Nullable\n    SuperiorCommand getCommand(String commandLabel);\n\n    /**\n     * Get all the registered admin sub-commands.\n     */\n    List<SuperiorCommand> getAdminSubCommands();\n\n    /**\n     * Get an admin sub command by its label.\n     *\n     * @param commandLabel The label of the sub command.\n     * @return The sub command if exists or null.\n     */\n    @Nullable\n    SuperiorCommand getAdminCommand(String commandLabel);\n\n    /**\n     * Dispatch a sub command.\n     * If the sub command does not exist, Bukkit#dispatchCommand is executed.\n     *\n     * @param sender     The sender to dispatch the command.\n     * @param subCommand The sub-command to dispatch.\n     */\n    void dispatchSubCommand(CommandSender sender, String subCommand);\n\n    /**\n     * Dispatch a sub command.\n     * If the sub command does not exist, Bukkit#dispatchCommand is executed.\n     *\n     * @param sender     The sender to dispatch the command.\n     * @param subCommand The sub-command to dispatch.\n     * @param args       The argument to use for the command.\n     */\n    void dispatchSubCommand(CommandSender sender, String subCommand, @Nullable String args);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\nimport com.bgsoftware.superiorskyblock.api.factory.BanksFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.IslandsFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.PlayersFactory;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Location;\nimport org.bukkit.Sound;\nimport org.bukkit.World;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\n\npublic interface FactoriesManager {\n\n    /**\n     * Register a custom islands factory.\n     *\n     * @param islandsFactory The new factory to set.\n     *                       If set to null, the default factory will be used.\n     */\n    void registerIslandsFactory(@Nullable IslandsFactory islandsFactory);\n\n    /**\n     * Get the current islands factory.\n     */\n    IslandsFactory getIslandsFactory();\n\n    /**\n     * Register a custom players factory.\n     *\n     * @param playersFactory The new factory to set.\n     *                       If set to null, the default factory will be used.\n     */\n    void registerPlayersFactory(@Nullable PlayersFactory playersFactory);\n\n    /**\n     * Get the current players factory.\n     */\n    PlayersFactory getPlayersFactory();\n\n    /**\n     * Register a custom banks factory.\n     *\n     * @param banksFactory The new factory to set.\n     *                     If set to null, the default factory will be used.\n     */\n    void registerBanksFactory(@Nullable BanksFactory banksFactory);\n\n    /**\n     * Get the current banks factory.\n     */\n    BanksFactory getBanksFactory();\n\n    /**\n     * Register a custom database-bridge factory.\n     *\n     * @param databaseBridgeFactory The new factory to set.\n     *                              If set to null, the default factory will be used.\n     */\n    void registerDatabaseBridgeFactory(@Nullable DatabaseBridgeFactory databaseBridgeFactory);\n\n    /**\n     * Get the database bridge factory.\n     */\n    DatabaseBridgeFactory getDatabaseBridgeFactory();\n\n    /**\n     * Create a new Island object.\n     * Warning: This island is not saved into the database unless inserting it manually!\n     *\n     * @param owner      The owner of the island.\n     * @param uuid       The uuid of the island.\n     * @param center     The location of the island.\n     * @param islandName The name of the island.\n     * @param schemName  The schematic used to create the island.\n     */\n    Island createIsland(@Nullable SuperiorPlayer owner, UUID uuid, Location center, String islandName, String schemName);\n\n    /**\n     * Create a new builder for a {@link Island} object.\n     */\n    Island.Builder createIslandBuilder();\n\n    /**\n     * Create a new SuperiorPlayer object.\n     * Warning: This player is not saved into the database unless inserting it manually!\n     *\n     * @param playerUUID The uuid of the player.\n     */\n    SuperiorPlayer createPlayer(UUID playerUUID);\n\n    /**\n     * Create a new builder for a {@link SuperiorPlayer} object.\n     */\n    SuperiorPlayer.Builder createPlayerBuilder();\n\n    /**\n     * Create a {@link BlockOffset} object from given offsets.\n     *\n     * @param offsetX The x-coords offset.\n     * @param offsetY The y-coords offset.\n     * @param offsetZ The z-coords offset.\n     */\n    BlockOffset createBlockOffset(int offsetX, int offsetY, int offsetZ);\n\n    /**\n     * Create a {@link BlockPosition} object from given block coords.\n     *\n     * @param world  The name of the world of the block.\n     * @param blockX The x-coords of the block.\n     * @param blockY The y-coords of the block.\n     * @param blockZ The z-coords of the block.\n     * @deprecated See {@link #createBlockPosition(int, int, int)}\n     */\n    @Deprecated\n    BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ);\n\n    /**\n     * Create a {@link BlockPosition} object from given block coords.\n     *\n     * @param blockX The x-coords of the block.\n     * @param blockY The y-coords of the block.\n     * @param blockZ The z-coords of the block.\n     */\n    BlockPosition createBlockPosition(int blockX, int blockY, int blockZ);\n\n    /**\n     * Create a {@link BlockPosition} object from a location.\n     *\n     * @param location The location.\n     */\n    BlockPosition createBlockPosition(Location location);\n\n    /**\n     * Create a {@link WorldPosition} object from given world coords.\n     *\n     * @param x The x-coords of the position.\n     * @param y The y-coords of the position.\n     * @param z The z-coords of the position.\n     */\n    WorldPosition createWorldPosition(double x, double y, double z);\n\n    /**\n     * Create a {@link WorldPosition} object from given world coords.\n     *\n     * @param x     The x-coords of the position.\n     * @param y     The y-coords of the position.\n     * @param z     The z-coords of the position.\n     * @param yaw   The yaw of the position.\n     * @param pitch The pitch of the position.\n     */\n    WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch);\n\n    /**\n     * Create a {@link WorldPosition} object from a location.\n     *\n     * @param location The location.\n     */\n    WorldPosition createWorldPosition(Location location);\n\n    /**\n     * Create a new bank transaction.\n     *\n     * @param player        The player that made the transaction.\n     *                      Can be null if console made it.\n     * @param action        The transaction action\n     * @param position      The position of the transaction.\n     * @param time          The time the transaction was made.\n     * @param failureReason The reason of failure for this transaction, if exists.\n     *                      On successful transactions, empty string should be set.\n     * @param amount        The amount of money that was transferred in this transaction.\n     */\n    BankTransaction createTransaction(@Nullable UUID player, BankAction action, int position,\n                                      long time, String failureReason, BigDecimal amount);\n\n    /**\n     * Create a new world info.\n     *\n     * @param worldName The name of the world.\n     * @param dimension The dimension of the world.\n     */\n    WorldInfo createWorldInfo(String worldName, Dimension dimension);\n\n    /**\n     * Create a new game sound instance.\n     *\n     * @param sound  The sound to play.\n     * @param volume The volume to play the sound.\n     * @param pitch  The pitch to play the sound.\n     */\n    GameSound createGameSound(Sound sound, float volume, float pitch);\n\n    /**\n     * Create a new builder for a {@link SchematicOptions} object.\n     *\n     * @param schematicName The name of the schematic to create.\n     */\n    SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\n\nimport java.math.BigDecimal;\nimport java.util.List;\nimport java.util.UUID;\n\npublic interface GridManager extends IDatabaseBridgeHolder {\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonus          A starting worth for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     */\n    void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName);\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonus          A starting worth for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     * @param offset         Should the island have an offset for it's values? If disabled, the bonus will be given.\n     */\n    void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName, boolean offset);\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonusWorth     A starting worth for the island.\n     * @param bonusLevel     A starting level for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     * @param offset         Should the island have an offset for it's values? If disabled, the bonus will be given.\n     */\n    void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel,\n                      Biome biome, String islandName, boolean offset);\n\n    /**\n     * Create a new island.\n     *\n     * @param superiorPlayer The new owner for the island.\n     * @param schemName      The schematic that should be used.\n     * @param bonusWorth     A starting worth for the island.\n     * @param bonusLevel     A starting level for the island.\n     * @param biome          A starting biome for the island.\n     * @param islandName     The name of the new island.\n     * @param offset         Should the island have an offset for it's values? If disabled, the bonus will be given.\n     * @param spawnOffset    The offset to teleport the player to from the center of the schematic\n     */\n    void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel,\n                      Biome biome, String islandName, boolean offset, @Nullable BlockOffset spawnOffset);\n\n    /**\n     * Create a new island.\n     *\n     * @param builder The builder for the island.\n     * @param biome   A starting biome for the island.\n     * @param offset  Should the island have an offset for its values? If disabled, the bonus will be given.\n     */\n    void createIsland(Island.Builder builder, Biome biome, boolean offset);\n\n    /**\n     * Create a new island.\n     *\n     * @param builder     The builder for the island.\n     * @param biome       A starting biome for the island.\n     * @param offset      Should the island have an offset for its values? If disabled, the bonus will be given.\n     * @param spawnOffset The offset to teleport the player to from the center of the schematic\n     */\n    void createIsland(Island.Builder builder, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset);\n\n    /**\n     * Set the creation algorithm of islands.\n     *\n     * @param islandCreationAlgorithm The new algorithm to set.\n     *                                If null, the default one will be used.\n     */\n    void setIslandCreationAlgorithm(@Nullable IslandCreationAlgorithm islandCreationAlgorithm);\n\n    /**\n     * Get the currently used island creation algorithm.\n     */\n    IslandCreationAlgorithm getIslandCreationAlgorithm();\n\n    /**\n     * Checks if a player has an active request for creating an island.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Start the island preview task for a specific player.\n     *\n     * @param superiorPlayer The player to start preview for.\n     * @param schemName      The schematic to preview.\n     * @param islandName     The requested island name by the player.\n     */\n    void startIslandPreview(SuperiorPlayer superiorPlayer, String schemName, String islandName);\n\n    /**\n     * Cancel the island preview for a specific player.\n     *\n     * @param superiorPlayer The player to cancel preview for.\n     */\n    void cancelIslandPreview(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Cancel all active island previews.\n     */\n    void cancelAllIslandPreviews();\n\n    /**\n     * Check if a player has an ongoing island preview task.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    @Nullable\n    IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Delete an island.\n     *\n     * @param island The island to delete.\n     */\n    void deleteIsland(Island island);\n\n    /**\n     * Get the island of a specific player.\n     *\n     * @param superiorPlayer The player to check.\n     * @return The island of the player. May be null.\n     * @deprecated See {@link SuperiorPlayer#getIsland()}\n     */\n    @Nullable\n    @Deprecated\n    Island getIsland(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the island in a specific position from one of the top lists.\n     * Positions are starting from 0.\n     *\n     * @param position    The position to check.\n     * @param sortingType The sorting type that should be considered.\n     * @return The island in that position. May be null.\n     */\n    @Nullable\n    Island getIsland(int position, SortingType sortingType);\n\n    /**\n     * Get the position of an island.\n     * Positions are starting from 0.\n     *\n     * @param island      The island to check.\n     * @param sortingType The sorting type that should be considered.\n     * @return The position of the island.\n     */\n    int getIslandPosition(Island island, SortingType sortingType);\n\n    /**\n     * Get an island by it's owner uuid.\n     *\n     * @param uuid The uuid of the owner.\n     * @return The island of the owner. May be null.\n     * @deprecated See {@link SuperiorPlayer#getIsland()}\n     */\n    @Nullable\n    @Deprecated\n    Island getIsland(UUID uuid);\n\n    /**\n     * Get an island by it's uuid.\n     *\n     * @param uuid The uuid of the island.\n     * @return The island with that UUID. May be null.\n     */\n    @Nullable\n    Island getIslandByUUID(UUID uuid);\n\n    /**\n     * Get an island by it's name.\n     *\n     * @param islandName The name to check.\n     * @return The island with that name. May be null.\n     */\n    @Nullable\n    Island getIsland(String islandName);\n\n    /**\n     * Get an island at an exact position in the world.\n     *\n     * @param location The position to check.\n     * @return The island at that position. May be null.\n     */\n    @Nullable\n    Island getIslandAt(@Nullable Location location);\n\n    /**\n     * Get an island from a chunk.\n     *\n     * @param chunk The chunk to check.\n     * @return The island at that position. May be null.\n     * @deprecated See {@link #getIslandsAt(Chunk)}\n     */\n    @Nullable\n    @Deprecated\n    Island getIslandAt(@Nullable Chunk chunk);\n\n    /**\n     * Get all the islands from a chunk.\n     *\n     * @param chunk The chunk to check.\n     * @return The islands at that position.\n     */\n    @Nullable\n    List<Island> getIslandsAt(@Nullable Chunk chunk);\n\n    /**\n     * Transfer an island's leadership to another owner.\n     *\n     * @param oldOwner The old owner of the island.\n     * @param newOwner The new owner of the island.\n     * @deprecated Does nothing. See {@link Island#transferIsland(SuperiorPlayer)}\n     */\n    @Deprecated\n    void transferIsland(UUID oldOwner, UUID newOwner);\n\n    /**\n     * Get the amount of islands.\n     */\n    int getSize();\n\n    /**\n     * Sort the islands.\n     *\n     * @param sortingType The sorting type to use.\n     */\n    void sortIslands(SortingType sortingType);\n\n    /**\n     * Sort the islands.\n     *\n     * @param sortingType The sorting type to use.\n     * @param onFinish    Callback runnable.\n     */\n    void sortIslands(SortingType sortingType, @Nullable Runnable onFinish);\n\n    /**\n     * Get the spawn island object.\n     */\n    Island getSpawnIsland();\n\n    /**\n     * Get the world of an island by the dimension.\n     * If the dimension is disabled in config, null will be returned.\n     *\n     * @param dimension The world dimension.\n     * @param island    The island to check.\n     */\n    @Nullable\n    World getIslandsWorld(Island island, Dimension dimension);\n\n    /**\n     * Get the dimension of an islands world.\n     * If the island is not an islands world, null will be returned.\n     *\n     * @param world The world to check.\n     */\n    @Nullable\n    Dimension getIslandsWorldDimension(World world);\n\n    /**\n     * Get the {@link WorldInfo} of the world of an island by the dimension.\n     * The world might not be loaded at the time of calling this method.\n     *\n     * @param island    The island to check.\n     * @param dimension The world dimension.\n     * @return The world info for the given dimension, or null if this dimension is not enabled.\n     */\n    @Nullable\n    WorldInfo getIslandsWorldInfo(Island island, Dimension dimension);\n\n    /**\n     * Get the {@link WorldInfo} of the world of an island by its name.\n     * The world might not be loaded at the time of calling this method.\n     *\n     * @param island    The island to check.\n     * @param worldName The name of the world.\n     * @return The world info for the given name, or null if this name is not an islands world.\n     */\n    @Nullable\n    WorldInfo getIslandsWorldInfo(Island island, String worldName);\n\n    /**\n     * Checks if the given world is an islands world.\n     * Can be the normal world, the nether world (if enabled in config) or the end world (if enabled in config)\n     */\n    boolean isIslandsWorld(World world);\n\n    /**\n     * Register a world as a islands world.\n     * This will add all protections to that world, however - no islands will by physically there.\n     *\n     * @param world The world to register as an islands world.\n     * @throws IllegalArgumentException if the world couldn't be registered\n     */\n    void registerIslandWorld(World world);\n\n    /**\n     * Get all registered worlds.\n     */\n    List<World> getRegisteredWorlds();\n\n    /**\n     * Get all the islands ordered by a specific sorting type.\n     *\n     * @param sortingType The sorting type to order the list by.\n     * @return A list of uuids of the island owners.\n     * @deprecated See {@link #getIslands(SortingType)}\n     */\n    @Deprecated\n    List<UUID> getAllIslands(SortingType sortingType);\n\n    /**\n     * Get all the islands unordered.\n     */\n    List<Island> getIslands();\n\n    /**\n     * Get all the islands ordered by a specific sorting type.\n     *\n     * @param sortingType The sorting type to order the list by.\n     * @return A list of uuids of the island owners.\n     */\n    List<Island> getIslands(SortingType sortingType);\n\n    /**\n     * Get the block amount of a specific block.\n     *\n     * @param block The block to check.\n     * @deprecated see {@link StackedBlocksManager}\n     */\n    @Deprecated\n    int getBlockAmount(Block block);\n\n    /**\n     * Get the block amount of a specific location.\n     *\n     * @param location The location to check.\n     * @deprecated see {@link StackedBlocksManager}\n     */\n    @Deprecated\n    int getBlockAmount(Location location);\n\n    /**\n     * Set a new amount for a specific block.\n     *\n     * @param block  The block to set the amount to.\n     * @param amount The new amount of the block.\n     * @deprecated see {@link StackedBlocksManager}\n     */\n    @Deprecated\n    void setBlockAmount(Block block, int amount);\n\n    /**\n     * Get all the stacked blocks on the server.\n     *\n     * @deprecated see {@link StackedBlocksManager}\n     */\n    @Deprecated\n    List<Location> getStackedBlocks();\n\n    /**\n     * Calculate the worth of all the islands on the server.\n     */\n    void calcAllIslands();\n\n    /**\n     * Calculate the worth of all the islands on the server.\n     *\n     * @param callback Runnable that will be ran when process is finished.\n     */\n    void calcAllIslands(@Nullable Runnable callback);\n\n    /**\n     * Make the island to be deleted when server stops.\n     *\n     * @param island The island to delete.\n     */\n    void addIslandToPurge(Island island);\n\n    /**\n     * Remove the island from being deleted when server stops.\n     *\n     * @param island The island to keep.\n     */\n    void removeIslandFromPurge(Island island);\n\n    /**\n     * Check if the island will be deleted when the server stops?\n     */\n    boolean isIslandPurge(Island island);\n\n    /**\n     * Get all the islands that will be deleted when the server stops.\n     */\n    List<Island> getIslandsToPurge();\n\n    /**\n     * Add a new sorting type to the registry of islands.\n     *\n     * @param sortingType The new sorting type to register.\n     */\n    void registerSortingType(SortingType sortingType);\n\n    /**\n     * Get the total worth of all the islands.\n     * This value is updated every minute, so it might not be 100% accurate.\n     */\n    BigDecimal getTotalWorth();\n\n    /**\n     * Get the total level of all the islands.\n     * This value is updated every minute, so it might not be 100% accurate.\n     */\n    BigDecimal getTotalLevel();\n\n    /**\n     * Get the location of the last island that was generated.\n     * The location's getWorld will always return null.\n     *\n     * @deprecated See {@link #getLastIslandPosition()}\n     */\n    @Deprecated\n    Location getLastIslandLocation();\n\n    /**\n     * Set the location of the last island.\n     * Warning: Do not use this method unless you know what you're doing\n     *\n     * @param location The location to set.\n     * @deprecated See {@link #setLastIslandPosition(BlockPosition)}\n     */\n    @Deprecated\n    void setLastIslandLocation(Location location);\n\n    /**\n     * Get the position of the last island that was generated.\n     */\n    BlockPosition getLastIslandPosition();\n\n    /**\n     * Set the position of the last island.\n     * Warning: Do not use this method unless you know what you're doing\n     *\n     * @param blockPosition The position to set.\n     */\n    void setLastIslandPosition(BlockPosition blockPosition);\n\n    /**\n     * Get the islands container.\n     */\n    IslandsContainer getIslandsContainer();\n\n    /**\n     * Set a new islands container.\n     *\n     * @param islandsContainer The new islands container to set.\n     */\n    void setIslandsContainer(IslandsContainer islandsContainer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/KeysManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic interface KeysManager {\n\n    /**\n     * Get the key of an entity type.\n     *\n     * @param entityType The entity type to check.\n     */\n    Key getKey(EntityType entityType);\n\n    /**\n     * Get the key of an entity type.\n     *\n     * @param entityTypeName The name of the entity type to create key for.\n     */\n    Key getEntityTypeKey(String entityTypeName);\n\n    /**\n     * Get the key of an entity.\n     *\n     * @param entity The entity to check.\n     */\n    Key getKey(Entity entity);\n\n    /**\n     * Get the key of a block.\n     *\n     * @param block The block to check.\n     */\n    Key getKey(Block block);\n\n    /**\n     * Get the key of a block-state.\n     *\n     * @param blockState The block-state to check.\n     */\n    Key getKey(BlockState blockState);\n\n    /**\n     * Get the key of an item-stack.\n     *\n     * @param itemStack The item-stack to check.\n     */\n    Key getKey(ItemStack itemStack);\n\n    /**\n     * Get the key of a material and data.\n     *\n     * @param material The material to check.\n     * @param data     The data to check.\n     */\n    Key getKey(Material material, short data);\n\n    /**\n     * Get the key of a material.\n     *\n     * @param material The material to create key for.\n     */\n    Key getKey(Material material);\n\n    /**\n     * Get the key of a material and data, split by ':' (optionally).\n     *\n     * @param type The combined material-data pair to create key for.\n     */\n    Key getMaterialAndDataKey(String type);\n\n    /**\n     * Get the key of a spawner block with specific entity type.\n     *\n     * @param entityType The entity type of the spawner to create key for.\n     */\n    Key getSpawnerKey(EntityType entityType);\n\n    /**\n     * Get the key of a spawner block with specific entity type.\n     *\n     * @param entityTypeName The name of the entity type of the spawner to create key for.\n     */\n    Key getSpawnerKey(String entityTypeName);\n\n    /**\n     * Get the key of a string.\n     *\n     * @param key The string to check.\n     */\n    Key getKey(String key);\n\n    /**\n     * Get the key of a global-key and a sub-key.\n     *\n     * @param globalKey The global key\n     * @param subKey    The sub key\n     */\n    Key getKey(String globalKey, String subKey);\n\n    /**\n     * Create a new empty {@link KeySet} instance.\n     */\n    KeySet createKeySet(Supplier<Set<String>> setCreator);\n\n    /**\n     * Create a new {@link KeySet} instance from the given collection.\n     * If the provided collection is also a {@link KeySet}, the exact same instance of that set is returned.\n     * Otherwise, the returned {@link KeySet} is a copy of that collection.\n     *\n     * @param collection The collection to create {@link KeySet} from.\n     */\n    KeySet createKeySet(Supplier<Set<String>> setCreator, Collection<Key> collection);\n\n    /**\n     * Create a new empty {@link KeyMap <V>} instance.\n     */\n    <V> KeyMap<V> createKeyMap(Supplier<Map<String, V>> mapCreator);\n\n    /**\n     * Create a new {@link KeyMap<V>} instance from the given map.\n     * If the provided map is also a {@link KeyMap<V>}, the exact same instance of the map is returned.\n     * Otherwise, the returned {@link KeyMap<V>} is a copy of that map.\n     *\n     * @param map The map to create {@link KeySet} from.\n     */\n    <V> KeyMap<V> createKeyMap(Supplier<Map<String, V>> mapCreator, Map<Key, V> map);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuCommands;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.Map;\n\npublic interface MenusManager {\n\n    /**\n     * Open the bank-logs menu.\n     * Used to display all logs of bank transactions.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to display bank logs for.\n     */\n    void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the bank-logs menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshBankLogs(Island island);\n\n    /**\n     * Open the biomes-menu.\n     * Used to display and choose biomes for the island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to change biomes for.\n     */\n    void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island biomes menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openBiomes(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandBiomesMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the border-color menu.\n     * Used to change the color of the world border for a player.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the border color menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openBorderColor(SuperiorPlayer, ISuperiorMenu)}\n     */\n    @Deprecated\n    void openBorderColorMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the confirm-ban menu.\n     * Used to confirm a ban of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to ban the player from.\n     * @param bannedPlayer The player that will be banned.\n     */\n    void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer);\n\n    /**\n     * Open the confirm-disband menu.\n     * Used to confirm disband of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to disband.\n     */\n    void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the confirm disband menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openConfirmDisband(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openConfirmDisbandMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the confirm-kick menu.\n     * Used to confirm a kick of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to kick the player from.\n     * @param kickedPlayer The player that will be kicked.\n     */\n    void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer);\n\n    /**\n     * Open the confirm-leave menu.\n     * Used to confirm leaving of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the confirm-transfer menu.\n     * Used to confirm the transfer of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to ban the player from.\n     * @param newOwner The player that will be banned.\n     */\n    void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner);\n\n    /**\n     * Open the control-panel menu.\n     * Used when opening the control panel of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the control panel of.\n     */\n    void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island panel menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated {@link #openControlPanel(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandPanelMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the coops menu.\n     * Used when opening the coops menu of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get coop-members from.\n     */\n    void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the coops-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshCoops(Island island);\n\n    /**\n     * Open the block-counts menu.\n     * Used when opening the counts menu of an island (using /is counts, for example)\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get block counts from.\n     */\n    void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island counts menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the block counts from.\n     * @deprecated see {@link #openCounts(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandCountsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the counts-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshCounts(Island island);\n\n    /**\n     * Open the global-warps menu.\n     * Used when running the /is warp command.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the global warps menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openGlobalWarps(SuperiorPlayer, ISuperiorMenu)}\n     */\n    @Deprecated\n    void openGlobalWarpsMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Refresh the global-warps menu.\n     */\n    void refreshGlobalWarps();\n\n    /**\n     * Open the island-bank menu.\n     * Used when running the /is bank command.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the bank for.\n     */\n    void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the island bank menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandBank(Island island);\n\n    /**\n     * Open the banned-players menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to check the members of.\n     */\n    void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the banned-players menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandBannedPlayers(Island island);\n\n    /**\n     * Open the island-chests menu.\n     * Used to open the shared chests menu of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the shared-chests menu for.\n     */\n    void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the island-chests menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandChest(Island island);\n\n    /**\n     * Open the islands-creation menu.\n     * Used when creating a new island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandName   The desired name of the new island.\n     */\n    void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName);\n\n    /**\n     * Open the island creation menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param islandName     The name to give the island if the player creates a new island.\n     * @deprecated see {@link #openIslandCreation(SuperiorPlayer, ISuperiorMenu, String)}\n     */\n    @Deprecated\n    void openIslandCreationMenu(SuperiorPlayer superiorPlayer, String islandName);\n\n    /**\n     * Open the rate-menu.\n     * Used when giving a rating for an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to give a rating.\n     */\n    void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island rate menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The target island to give the rating.\n     * @deprecated see {@link #openIslandRate(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandRateMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Open the ratings-menu.\n     * Used when checking given ratings of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get ratings from.\n     */\n    void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island ratings menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the ratings from.\n     * @deprecated see {@link #openIslandRatings(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandRatingsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the ratings-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandRatings(Island island);\n\n    /**\n     * Open the member-manage menu.\n     * Used when managing an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandMember The island member to manage.\n     */\n    void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember);\n\n    /**\n     * Open the member manage menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param targetPlayer   The target player to manage.\n     * @deprecated see {@link #openMemberManage(SuperiorPlayer, ISuperiorMenu, SuperiorPlayer)}\n     */\n    @Deprecated\n    void openMemberManageMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer);\n\n    /**\n     * Destroy the member-manage menus for a specific island member.\n     *\n     * @param islandMember The island member to close menus of.\n     */\n    void destroyMemberManage(SuperiorPlayer islandMember);\n\n    /**\n     * Used to open the member-role menu.\n     * Used when changing a role of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandMember The island member to change role for.\n     */\n    void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember);\n\n    /**\n     * Open the member role menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param targetPlayer   The target player to manage their role.\n     * @deprecated see {@link #openMemberRole(SuperiorPlayer, ISuperiorMenu, SuperiorPlayer)}\n     */\n    @Deprecated\n    void openMemberRoleMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer);\n\n    /**\n     * Destroy the member-role menus for a specific island member.\n     *\n     * @param islandMember The island member to close menus of.\n     */\n    void destroyMemberRole(SuperiorPlayer islandMember);\n\n    /**\n     * Open the members-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to check the members of.\n     */\n    void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island members menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the members from.\n     * @deprecated {@link #openMembers(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandMembersMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the members-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshMembers(Island island);\n\n    /**\n     * Open the missions-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the main island missions menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openMissions(SuperiorPlayer, ISuperiorMenu)}\n     */\n    @Deprecated\n    void openIslandMainMissionsMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the missions-menu of a specific category.\n     *\n     * @param targetPlayer    The player to open the menu for.\n     * @param previousMenu    The previous menu that was opened, if exists.\n     * @param missionCategory The category to get missions from.\n     */\n    void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory);\n\n    /**\n     * Open the island missions menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param islandMissions Should island missions be displayed or player missions?\n     * @deprecated Unused menu.\n     */\n    @Deprecated\n    void openIslandMissionsMenu(SuperiorPlayer superiorPlayer, boolean islandMissions);\n\n    /**\n     * Refresh the missions-menu for a specific category.\n     *\n     * @param missionCategory The category to refresh the menus for.\n     */\n    void refreshMissionsCategory(MissionCategory missionCategory);\n\n    /**\n     * Open the permissions-menu.\n     * Used when changing island-permissions of a player on an island.\n     *\n     * @param targetPlayer      The player to open the menu for.\n     * @param previousMenu      The previous menu that was opened, if exists.\n     * @param targetIsland      The island to change permissions in.\n     * @param permissiblePlayer The player to change permissions for.\n     */\n    void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu,\n                         Island targetIsland, SuperiorPlayer permissiblePlayer);\n\n    /**\n     * Open the island permissions menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island that holds the permissions.\n     * @param targetPlayer   The target player to see their permissions.\n     * @deprecated see {@link #openPermissions(SuperiorPlayer, ISuperiorMenu, Island, SuperiorPlayer)}\n     */\n    @Deprecated\n    void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer);\n\n    /**\n     * Open the permissions-menu.\n     * Used when changing island-permissions of an island-role on an island.\n     *\n     * @param targetPlayer    The player to open the menu for.\n     * @param previousMenu    The previous menu that was opened, if exists.\n     * @param targetIsland    The island to change permissions in.\n     * @param permissibleRole The island-role to change permissions for.\n     */\n    void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu,\n                         Island targetIsland, PlayerRole permissibleRole);\n\n    /**\n     * Open the island permissions menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island that holds the permissions.\n     * @param playerRole     The target role to see their permissions.\n     * @deprecated see {@link #openPermissions(SuperiorPlayer, ISuperiorMenu, Island, PlayerRole)}\n     */\n    @Deprecated\n    void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole);\n\n    /**\n     * Refresh the permissions-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshPermissions(Island island);\n\n    /**\n     * Refresh the permissions-menu of a player for a specific island.\n     *\n     * @param island            The island to refresh the menus for.\n     * @param permissiblePlayer The player to change permissions.\n     */\n    void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer);\n\n    /**\n     * Refresh the permissions-menu of an island role for a specific island.\n     *\n     * @param island          The island to refresh the menus for.\n     * @param permissibleRole The island role to change permissions for.\n     */\n    void refreshPermissions(Island island, PlayerRole permissibleRole);\n\n    /**\n     * Update the island permission in the menu.\n     *\n     * @param islandPrivilege The permission to update.\n     */\n    void updatePermission(IslandPrivilege islandPrivilege);\n\n    /**\n     * Open the player-language menu.\n     * Used when a player changes his language.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the language menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @deprecated see {@link #openPlayerLanguage(SuperiorPlayer, ISuperiorMenu)}\n     */\n    @Deprecated\n    void openPlayerLanguageMenu(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Open the island-settings menu.\n     * Used when changing island-settings.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to change settings for.\n     */\n    void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island settings menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the settings from.\n     * @deprecated see {@link #openSettings(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandSettingsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the island-settings menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshSettings(Island island);\n\n    /**\n     * Update the island settings in the menu.\n     *\n     * @param islandFlag The settings to update.\n     */\n    @Deprecated\n    void updateSettings(IslandFlag islandFlag);\n\n    /**\n     * Open the top-islands menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param sortingType  The type of sorting of islands to use.\n     */\n    void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType);\n\n    /**\n     * Open the islands top menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param sortingType    The sorting type you want to open.\n     * @deprecated see {@link #openTopIslands(SuperiorPlayer, ISuperiorMenu, SortingType)}\n     */\n    @Deprecated\n    void openIslandsTopMenu(SuperiorPlayer superiorPlayer, SortingType sortingType);\n\n    /**\n     * Refresh the top-islands menu for a specific sorting type.\n     *\n     * @param sortingType The sorting type to refresh.\n     */\n    void refreshTopIslands(SortingType sortingType);\n\n    /**\n     * Open the unique-visitors menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get visitors from.\n     */\n    void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the unique island visitors menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the visitors from.\n     * @deprecated see {@link #openUniqueVisitors(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openUniqueVisitorsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the unique-visitors menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshUniqueVisitors(Island island);\n\n    /**\n     * Open the upgrades-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get upgrade levels from.\n     */\n    void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island upgrade menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the upgrades from.\n     * @deprecated see {@link #openUpgrades(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandUpgradeMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the upgrades-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshUpgrades(Island island);\n\n    /**\n     * Open the values-menu.\n     * Used when right-clicking an island in the top-islands menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get values from.\n     */\n    void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the island values menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the values from.\n     * @deprecated see {@link #openValues(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandValuesMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the values-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshValues(Island island);\n\n    /**\n     * Open the visitors-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get visitors from.\n     */\n    void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the visitors-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshVisitors(Island island);\n\n    /**\n     * Open the island visitors menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the visitors from.\n     * @deprecated see {@link #openVisitors(SuperiorPlayer, ISuperiorMenu, Island)}\n     */\n    @Deprecated\n    void openIslandVisitorsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Open the warp categories menu\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get warp categories from.\n     */\n    void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the warp categories menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshWarpCategories(Island island);\n\n    /**\n     * Destroy the warp-categories menus for a specific island.\n     *\n     * @param island The island to close menus of.\n     */\n    void destroyWarpCategories(Island island);\n\n    /**\n     * Open the warp-category icon edit menu.\n     * Used when editing an icon of a warp category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The warp category to edit the icon for.\n     */\n    void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Open the warp category manage menu.\n     * Used when managing a warp category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The warp category to manage.\n     */\n    void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Refresh the warp category manage menu for a specific warp category.\n     *\n     * @param warpCategory The warp category to refresh the menus for.\n     */\n    void refreshWarpCategoryManage(WarpCategory warpCategory);\n\n    /**\n     * Open the warp icon edit menu.\n     * Used when editing an icon of a warp.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetWarp   The warp to edit the icon for.\n     */\n    void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp);\n\n    /**\n     * Open the warp manage menu.\n     * Used when managing a warp.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetWarp   The warp to manage.\n     */\n    void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp);\n\n    /**\n     * Refresh the warp manage menu for a specific warp.\n     *\n     * @param islandWarp The warp to refresh the menus for.\n     */\n    void refreshWarpManage(IslandWarp islandWarp);\n\n    /**\n     * Open the warps menu.\n     * Used to look for all warps in a category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The category to get warps from.\n     */\n    void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Open the island warps menu for a player.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param island         The island to get the warps from.\n     * @deprecated see {@link #openWarps(SuperiorPlayer, ISuperiorMenu, WarpCategory)}\n     */\n    @Deprecated\n    void openIslandWarpsMenu(SuperiorPlayer superiorPlayer, Island island);\n\n    /**\n     * Refresh the warps-menu for a specific island.\n     *\n     * @param warpCategory The warp category to refresh the menus for.\n     */\n    void refreshWarps(WarpCategory warpCategory);\n\n    /**\n     * Destroy the warp-categories menus for a specific warp category.\n     *\n     * @param warpCategory The warp category to close menus of.\n     */\n    void destroyWarps(WarpCategory warpCategory);\n\n    /**\n     * Register a new menu to the plugin.\n     *\n     * @param menu The menu to register.\n     */\n    void registerMenu(Menu<?, ?> menu);\n\n    /**\n     * Get a menu by its identifier.\n     *\n     * @param identifier The identifier of the menu.\n     */\n    @Nullable\n    <V extends MenuView<V, A>, A extends ViewArgs> Menu<V, A> getMenu(String identifier);\n\n    /**\n     * Get all the registered menus.\n     */\n    Map<String, Menu<?, ?>> getMenus();\n\n    /**\n     * Get all the custom menus that were registered.\n     */\n    Map<String, Menu<?, ?>> getCustomMenus();\n\n    /**\n     * Create a new pattern builder for building a menu.\n     */\n    <V extends MenuView<V, ?>> MenuLayout.Builder<V> createPatternBuilder();\n\n    /**\n     * Create a new pattern builder for building a paged-based menu.\n     */\n    <V extends PagedMenuView<V, ?, E>, E> PagedMenuLayout.Builder<V, E> createPagedPatternBuilder();\n\n    /**\n     * Create a new button builder.\n     */\n    <V extends MenuView<V, ?>> MenuTemplateButton.Builder<V> createButtonBuilder(\n            Class<?> viewButtonType, MenuTemplateButton.MenuViewButtonCreator<V> viewButtonCreator);\n\n    /**\n     * Create a new button builder.\n     */\n    <V extends MenuView<V, ?>, E> PagedMenuTemplateButton.Builder<V, E> createPagedButtonBuilder(\n            Class<?> viewButtonType, PagedMenuTemplateButton.PagedMenuViewButtonCreator<V, E> viewButtonCreator);\n\n    /**\n     * Get the parser instance.\n     */\n    MenuParser getParser();\n\n    /**\n     * Get the commands executor instance.\n     */\n    MenuCommands getMenuCommands();\n\n\n    /**\n     * Helper method to cast the new {@link MenuView} object to the old {@link ISuperiorMenu} object.\n     */\n    @Deprecated\n    ISuperiorMenu getOldMenuFromView(MenuView<?, ?> menuView);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MissionsManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic interface MissionsManager {\n\n    /**\n     * Get a mission by its name.\n     *\n     * @param name The name to check.\n     */\n    @Nullable\n    Mission<?> getMission(String name);\n\n    /**\n     * Get a list of all the missions.\n     */\n    List<Mission<?>> getAllMissions();\n\n    /**\n     * Get a list of all missions that are player missions.\n     */\n    List<Mission<?>> getPlayerMissions();\n\n    /**\n     * Get a list of all missions that are island missions.\n     */\n    List<Mission<?>> getIslandMissions();\n\n    /**\n     * Get a mission category by its name.\n     *\n     * @param name The name to check.\n     */\n    @Nullable\n    MissionCategory getMissionCategory(String name);\n\n    /**\n     * Get all the mission categories.\n     */\n    List<MissionCategory> getMissionCategories();\n\n    /**\n     * Check whether or not the player has already completed the mission.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player has completed, otherwise false.\n     */\n    boolean hasCompleted(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Check whether or not a player can complete a mission.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player can complete, otherwise false.\n     */\n    boolean canComplete(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Check whether or not a player can complete a mission, without considering progress.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player can complete, otherwise false.\n     */\n    boolean canCompleteNoProgress(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Check whether or not the player can complete the mission again.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player can complete, otherwise false.\n     */\n    boolean canCompleteAgain(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Check whether or not a player has all the required missions to complete a mission.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player has all required missions, otherwise false.\n     */\n    boolean hasAllRequiredMissions(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Check whether or not a player can pass all the checks to complete a mission.\n     *\n     * @param superiorPlayer The player to check.\n     * @param mission        The mission to check.\n     * @return True if player can pass all checks, otherwise false.\n     */\n    boolean canPassAllChecks(SuperiorPlayer superiorPlayer, Mission<?> mission);\n\n    /**\n     * Reward a player for completing a specific mission.\n     *\n     * @param mission         The mission that was completed.\n     * @param superiorPlayer  The player to reward.\n     * @param checkAutoReward Whether or not the auto reward flag should be checked.\n     */\n    void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward);\n\n    /**\n     * Reward a player for completing a specific mission.\n     *\n     * @param mission         The mission that was completed.\n     * @param superiorPlayer  The player to reward.\n     * @param checkAutoReward Whether or not the auto reward flag should be checked.\n     * @param forceReward     Should the plugin force the reward to the player (no checks will be ran)\n     */\n    void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward);\n\n    /**\n     * Reward a player for completing a specific mission.\n     *\n     * @param mission         The mission that was completed.\n     * @param superiorPlayer  The player to reward.\n     * @param checkAutoReward Whether or not the auto reward flag should be checked.\n     * @param forceReward     Should the plugin force the reward to the player (no checks will be ran)\n     * @param result          The result of the reward.\n     */\n    void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward, @Nullable Consumer<Boolean> result);\n\n    /**\n     * Save all data related to missions.\n     * All the data is saved into a yaml file.\n     */\n    void saveMissionsData();\n\n    /**\n     * Load all data related to missions.\n     * All the data is loaded from a yaml file.\n     */\n    void loadMissionsData();\n\n    /**\n     * Load all data related to missions of specific missions.\n     * All the data is loaded from a yaml file.\n     */\n    void loadMissionsData(List<Mission<?>> missionsList);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/ModulesManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collection;\n\npublic interface ModulesManager {\n\n    /**\n     * Register a new module to the plugin.\n     *\n     * @param pluginModule The module to register.\n     */\n    void registerModule(PluginModule pluginModule);\n\n    /**\n     * Register a new module to the plugin from a file.\n     *\n     * @param moduleFile The module to register.\n     */\n    PluginModule registerModule(File moduleFile) throws IOException, ReflectiveOperationException;\n\n    /**\n     * Unregister a module from the plugin.\n     *\n     * @param pluginModule The module to unregister.\n     */\n    void unregisterModule(PluginModule pluginModule);\n\n    /**\n     * Get a module by its name.\n     *\n     * @param name The name of the module.\n     */\n    @Nullable\n    PluginModule getModule(String name);\n\n    /**\n     * Get all the active modules currently running.\n     */\n    Collection<PluginModule> getModules();\n\n    /**\n     * Enable a specific module.\n     *\n     * @param pluginModule The module to load.\n     */\n    void enableModule(PluginModule pluginModule);\n\n    /**\n     * Enable all modules with a specific module load time.\n     *\n     * @param moduleLoadTime The module load time to load modules with.\n     */\n    void enableModules(ModuleLoadTime moduleLoadTime);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/PlayersManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic interface PlayersManager {\n\n    /**\n     * Get a player by it's name.\n     *\n     * @param name The name to check.\n     * @return The player with that name.\n     */\n    @Nullable\n    SuperiorPlayer getSuperiorPlayer(String name);\n\n    /**\n     * Get a player by a player.\n     *\n     * @param player The player to check.\n     */\n    SuperiorPlayer getSuperiorPlayer(Player player);\n\n    /**\n     * Get a player by it's uuid.\n     *\n     * @param uuid The uuid to check.\n     * @return The player with that uuid.\n     */\n    SuperiorPlayer getSuperiorPlayer(UUID uuid);\n\n    /**\n     * Get all the players that joined the server.\n     */\n    List<SuperiorPlayer> getAllPlayers();\n\n    /**\n     * Get a player role by it's weight.\n     *\n     * @param weight The weight to check.\n     * @return The player role with that weight.\n     */\n    @Nullable\n    @Deprecated\n    PlayerRole getPlayerRole(int weight);\n\n    /**\n     * Get a player role by it's id.\n     *\n     * @param id The id to check.\n     * @return The player role with that weight.\n     */\n    @Nullable\n    @Deprecated\n    PlayerRole getPlayerRoleFromId(int id);\n\n    /**\n     * Get a player role by it's name.\n     *\n     * @param name The name to check.\n     * @return The player role with that name.\n     * If there's no role with that name, IllegalArgumentException will be thrown.\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    PlayerRole getPlayerRole(String name);\n\n    /**\n     * Get the default role that players are assigned with when they join an island.\n     *\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    PlayerRole getDefaultRole();\n\n    /**\n     * Get the highest role in the ladder - aka, leader's role.\n     *\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    PlayerRole getLastRole();\n\n    /**\n     * Get the guest's role.\n     *\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    PlayerRole getGuestRole();\n\n    /**\n     * Get the co-op's role.\n     *\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    PlayerRole getCoopRole();\n\n    /**\n     * Get a list of all the roles.\n     *\n     * @deprecated see {@link RolesManager}\n     */\n    @Deprecated\n    List<PlayerRole> getRoles();\n\n    /**\n     * Get the players container.\n     */\n    PlayersContainer getPlayersContainer();\n\n    /**\n     * Set a new players container.\n     *\n     * @param playersContainer The new players container to set.\n     */\n    void setPlayersContainer(PlayersContainer playersContainer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/ProvidersManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.AFKProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.MenusProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.PricesProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.ISkinsListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldsListener;\n\nimport java.util.List;\n\npublic interface ProvidersManager {\n\n    /**\n     * Get the currently used spawners-provider.\n     */\n    SpawnersProvider getSpawnersProvider();\n\n    /**\n     * Set custom spawners provider for the plugin.\n     *\n     * @param spawnersProvider The spawner provider to set.\n     */\n    void setSpawnersProvider(SpawnersProvider spawnersProvider);\n\n    /**\n     * Get the currently used stacked-blocks provider.\n     */\n    StackedBlocksProvider getStackedBlocksProvider();\n\n    /**\n     * Set a custom stacked-blocks provider for the plugin.\n     *\n     * @param stackedBlocksProvider The stacked-blocks provider to set.\n     */\n    void setStackedBlocksProvider(StackedBlocksProvider stackedBlocksProvider);\n\n    /**\n     * Get the currently used stacked-entities provider.\n     */\n    List<EntitiesProvider> getEntitiesProviders();\n\n    /**\n     * Add a custom entities provider for the plugin.\n     *\n     * @param entitiesProvider The entities provider to add.\n     */\n    void addEntitiesProvider(EntitiesProvider entitiesProvider);\n\n    /**\n     * Get the currently used economy-provider.\n     */\n    EconomyProvider getEconomyProvider();\n\n    /**\n     * Set custom economy provider for the plugin.\n     *\n     * @param economyProvider The economy provider to set.\n     */\n    void setEconomyProvider(EconomyProvider economyProvider);\n\n    /**\n     * Get the currently used worlds-provider.\n     */\n    WorldsProvider getWorldsProvider();\n\n    /**\n     * Set a custom worlds provider for the plugin.\n     *\n     * @param worldsProvider The worlds provider to set.\n     */\n    void setWorldsProvider(WorldsProvider worldsProvider);\n\n    /**\n     * Get the currently used chunks-provider.\n     */\n    ChunksProvider getChunksProvider();\n\n    /**\n     * Set a custom chunks provider for the plugin.\n     *\n     * @param chunksProvider The chunks provider to set.\n     */\n    void setChunksProvider(ChunksProvider chunksProvider);\n\n    /**\n     * Get the currently used bank-economy provider.\n     */\n    EconomyProvider getBankEconomyProvider();\n\n    /**\n     * Set custom economy provider for the island banks.\n     *\n     * @param economyProvider The economy provider to set.\n     */\n    void setBankEconomyProvider(EconomyProvider economyProvider);\n\n    /**\n     * Get the currently used afk providers.\n     */\n    List<AFKProvider> getAFKProviders();\n\n    /**\n     * Add AFK Provider to the plugin.\n     *\n     * @param afkProvider The afk-provider to add.\n     */\n    void addAFKProvider(AFKProvider afkProvider);\n\n    /**\n     * Get the currently used menus-provider.\n     */\n    MenusProvider getMenusProvider();\n\n    /**\n     * Set a new menus-provider to the plugin.\n     *\n     * @param menuProvider The new menus-provider to use.\n     */\n    void setMenusProvider(MenusProvider menuProvider);\n\n    /**\n     * Get the currently used permissions-provider.\n     */\n    PermissionsProvider getPermissionsProvider();\n\n    /**\n     * Set a new permissions-provider to the plugin.\n     *\n     * @param permissionsProvider The new permissions-provider to use.\n     */\n    void setPermissionsProvider(PermissionsProvider permissionsProvider);\n\n    /**\n     * Get the currently used prices-provider.\n     */\n    PricesProvider getPricesProvider();\n\n    /**\n     * Set a new prices-provider to the plugin.\n     *\n     * @param pricesProvider The new prices-provider to use.\n     */\n    void setPricesProvider(PricesProvider pricesProvider);\n\n    /**\n     * Get the currently used vanish-provider.\n     */\n    VanishProvider getVanishProvider();\n\n    /**\n     * Set a new vanish-provider to the plugin.\n     *\n     * @param vanishProvider The new vanish-provider to use.\n     */\n    void setVanishProvider(VanishProvider vanishProvider);\n\n    /**\n     * Register a new skins listener.\n     *\n     * @param skinsListener The new skins listener to register.\n     */\n    void registerSkinsListener(ISkinsListener skinsListener);\n\n    /**\n     * Unregister a skins listener.\n     *\n     * @param skinsListener The new skins listener to unregister.\n     */\n    void unregisterSkinsListener(ISkinsListener skinsListener);\n\n    /**\n     * Register a new stacked-blocks listener.\n     *\n     * @param stackedBlocksListener The new stacked-blocks listener to register.\n     */\n    void registerStackedBlocksListener(IStackedBlocksListener stackedBlocksListener);\n\n    /**\n     * Unregister a stacked-blocks listener.\n     *\n     * @param stackedBlocksListener The stacked-blocks listener to unregister.\n     */\n    void unregisterStackedBlocksListener(IStackedBlocksListener stackedBlocksListener);\n\n    /**\n     * Register a new worlds listener.\n     *\n     * @param worldsListener The new worlds listener to register.\n     */\n    void registerWorldsListener(IWorldsListener worldsListener);\n\n    /**\n     * Unregister a worlds listener.\n     *\n     * @param worldsListener The worlds listener to unregister.\n     */\n    void unregisterWorldsListener(IWorldsListener worldsListener);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/RolesManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\n\nimport java.util.List;\n\npublic interface RolesManager {\n\n    /**\n     * Get a player role by it's weight.\n     *\n     * @param weight The weight to check.\n     * @return The player role with that weight.\n     */\n    @Nullable\n    PlayerRole getPlayerRole(int weight);\n\n    /**\n     * Get a player role by it's id.\n     *\n     * @param id The id to check.\n     * @return The player role with that weight.\n     */\n    @Nullable\n    PlayerRole getPlayerRoleFromId(int id);\n\n    /**\n     * Get a player role by it's name.\n     *\n     * @param name The name to check.\n     * @return The player role with that name.\n     * If there's no role with that name, IllegalArgumentException will be thrown.\n     */\n    PlayerRole getPlayerRole(String name);\n\n    /**\n     * Get the default role that players are assigned with when they join an island.\n     */\n    PlayerRole getDefaultRole();\n\n    /**\n     * Get the highest role in the ladder - aka, leader's role.\n     */\n    PlayerRole getLastRole();\n\n    /**\n     * Get the guest's role.\n     */\n    PlayerRole getGuestRole();\n\n    /**\n     * Get the co-op's role.\n     */\n    PlayerRole getCoopRole();\n\n    /**\n     * Get a list of all the roles.\n     */\n    List<PlayerRole> getRoles();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\n\nimport java.util.List;\n\npublic interface SchematicManager {\n\n    /**\n     * Get a schematic by it's name.\n     *\n     * @param name The name to check.\n     * @return The schematic with that name.\n     */\n    @Nullable\n    Schematic getSchematic(String name);\n\n    /**\n     * Get a list of all the schematics.\n     */\n    List<String> getSchematics();\n\n    /**\n     * Register a new schematic parser.\n     * Files will be parsed using the registered schematics. The plugin will attempt to parse the schematic files\n     * using each of the parsers in the same order they were registered. If no parsers are available, or no parser\n     * could parse the file, the plugin will use the default parser.\n     *\n     * @param schematicParser The schematic-parser to register.\n     */\n    void registerSchematicParser(SchematicParser schematicParser);\n\n    /**\n     * Get all the registered parsers, in the same order they were registered.\n     */\n    List<SchematicParser> getSchematicParsers();\n\n    /**\n     * Save a schematic.\n     * Calls the {@link #saveSchematic(SuperiorPlayer, String, boolean)} with saveAir set to false.\n     *\n     * @param superiorPlayer The player who saves the schematic.\n     * @param schematicName  The schematic name.\n     */\n    void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName);\n\n    /**\n     * Save a schematic.\n     * Calls the {@link #saveSchematic(Location, Location, SchematicOptions, Runnable)} method with default values.\n     *\n     * @param superiorPlayer The player who saves the schematic.\n     * @param schematicName  The schematic name.\n     * @param saveAir        Whether to save air blocks into the schematic.\n     */\n    void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1          First position for the schematic.\n     * @param pos2          Second position for the schematic.\n     * @param offsetX       The offset x value for the schematic (from minimum location between the two)\n     * @param offsetY       The offset y value for the schematic (from minimum location between the two)\n     * @param offsetZ       The offset z value for the schematic (from minimum location between the two)\n     * @param schematicName The new schematic name that will be created.\n     */\n    void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1          First position for the schematic.\n     * @param pos2          Second position for the schematic.\n     * @param offsetX       The offset x value for the schematic (from minimum location between the two)\n     * @param offsetY       The offset y value for the schematic (from minimum location between the two)\n     * @param offsetZ       The offset z value for the schematic (from minimum location between the two)\n     * @param yaw           The yaw value of the schematic.\n     * @param pitch         The pitch value of the schematic.\n     * @param schematicName The new schematic name that will be created.\n     */\n    void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1          First position for the schematic.\n     * @param pos2          Second position for the schematic.\n     * @param offsetX       The offset x value for the schematic (from minimum location between the two)\n     * @param offsetY       The offset y value for the schematic (from minimum location between the two)\n     * @param offsetZ       The offset z value for the schematic (from minimum location between the two)\n     * @param schematicName The new schematic name that will be created.\n     * @param callable      A runnable that will be ran after the task is completed.\n     */\n    void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName, Runnable callable);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1          First position for the schematic.\n     * @param pos2          Second position for the schematic.\n     * @param offsetX       The offset x value for the schematic (from minimum location between the two)\n     * @param offsetY       The offset y value for the schematic (from minimum location between the two)\n     * @param offsetZ       The offset z value for the schematic (from minimum location between the two)\n     * @param yaw           The yaw value of the schematic.\n     * @param pitch         The pitch value of the schematic.\n     * @param schematicName The new schematic name that will be created.\n     * @param callable      A runnable that will be ran after the task is completed.\n     */\n    void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName, @Nullable Runnable callable);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1             First position for the schematic.\n     * @param pos2             Second position for the schematic.\n     * @param schematicOptions The options for creating the new schematic.\n     */\n    void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions);\n\n    /**\n     * Save a schematic.\n     *\n     * @param pos1             First position for the schematic.\n     * @param pos2             Second position for the schematic.\n     * @param schematicOptions The options for creating the new schematic.\n     * @param callable         A runnable that will be ran after the task is completed.\n     */\n    void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/StackedBlocksManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\n\nimport java.util.Map;\n\npublic interface StackedBlocksManager extends IDatabaseBridgeHolder {\n\n    /**\n     * Get the block amount in a specific block.\n     *\n     * @param block The block to check.\n     */\n    int getStackedBlockAmount(Block block);\n\n    /**\n     * Get the block amount in a specific location.\n     *\n     * @param location The location to check.\n     */\n    int getStackedBlockAmount(Location location);\n\n    /**\n     * Get the block's key in a specific location.\n     *\n     * @param location The location to check.\n     */\n    @Nullable\n    Key getStackedBlockKey(Location location);\n\n    /**\n     * Set a new amount for a specific block.\n     *\n     * @param block  The block to set the amount to.\n     * @param amount The new amount of the block.\n     */\n    boolean setStackedBlock(Block block, int amount);\n\n    /**\n     * Set a new amount for a specific block.\n     *\n     * @param location The location of the block.\n     * @param blockKey The key of the block.\n     * @param amount   The new amount of the block.\n     * @return true on success.\n     */\n    boolean setStackedBlock(Location location, Key blockKey, int amount);\n\n    /**\n     * Remove stacked block at a specific location.\n     *\n     * @param location The location of the stacked block.\n     * @return The amount of the removed block, or 1 if there were no blocks in the specified location.\n     */\n    int removeStackedBlock(Location location);\n\n    /**\n     * Remove stacked blocks at a specific chunk.\n     *\n     * @param chunk The chunk to remove stacked blocks from.\n     * @return The stacked blocks in the provided chunk.\n     */\n    Map<Location, Integer> removeStackedBlocks(Chunk chunk);\n\n    /**\n     * Remove stacked blocks at a specific chunk.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords value of the chunk.\n     * @param chunkZ The z-coords value of the chunk.\n     * @return The stacked blocks in the provided chunk.\n     */\n    Map<Location, Integer> removeStackedBlocks(World world, int chunkX, int chunkZ);\n\n    /**\n     * Get all the stacked blocks in a specific chunk.\n     *\n     * @param chunk The chunk to get stacked blocks from.\n     */\n    Map<Location, Integer> getStackedBlocks(Chunk chunk);\n\n    /**\n     * Get all the stacked blocks in a specific chunk.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords value of the chunk.\n     * @param chunkZ The z-coords value of the chunk.\n     */\n    Map<Location, Integer> getStackedBlocks(World world, int chunkX, int chunkZ);\n\n    /**\n     * Get all the stacked blocks on the server.\n     */\n    Map<Location, Integer> getStackedBlocks();\n\n    /**\n     * Update the hologram of a stacked block.\n     *\n     * @param location The location of the stacked block.\n     */\n    void updateStackedBlockHologram(Location location);\n\n    /**\n     * Update the holograms of stacked-blocks in a specific chunk.\n     *\n     * @param chunk The chunk to update holograms in.\n     */\n    void updateStackedBlockHolograms(Chunk chunk);\n\n    /**\n     * Remove the hologram of a stacked block.\n     *\n     * @param location The location of the stacked block.\n     */\n    void removeStackedBlockHologram(Location location);\n\n    /**\n     * Remove the holograms of stacked-blocks in a specific chunk.\n     *\n     * @param chunk The chunk to update holograms in.\n     */\n    void removeStackedBlockHolograms(Chunk chunk);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/UpgradesManager.java",
    "content": "package com.bgsoftware.superiorskyblock.api.handlers;\n\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\n\nimport java.util.Collection;\n\npublic interface UpgradesManager {\n\n    /**\n     * Get an upgrade by it's name.\n     *\n     * @param upgradeName The name of the upgrade.\n     */\n    @Nullable\n    Upgrade getUpgrade(String upgradeName);\n\n    /**\n     * Get an upgrade by it's menu slot.\n     *\n     * @param slot The slot of the upgrade.\n     */\n    @Nullable\n    Upgrade getUpgrade(int slot);\n\n    /**\n     * Add a new upgrade.\n     *\n     * @param upgrade The upgrade to add.\n     */\n    void addUpgrade(Upgrade upgrade);\n\n    /**\n     * Get an upgrade object that contains all the default values from config.\n     */\n    Upgrade getDefaultUpgrade();\n\n    /**\n     * Check whether or not an upgrade with the provided name exists or not.\n     *\n     * @param upgradeName The name to check.\n     */\n    boolean isUpgrade(String upgradeName);\n\n    /**\n     * Get all the upgrades of the plugin.\n     */\n    Collection<Upgrade> getUpgrades();\n\n    /**\n     * Register custom upgrade cost loader\n     *\n     * @param id         The id of the loader.\n     * @param costLoader the loader you're registering\n     */\n    void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader);\n\n    /**\n     * Get all registered cost loader\n     */\n    Collection<UpgradeCostLoader> getUpgradesCostLoaders();\n\n    /**\n     * Get upgrade cost loader by its id\n     */\n    @Nullable\n    UpgradeCostLoader getUpgradeCostLoader(String id);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/AFKProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport org.bukkit.entity.Player;\n\npublic interface AFKProvider {\n\n    /**\n     * Check whether a player is considered AFK.\n     *\n     * @param player The player to check.\n     */\n    boolean isAFK(Player player);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/ChunksProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport org.bukkit.Chunk;\nimport org.bukkit.World;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface ChunksProvider {\n\n    /**\n     * Load a chunk in the world.\n     *\n     * @param world  The world to load chunk from.\n     * @param chunkX X-coords of the chunk.\n     * @param chunkZ Z-coords of the chunk.\n     * @return CompletableFuture of the chunk instance.\n     */\n    CompletableFuture<Chunk> loadChunk(World world, int chunkX, int chunkZ);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/EconomyProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\npublic interface EconomyProvider {\n\n    /**\n     * Get the amount of money a specific user has in his bank.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    BigDecimal getBalance(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Deposit money into a player's bank.\n     *\n     * @param superiorPlayer The player to deposit money to.\n     * @param amount         The amount to deposit.\n     * @return A result object for the transaction.\n     */\n    EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount);\n\n    /**\n     * Withdraw money from a player's bank.\n     *\n     * @param superiorPlayer The player to withdraw money from.\n     * @param amount         The amount to withdraw.\n     * @return A result object for the transaction.\n     */\n    EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount);\n\n    class EconomyResult {\n\n        @Nullable\n        private final String errorMessage;\n        private final double transactionMoney;\n\n        public EconomyResult(String errorMessage) {\n            this(errorMessage, 0);\n        }\n\n        public EconomyResult(double transactionMoney) {\n            this(\"\", transactionMoney);\n        }\n\n        public EconomyResult(@Nullable String errorMessage, double transactionMoney) {\n            this.errorMessage = errorMessage;\n            this.transactionMoney = transactionMoney;\n        }\n\n        /**\n         * Get the error that occurred.\n         */\n        @Nullable\n        public String getErrorMessage() {\n            return errorMessage;\n        }\n\n        /**\n         * Get the amount of money involved in the transaction.\n         */\n        public double getTransactionMoney() {\n            return transactionMoney;\n        }\n\n        /**\n         * Check if the transaction has failed.\n         */\n        public boolean hasFailed() {\n            return errorMessage != null && !errorMessage.isEmpty();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/EntitiesProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport org.bukkit.entity.Entity;\n\npublic interface EntitiesProvider {\n\n    /**\n     * Should the plugin track the entity {@param entity}?\n     * This is relevant for spawning, de-spawning and entity limits.\n     * <p>\n     * Please note: The entity provided to this function may be in unloaded chunks.\n     * Do not attempt to change its attributes in this method in any way.\n     *\n     * @param entity The entity to check.\n     */\n    boolean shouldTrackEntity(Entity entity);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport org.bukkit.World;\n\npublic interface LazyWorldsProvider extends WorldsProvider {\n\n    /**\n     * Prepare world for teleportation.\n     *\n     * @param island         The target island.\n     * @param environment    The environment of the world to prepare.\n     * @param finishCallback Callback function after the preparation is finished.\n     */\n    @Deprecated\n    default void prepareWorld(Island island, World.Environment environment, Runnable finishCallback) {\n        prepareWorld(island, Dimension.getByName(environment.name()), finishCallback);\n    }\n\n    /**\n     * Prepare world for teleportation.\n     *\n     * @param island         The target island.\n     * @param dimension      The dimension of the world to prepare.\n     * @param finishCallback Callback function after the preparation is finished.\n     */\n    void prepareWorld(Island island, Dimension dimension, Runnable finishCallback);\n\n    /**\n     * Get the {@link WorldInfo} of the world of an island by the environment.\n     * The world does not have to be loaded.\n     *\n     * @param island      The island to check.\n     * @param environment The world environment.\n     * @return The world info for the given environment, or null if this environment is not enabled.\n     */\n    @Deprecated\n    @Nullable\n    default WorldInfo getIslandsWorldInfo(Island island, World.Environment environment) {\n        return getIslandsWorldInfo(island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * Get the {@link WorldInfo} of the world of an island by the dimension.\n     * The world does not have to be loaded.\n     *\n     * @param island    The island to check.\n     * @param dimension The world dimension.\n     * @return The world info for the given dimension, or null if this dimension is not enabled.\n     */\n    @Nullable\n    WorldInfo getIslandsWorldInfo(Island island, Dimension dimension);\n\n    /**\n     * Get the {@link WorldInfo} of the world of an island by its name.\n     * The world does not have to be loaded.\n     *\n     * @param island    The island to check.\n     * @param worldName The name of the world.\n     * @return The world info for the given name, or null if this name is not an islands world.\n     */\n    @Nullable\n    WorldInfo getIslandsWorldInfo(Island island, String worldName);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic interface MenusProvider {\n\n    /**\n     * Initialize the menus.\n     */\n    void initializeMenus();\n\n    /**\n     * Open the bank-logs menu.\n     * Used to display all logs of bank transactions.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to display bank logs for.\n     */\n    void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the bank-logs menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshBankLogs(Island island);\n\n    /**\n     * Open the biomes-menu.\n     * Used to display and choose biomes for the island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to change biomes for.\n     */\n    void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the border-color menu.\n     * Used to change the color of the world border for a player.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the confirm-ban menu.\n     * Used to confirm a ban of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to ban the player from.\n     * @param bannedPlayer The player that will be banned.\n     */\n    void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer);\n\n    /**\n     * Open the confirm-disband menu.\n     * Used to confirm disband of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to disband.\n     */\n    void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the confirm-kick menu.\n     * Used to confirm a kick of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to kick the player from.\n     * @param kickedPlayer The player that will be kicked.\n     */\n    void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer);\n\n    /**\n     * Open the confirm-leave menu.\n     * Used to confirm leaving of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the confirm-transfer menu.\n     * Used to confirm the transfer of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to ban the player from.\n     * @param newOwner The player that will be banned.\n     */\n    void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner);\n\n    /**\n     * Open the control-panel menu.\n     * Used when opening the control panel of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the control panel of.\n     */\n    void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the coops menu.\n     * Used when opening the coops menu of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get coop-members from.\n     */\n    void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the coops-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshCoops(Island island);\n\n    /**\n     * Open the block-counts menu.\n     * Used when opening the counts menu of an island (using /is counts, for example)\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get block counts from.\n     */\n    void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the counts-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshCounts(Island island);\n\n    /**\n     * Open the global-warps menu.\n     * Used when running the /is warp command.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Refresh the global-warps menu.\n     */\n    void refreshGlobalWarps();\n\n    /**\n     * Open the island-bank menu.\n     * Used when running the /is bank command.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the bank for.\n     */\n    void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the island bank menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandBank(Island island);\n\n    /**\n     * Open the island-banned-players menu.\n     * Used when running the /is ban command.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the menu for.\n     */\n    void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the banned-players menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandBannedPlayers(Island island);\n\n    /**\n     * Open the island-chests menu.\n     * Used to open the shared chests menu of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to open the shared-chests menu for.\n     */\n    void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the island-chests menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandChest(Island island);\n\n    /**\n     * Get island creation config for specific schematic.\n     *\n     * @param schematic The schematic to get the creation config for.\n     */\n    MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic);\n\n    /**\n     * Open the islands-creation menu.\n     * Used when creating a new island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandName   The desired name of the new island.\n     */\n    void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName);\n\n    /**\n     * Open the rate-menu.\n     * Used when giving a rating for an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to give a rating.\n     */\n    void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Open the ratings-menu.\n     * Used when checking given ratings of an island.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get ratings from.\n     */\n    void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the ratings-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshIslandRatings(Island island);\n\n    /**\n     * Open the member-manage menu.\n     * Used when managing an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandMember The island member to manage.\n     */\n    void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember);\n\n    /**\n     * Destroy the member-manage menus for a specific island member.\n     *\n     * @param islandMember The island member to close menus of.\n     */\n    void destroyMemberManage(SuperiorPlayer islandMember);\n\n    /**\n     * Used to open the member-role menu.\n     * Used when changing a role of an island member.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param islandMember The island member to change role for.\n     */\n    void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember);\n\n    /**\n     * Destroy the member-role menus for a specific island member.\n     *\n     * @param islandMember The island member to close menus of.\n     */\n    void destroyMemberRole(SuperiorPlayer islandMember);\n\n    /**\n     * Open the members-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to check the members of.\n     */\n    void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the members-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshMembers(Island island);\n\n    /**\n     * Open the missions-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the missions-menu of a specific category.\n     *\n     * @param targetPlayer    The player to open the menu for.\n     * @param previousMenu    The previous menu that was opened, if exists.\n     * @param missionCategory The category to get missions from.\n     */\n    void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory);\n\n    /**\n     * Refresh the missions-menu for a specific category.\n     *\n     * @param missionCategory The category to refresh the menus for.\n     */\n    void refreshMissionsCategory(MissionCategory missionCategory);\n\n    /**\n     * Open the permissions-menu.\n     * Used when changing island-permissions of a player on an island.\n     *\n     * @param targetPlayer      The player to open the menu for.\n     * @param previousMenu      The previous menu that was opened, if exists.\n     * @param targetIsland      The island to change permissions in.\n     * @param permissiblePlayer The player to change permissions for.\n     */\n    void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu,\n                         Island targetIsland, SuperiorPlayer permissiblePlayer);\n\n    /**\n     * Open the permissions-menu.\n     * Used when changing island-permissions of an island-role on an island.\n     *\n     * @param targetPlayer    The player to open the menu for.\n     * @param previousMenu    The previous menu that was opened, if exists.\n     * @param targetIsland    The island to change permissions in.\n     * @param permissibleRole The island-role to change permissions for.\n     */\n    void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu,\n                         Island targetIsland, PlayerRole permissibleRole);\n\n    /**\n     * Refresh the permissions-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshPermissions(Island island);\n\n    /**\n     * Refresh the permissions-menu of a player for a specific island.\n     *\n     * @param island            The island to refresh the menus for.\n     * @param permissiblePlayer The player to change permissions.\n     */\n    void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer);\n\n    /**\n     * Refresh the permissions-menu of an island role for a specific island.\n     *\n     * @param island          The island to refresh the menus for.\n     * @param permissibleRole The island role to change permissions for.\n     */\n    void refreshPermissions(Island island, PlayerRole permissibleRole);\n\n    /**\n     * Update the island permission in the menu.\n     *\n     * @param islandPrivilege The permission to update.\n     */\n    void updatePermission(IslandPrivilege islandPrivilege);\n\n    /**\n     * Open the player-language menu.\n     * Used when a player changes his language.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     */\n    void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Open the island-settings menu.\n     * Used when changing island-settings.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to change settings for.\n     */\n    void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the island-settings menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshSettings(Island island);\n\n    /**\n     * Update the island settings in the menu.\n     *\n     * @param islandFlag The settings to update.\n     */\n    void updateSettings(IslandFlag islandFlag);\n\n    /**\n     * Open the top-islands menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param sortingType  The type of sorting of islands to use.\n     */\n    void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType);\n\n    /**\n     * Refresh the top-islands menu for a specific sorting type.\n     *\n     * @param sortingType The sorting type to refresh.\n     */\n    void refreshTopIslands(SortingType sortingType);\n\n    /**\n     * Open the unique-visitors menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get visitors from.\n     */\n    void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the unique-visitors menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshUniqueVisitors(Island island);\n\n    /**\n     * Open the upgrades-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get upgrade levels from.\n     */\n    void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the upgrades-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshUpgrades(Island island);\n\n    /**\n     * Open the values-menu.\n     * Used when right-clicking an island in the top-islands menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get values from.\n     */\n    void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the values-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshValues(Island island);\n\n    /**\n     * Open the visitors-menu.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get visitors from.\n     */\n    void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the visitors-menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshVisitors(Island island);\n\n    /**\n     * Open the warp categories menu\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetIsland The island to get warp categories from.\n     */\n    void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland);\n\n    /**\n     * Refresh the warp categories menu for a specific island.\n     *\n     * @param island The island to refresh the menus for.\n     */\n    void refreshWarpCategories(Island island);\n\n    /**\n     * Destroy the warp-categories menus for a specific island.\n     *\n     * @param island The island to close menus of.\n     */\n    void destroyWarpCategories(Island island);\n\n    /**\n     * Open the warp-category icon edit menu.\n     * Used when editing an icon of a warp category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The warp category to edit the icon for.\n     */\n    void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Open the warp category manage menu.\n     * Used when managing a warp category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The warp category to manage.\n     */\n    void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Refresh the warp category manage menu for a specific warp category.\n     *\n     * @param warpCategory The warp category to refresh the menus for.\n     */\n    void refreshWarpCategoryManage(WarpCategory warpCategory);\n\n    /**\n     * Open the warp icon edit menu.\n     * Used when editing an icon of a warp.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetWarp   The warp to edit the icon for.\n     */\n    void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp);\n\n    /**\n     * Open the warp manage menu.\n     * Used when managing a warp.\n     *\n     * @param targetPlayer The player to open the menu for.\n     * @param previousMenu The previous menu that was opened, if exists.\n     * @param targetWarp   The warp to manage.\n     */\n    void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp);\n\n    /**\n     * Refresh the warp manage menu for a specific warp.\n     *\n     * @param islandWarp The warp to refresh the menus for.\n     */\n    void refreshWarpManage(IslandWarp islandWarp);\n\n    /**\n     * Open the warps-menu.\n     * Used to look for all warps in a category.\n     *\n     * @param targetPlayer   The player to open the menu for.\n     * @param previousMenu   The previous menu that was opened, if exists.\n     * @param targetCategory The category to get warps from.\n     */\n    void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory);\n\n    /**\n     * Refresh the warps-menu for a specific island.\n     *\n     * @param warpCategory The warp category to refresh the menus for.\n     */\n    void refreshWarps(WarpCategory warpCategory);\n\n    /**\n     * Destroy the warp-categories menus for a specific warp category.\n     *\n     * @param warpCategory The warp category to close menus of.\n     */\n    void destroyWarps(WarpCategory warpCategory);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/PermissionsProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport org.bukkit.entity.Player;\n\npublic interface PermissionsProvider {\n\n    /**\n     * Check whether a player has permission.\n     *\n     * @param player     The player to check permissions for.\n     * @param permission The permission to check.\n     * @return whether the player has permission excluding his operator status.\n     * This means that the permission must be given explicitly to the player for the method to return true.\n     */\n    boolean hasPermission(Player player, String permission);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/PricesProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigDecimal;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface PricesProvider {\n\n    /**\n     * Get price of a block/item.\n     *\n     * @param key The key of the block or the item.\n     * @return The price of that block/item.\n     */\n    BigDecimal getPrice(Key key);\n\n    /**\n     * Get the correct block-key for a price.\n     * Mostly used for legacy-versions where data values of blocks can be ignored.\n     *\n     * @param blockKey The original block-key.\n     * @return The correct-block key for a price.\n     */\n    @Nullable\n    Key getBlockKey(Key blockKey);\n\n    /**\n     * Get a CompletableFuture that is completed when all prices and data of this provider are ready.\n     */\n    default CompletableFuture<Void> getWhenPricesAreReady() {\n        return CompletableFuture.completedFuture(null);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/SpawnersProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface SpawnersProvider {\n\n    /**\n     * Get a pair that represents information about a spawner in a specific location.\n     * This method is called async first, and if the string in the pair is null, it will be called synced later.\n     * The integer represents the amount of spawners in that location, and the string represents the entity type.\n     *\n     * @param location The location to check.\n     */\n    Pair<Integer, String> getSpawner(Location location);\n\n    /**\n     * Get the spawner type from an item.\n     * May return null in-case the spawner has no entity inside it.\n     *\n     * @param itemStack The item to check.\n     */\n    @Nullable\n    String getSpawnerType(ItemStack itemStack);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/SpawnersSnapshotProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\n\nimport org.bukkit.Chunk;\nimport org.bukkit.World;\n\n/**\n * SpawnersProvider based on snapshots, similar concept to ChunkSnapshot from Bukkit.\n * The plugin will take a snapshot when calculating a chunk, and will release it once it's done\n * calculation of that chunk. Snapshots are taken sync, however reading them is done async.\n * Thread-safety must be implemented in order to not get weird issues.\n */\npublic interface SpawnersSnapshotProvider extends SpawnersProvider {\n\n    /**\n     * Take a snapshot of a chunk.\n     *\n     * @param chunk The chunk to take a snapshot of.\n     */\n    void takeSnapshot(Chunk chunk);\n\n    /**\n     * Release a snapshot of a chunk.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    void releaseSnapshot(World world, int chunkX, int chunkZ);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/StackedBlocksProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport org.bukkit.World;\n\nimport java.util.Collection;\n\npublic interface StackedBlocksProvider {\n\n    /**\n     * Get all stacked blocks in a chunk.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     * @return Collection of pairs representing the stacked blocks.\n     * The key of the pair is a Key object of the block.\n     * The value of the pair is the amount of the block.\n     */\n    Collection<Pair<Key, Integer>> getBlocks(World world, int chunkX, int chunkZ);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/StackedBlocksSnapshotProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\n\nimport org.bukkit.Chunk;\nimport org.bukkit.World;\n\n/**\n * StackedBlocksProvider based on snapshots, similar concept to ChunkSnapshot from Bukkit.\n * The plugin will take a snapshot when calculating a chunk, and will release it once it's done\n * calculation of that chunk. Snapshots are taken sync, however reading them is done async.\n * Thread-safety must be implemented in order to not get weird issues.\n */\npublic interface StackedBlocksSnapshotProvider extends StackedBlocksProvider {\n\n    /**\n     * Take a snapshot of a chunk.\n     *\n     * @param chunk The chunk to take a snapshot of.\n     */\n    void takeSnapshot(Chunk chunk);\n\n    /**\n     * Release a snapshot of a chunk.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    void releaseSnapshot(World world, int chunkX, int chunkZ);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/VanishProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport org.bukkit.entity.Player;\n\npublic interface VanishProvider {\n\n    /**\n     * Check whether a player is vanished from online players.\n     *\n     * @param player The player to check\n     */\n    boolean isVanished(Player player);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\nimport java.util.UUID;\n\npublic interface WorldsProvider {\n\n    /**\n     * Prepare all the island worlds on startup.\n     */\n    void prepareWorlds();\n\n    /**\n     * Get the world of an island by the dimension.\n     * If the world is not loaded, this method should load the world before returning.\n     *\n     * @param dimension The world dimension.\n     * @param island    The island to check.\n     */\n    @Nullable\n    World getIslandsWorld(Island island, Dimension dimension);\n\n    /**\n     * Get the world of an island by the environment.\n     * If the world is not loaded, this method should load the world before returning.\n     *\n     * @param environment The world environment.\n     * @param island      The island to check.\n     */\n    @Deprecated\n    @Nullable\n    default World getIslandsWorld(Island island, World.Environment environment) {\n        return getIslandsWorld(island, Dimension.getByName(environment.name()));\n    }\n\n    /**\n     * Get the dimension of an islands world.\n     * If the island is not an islands world, null will be returned.\n     *\n     * @param world The world to check.\n     */\n    @Nullable\n    Dimension getIslandsWorldDimension(World world);\n\n    /**\n     * Checks if the given world is an islands world.\n     *\n     * @param world The world to check.\n     */\n    boolean isIslandsWorld(World world);\n\n    /**\n     * Get the location for a new island that is created.\n     *\n     * @param previousLocation The location of the previous island that was created.\n     * @param islandsHeight    The default islands height.\n     * @param maxIslandSize    The default maximum island size.\n     * @param islandOwner      The owner of the island.\n     * @param islandUUID       The UUID of the island.\n     * @deprecated See {@link #getNextLocation(BlockPosition, int, int, UUID, UUID)}\n     */\n    default Location getNextLocation(Location previousLocation, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) {\n        return getNextLocation(SuperiorSkyblockAPI.getFactory().createBlockPosition(previousLocation),\n                islandsHeight, maxIslandSize, islandOwner, islandUUID);\n    }\n\n    /**\n     * Get the location for a new island that is created.\n     *\n     * @param previousPosition The position of the previous island that was created.\n     * @param islandsHeight    The default islands height.\n     * @param maxIslandSize    The default maximum island size.\n     * @param islandOwner      The owner of the island.\n     * @param islandUUID       The UUID of the island.\n     */\n    Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID);\n\n    /**\n     * Callback upon finishing of creation of islands.\n     *\n     * @param islandLocation The location of the new island.\n     * @param islandOwner    The owner of the island.\n     * @param islandUUID     The UUID of the island.\n     */\n    void finishIslandCreation(Location islandLocation, UUID islandOwner, UUID islandUUID);\n\n    /**\n     * Prepare teleportation of an entity to an island.\n     *\n     * @param island         The target island.\n     * @param location       The location that the entity will be teleported to.\n     * @param finishCallback Callback function after the preparation is finished.\n     */\n    void prepareTeleport(Island island, Location location, Runnable finishCallback);\n\n    /**\n     * Check whether or not normal worlds are enabled.\n     */\n    default boolean isNormalEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"NORMAL\"));\n    }\n\n    /**\n     * Check whether or not normal worlds are unlocked for islands by default.\n     */\n    default boolean isNormalUnlocked() {\n        return isDimensionUnlocked(Dimension.getByName(\"NORMAL\"));\n    }\n\n    /**\n     * Check whether or not nether worlds are enabled.\n     */\n    default boolean isNetherEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"NETHER\"));\n    }\n\n    /**\n     * Check whether or not nether worlds are unlocked for islands by default.\n     */\n    default boolean isNetherUnlocked() {\n        return isDimensionUnlocked(Dimension.getByName(\"NETHER\"));\n    }\n\n    /**\n     * Check whether or not end worlds are enabled.\n     */\n    default boolean isEndEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"THE_END\"));\n    }\n\n    /**\n     * Check whether or not end worlds are unlocked for islands by default.\n     */\n    default boolean isEndUnlocked() {\n        return isDimensionUnlocked(Dimension.getByName(\"THE_END\"));\n    }\n\n    /**\n     * Check whether a dimension is enabled on the server.\n     *\n     * @param dimension The dimension to check.\n     */\n    boolean isDimensionEnabled(Dimension dimension);\n\n    /**\n     * Check whether a dimension is unlocked for islands by default.\n     */\n    boolean isDimensionUnlocked(Dimension dimension);\n\n    /**\n     * Add a listener to when worlds are loaded by the provider.\n     * This is called by the plugin to listen to changes and fix things within island worlds.\n     *\n     * @param worldLoadListener The callback to listener.\n     */\n    default void addWorldLoadListener(IWorldLoadListener worldLoadListener) {\n        throw new UnsupportedOperationException(\"This operation is not supported by this WorldProvider.\");\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/ISkinsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks.listener;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\n/**\n * Listener for changes of skins of players.\n */\npublic interface ISkinsListener {\n\n    /**\n     * Update the skin of a player.\n     *\n     * @param superiorPlayer The player to update the skin for.\n     */\n    void setSkinTexture(SuperiorPlayer superiorPlayer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IStackedBlocksListener.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks.listener;\n\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.block.Block;\n\n/**\n * Listener for changes of stacked-blocks\n */\npublic interface IStackedBlocksListener {\n\n    /**\n     * Record a block-action related to stacked-blocks.\n     *\n     * @param offlinePlayer The player that interacted with the stacked-block.\n     * @param block The stacked-block\n     * @param action The action that was performed.\n     */\n    void recordBlockAction(OfflinePlayer offlinePlayer, Block block, Action action);\n\n    enum Action {\n\n        BLOCK_PLACE,\n        BLOCK_BREAK\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks.listener;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.World;\n\n/**\n * Listener used for {@link WorldsProvider#addWorldLoadListener(IWorldLoadListener)}\n */\npublic interface IWorldLoadListener {\n\n    /**\n     * The method to be called when a world is loaded.\n     *\n     * @param world          The world that was loaded.\n     * @param worldDimension The dimension of the world.\n     * @param flags          Flags to what the listener can do. More info at {@link WorldLoadFlags}\n     */\n    void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks.listener;\n\n/**\n * Listener for updates of worlds.\n */\npublic interface IWorldsListener {\n\n    /**\n     * Load a world.\n     *\n     * @param worldName the name of the world to load.\n     */\n    void loadWorld(String worldName);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.api.hooks.world;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener;\n\n/**\n * The integer value element annotated with {@link WorldLoadFlags} represents flags related to what to do\n * when a world is loaded. It is mainly used within the default {@link IWorldLoadListener} interface of the plugin.\n */\npublic @interface WorldLoadFlags {\n\n    /**\n     * Enable dragon fights for end worlds.\n     */\n    int END_DRAGON_FIGHT = 1 << 0;\n\n    /**\n     * Remove the anti-xray world patches.\n     */\n    int REMOVE_ANTI_XRAY = 1 << 1;\n\n    /**\n     * Update the ocean level of the world to the configured islands-height.\n     */\n    int UPDATE_OCEAN_LEVEL = 1 << 2;\n\n    /**\n     * Make the plugin listen to block neighbor changes and self-changing blocks.\n     */\n    int LISTEN_BLOCK_CHANGES = 1 << 3;\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/BlockChangeResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\n/**\n * Result of one of the block change methods of {@link Island}\n */\npublic enum BlockChangeResult {\n\n    /**\n     * No blocks were available in the block counts map provided.\n     */\n    NO_AVAILABLE_BLOCKS,\n\n    /**\n     * The block provided had no value configured for it and therefore was not tracked.\n     */\n    MISSING_BLOCK_VALUE,\n\n    /**\n     * Tried to track a block change for the spawn island.\n     */\n    SPAWN_ISLAND,\n\n    /**\n     * The block change was tracked successfully.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.annotations.Size;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic class DelegateIsland implements Island {\n\n    protected final Island handle;\n\n    protected DelegateIsland(Island handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public SuperiorPlayer getOwner() {\n        return this.handle.getOwner();\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return this.handle.getUniqueId();\n    }\n\n    @Override\n    public long getCreationTime() {\n        return this.handle.getCreationTime();\n    }\n\n    @Override\n    public String getCreationTimeDate() {\n        return this.handle.getCreationTimeDate();\n    }\n\n    @Override\n    public void updateDatesFormatter() {\n        this.handle.updateDatesFormatter();\n    }\n\n    @Override\n    public IslandCache getCache() {\n        return this.handle.getCache();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(boolean includeOwner) {\n        return this.handle.getIslandMembers(includeOwner);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(PlayerRole... playerRoles) {\n        return this.handle.getIslandMembers(playerRoles);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getBannedPlayers() {\n        return this.handle.getBannedPlayers();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors() {\n        return this.handle.getIslandVisitors();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors(boolean vanishPlayers) {\n        return this.handle.getIslandVisitors(vanishPlayers);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayersInside() {\n        return this.handle.getAllPlayersInside();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getUniqueVisitors() {\n        return this.handle.getUniqueVisitors();\n    }\n\n    @Override\n    public List<Pair<SuperiorPlayer, Long>> getUniqueVisitorsWithTimes() {\n        return this.handle.getUniqueVisitorsWithTimes();\n    }\n\n    @Override\n    public void inviteMember(SuperiorPlayer superiorPlayer) {\n        this.handle.inviteMember(superiorPlayer);\n    }\n\n    @Override\n    public void revokeInvite(SuperiorPlayer superiorPlayer) {\n        this.handle.revokeInvite(superiorPlayer);\n    }\n\n    @Override\n    public boolean isInvited(SuperiorPlayer superiorPlayer) {\n        return this.handle.isInvited(superiorPlayer);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getInvitedPlayers() {\n        return this.handle.getInvitedPlayers();\n    }\n\n    @Override\n    public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        this.handle.addMember(superiorPlayer, playerRole);\n    }\n\n    @Override\n    @Deprecated\n    public void kickMember(SuperiorPlayer superiorPlayer) {\n        this.handle.kickMember(superiorPlayer);\n    }\n\n    @Override\n    public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) {\n        this.handle.removeMember(superiorPlayer, memberRemoveReason);\n    }\n\n    @Override\n    public boolean isMember(SuperiorPlayer superiorPlayer) {\n        return this.handle.isMember(superiorPlayer);\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer) {\n        this.handle.banMember(superiorPlayer);\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom) {\n        this.handle.banMember(superiorPlayer, whom);\n    }\n\n    @Override\n    public void unbanMember(SuperiorPlayer superiorPlayer) {\n        this.handle.unbanMember(superiorPlayer);\n    }\n\n    @Override\n    public boolean isBanned(SuperiorPlayer superiorPlayer) {\n        return this.handle.isBanned(superiorPlayer);\n    }\n\n    @Override\n    public void addCoop(SuperiorPlayer superiorPlayer) {\n        this.handle.addCoop(superiorPlayer);\n    }\n\n    @Override\n    public void removeCoop(SuperiorPlayer superiorPlayer) {\n        this.handle.removeCoop(superiorPlayer);\n    }\n\n    @Override\n    public boolean isCoop(SuperiorPlayer superiorPlayer) {\n        return this.handle.isCoop(superiorPlayer);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getCoopPlayers() {\n        return this.handle.getCoopPlayers();\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return this.handle.getCoopLimit();\n    }\n\n    @Override\n    public int getCoopLimitRaw() {\n        return this.handle.getCoopLimitRaw();\n    }\n\n    @Override\n    public void setCoopLimit(int coopLimit) {\n        this.handle.setCoopLimit(coopLimit);\n    }\n\n    @Override\n    public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) {\n        this.handle.setPlayerInside(superiorPlayer, inside);\n    }\n\n    @Override\n    public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean checkCoopStatus) {\n        return this.handle.isVisitor(superiorPlayer, checkCoopStatus);\n    }\n\n    @Override\n    public Location getCenter(Dimension dimension) {\n        return this.handle.getCenter(dimension);\n    }\n\n    @Override\n    public BlockPosition getCenterPosition() {\n        return this.handle.getCenterPosition();\n    }\n\n    @Override\n    public CompletableFuture<World> accessIslandWorld(Dimension dimension) {\n        return this.handle.accessIslandWorld(dimension);\n    }\n\n    @Override\n    public Location getIslandHome(Dimension dimension) {\n        return this.handle.getIslandHome(dimension);\n    }\n\n    @Override\n    public WorldPosition getIslandHomePosition(Dimension dimension) {\n        return this.handle.getIslandHomePosition(dimension);\n    }\n\n    @Override\n    public Map<Dimension, Location> getIslandHomesAsDimensions() {\n        return this.handle.getIslandHomesAsDimensions();\n    }\n\n    @Override\n    public Map<Dimension, WorldPosition> getIslandHomes() {\n        return this.handle.getIslandHomes();\n    }\n\n    @Override\n    public void setIslandHome(Location homeLocation) {\n        this.handle.setIslandHome(homeLocation);\n    }\n\n    @Override\n    @Deprecated\n    public void setIslandHome(Dimension dimension, Location homeLocation) {\n        this.handle.setIslandHome(dimension, homeLocation);\n    }\n\n    @Override\n    public void setIslandHome(Dimension dimension, WorldPosition homePosition) {\n        this.handle.setIslandHome(dimension, homePosition);\n    }\n\n    @Override\n    public Location getVisitorsLocation(Dimension dimension) {\n        return this.handle.getVisitorsLocation(dimension);\n    }\n\n    @Override\n    public WorldPosition getVisitorsPosition(Dimension dimension) {\n        return this.handle.getVisitorsPosition(dimension);\n    }\n\n    @Override\n    public void setVisitorsLocation(@Nullable Location visitorsLocation) {\n        this.handle.setVisitorsLocation(visitorsLocation);\n    }\n\n    @Override\n    public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) {\n        this.handle.setVisitorsLocation(dimension, visitorsPosition);\n    }\n\n    @Override\n    public Location getMinimum() {\n        return this.handle.getMinimum();\n    }\n\n    @Override\n    public BlockPosition getMinimumPosition() {\n        return this.handle.getMinimumPosition();\n    }\n\n    @Override\n    public Location getMinimumProtected() {\n        return this.handle.getMinimumProtected();\n    }\n\n    @Override\n    public BlockPosition getMinimumProtectedPosition() {\n        return this.handle.getMinimumProtectedPosition();\n    }\n\n    @Override\n    public Location getMaximum() {\n        return this.handle.getMaximum();\n    }\n\n    @Override\n    public BlockPosition getMaximumPosition() {\n        return this.handle.getMaximumPosition();\n    }\n\n    @Override\n    public Location getMaximumProtected() {\n        return this.handle.getMaximumProtected();\n    }\n\n    @Override\n    public BlockPosition getMaximumProtectedPosition() {\n        return this.handle.getMaximumProtectedPosition();\n    }\n\n    @Override\n    public List<Chunk> getAllChunks() {\n        return this.handle.getAllChunks();\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(@IslandChunkFlags int flags) {\n        return this.handle.getAllChunks(flags);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(Dimension dimension) {\n        return this.handle.getAllChunks(dimension);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        return this.handle.getAllChunks(dimension, flags);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks() {\n        return this.handle.getLoadedChunks();\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(@IslandChunkFlags int flags) {\n        return this.handle.getLoadedChunks(flags);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension dimension) {\n        return this.handle.getLoadedChunks(dimension);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        return this.handle.getLoadedChunks(dimension, flags);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension) {\n        return this.handle.getAllChunksAsync(dimension);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) {\n        return this.handle.getAllChunksAsync(dimension, flags);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, Consumer<Chunk> onChunkLoad) {\n        return this.handle.getAllChunksAsync(dimension, onChunkLoad);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension,\n                                                            @IslandChunkFlags int flags,\n                                                            Consumer<Chunk> onChunkLoad) {\n        return this.handle.getAllChunksAsync(dimension, flags, onChunkLoad);\n    }\n\n    @Override\n    public void resetChunks() {\n        this.handle.resetChunks();\n    }\n\n    @Override\n    public void resetChunks(@Nullable Runnable onFinish) {\n        this.handle.resetChunks(onFinish);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension) {\n        this.handle.resetChunks(dimension);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, Runnable onFinish) {\n        this.handle.resetChunks(dimension, onFinish);\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags) {\n        this.handle.resetChunks(flags);\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) {\n        this.handle.resetChunks(flags, onFinish);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        this.handle.resetChunks(dimension, flags);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, Runnable onFinish) {\n        this.handle.resetChunks(dimension, flags, onFinish);\n    }\n\n    @Override\n    public boolean isInside(Location location) {\n        return this.handle.isInside(location);\n    }\n\n    @Override\n    public boolean isInside(Location location, int extraRadius) {\n        return this.handle.isInside(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Location location, double extraRadius) {\n        return this.handle.isInside(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition) {\n        return this.handle.isInside(blockPosition);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, int extraRadius) {\n        return this.handle.isInside(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, double extraRadius) {\n        return this.handle.isInside(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition) {\n        return this.handle.isInside(worldPosition);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, int extraRadius) {\n        return this.handle.isInside(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, double extraRadius) {\n        return this.handle.isInside(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Chunk chunk) {\n        return this.handle.isInside(chunk);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ) {\n        return this.handle.isInside(world, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInside(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInside(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return this.handle.isInside(worldInfo, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ) {\n        return this.handle.isInside(chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location) {\n        return this.handle.isInsideRange(location);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, int extraRadius) {\n        return this.handle.isInsideRange(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, double extraRadius) {\n        return this.handle.isInsideRange(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition) {\n        return this.handle.isInsideRange(blockPosition);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) {\n        return this.handle.isInsideRange(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) {\n        return this.handle.isInsideRange(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition) {\n        return this.handle.isInsideRange(worldPosition);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) {\n        return this.handle.isInsideRange(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) {\n        return this.handle.isInsideRange(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Chunk chunk) {\n        return this.handle.isInsideRange(chunk);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ) {\n        return this.handle.isInsideRange(world, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return this.handle.isInsideRange(worldInfo, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ) {\n        return this.handle.isInsideRange(chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) {\n        return this.handle.isInsideRange(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) {\n        return this.handle.isInsideRange(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isNormalEnabled() {\n        return this.handle.isNormalEnabled();\n    }\n\n    @Override\n    @Deprecated\n    public void setNormalEnabled(boolean enabled) {\n        this.handle.setNormalEnabled(enabled);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isNetherEnabled() {\n        return this.handle.isNetherEnabled();\n    }\n\n    @Override\n    @Deprecated\n    public void setNetherEnabled(boolean enabled) {\n        this.handle.setNetherEnabled(enabled);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isEndEnabled() {\n        return this.handle.isEndEnabled();\n    }\n\n    @Override\n    @Deprecated\n    public void setEndEnabled(boolean enabled) {\n        this.handle.setEndEnabled(enabled);\n    }\n\n    @Override\n    public boolean isDimensionEnabled(Dimension dimension) {\n        return this.handle.isDimensionEnabled(dimension);\n    }\n\n    @Override\n    public void setDimensionEnabled(Dimension dimension, boolean enabled) {\n        this.handle.setDimensionEnabled(dimension, enabled);\n    }\n\n    @Override\n    public Collection<Dimension> getUnlockedWorlds() {\n        return this.handle.getUnlockedWorlds();\n    }\n\n    @Override\n    public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) {\n        return this.handle.hasPermission(sender, islandPrivilege);\n    }\n\n    @Override\n    public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) {\n        return this.handle.hasPermission(superiorPlayer, islandPrivilege);\n    }\n\n    @Override\n    public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        return this.handle.hasPermission(playerRole, islandPrivilege);\n    }\n\n    @Override\n    @Deprecated\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) {\n        this.handle.setPermission(playerRole, islandPrivilege, value);\n    }\n\n    @Override\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        this.handle.setPermission(playerRole, islandPrivilege);\n    }\n\n    @Override\n    public void resetPermissions() {\n        this.handle.resetPermissions();\n    }\n\n    @Override\n    public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) {\n        this.handle.setPermission(superiorPlayer, islandPrivilege, value);\n    }\n\n    @Override\n    public void resetPermissions(SuperiorPlayer superiorPlayer) {\n        this.handle.resetPermissions(superiorPlayer);\n    }\n\n    @Override\n    public PermissionNode getPermissionNode(SuperiorPlayer superiorPlayer) {\n        return this.handle.getPermissionNode(superiorPlayer);\n    }\n\n    @Override\n    public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) {\n        return this.handle.getRequiredPlayerRole(islandPrivilege);\n    }\n\n    @Override\n    public Map<SuperiorPlayer, PermissionNode> getPlayerPermissions() {\n        return this.handle.getPlayerPermissions();\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> getRolePermissions() {\n        return this.handle.getRolePermissions();\n    }\n\n    @Override\n    public boolean isSpawn() {\n        return this.handle.isSpawn();\n    }\n\n    @Override\n    public String getName() {\n        return this.handle.getName();\n    }\n\n    @Override\n    public void setName(String islandName) {\n        this.handle.setName(islandName);\n    }\n\n    @Override\n    @Deprecated\n    public String getRawName() {\n        return this.handle.getRawName();\n    }\n\n    @Override\n    public String getStrippedName() {\n        return this.handle.getStrippedName();\n    }\n\n    @Override\n    public String getFormattedName() {\n        return this.handle.getFormattedName();\n    }\n\n    @Override\n    public String getDescription() {\n        return this.handle.getDescription();\n    }\n\n    @Override\n    public void setDescription(String description) {\n        this.handle.setDescription(description);\n    }\n\n    @Override\n    public void disbandIsland() {\n        this.handle.disbandIsland();\n    }\n\n    @Override\n    public boolean transferIsland(SuperiorPlayer superiorPlayer) {\n        return this.handle.transferIsland(superiorPlayer);\n    }\n\n    @Override\n    public void replacePlayers(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) {\n        this.handle.replacePlayers(originalPlayer, newPlayer);\n    }\n\n    @Override\n    public void calcIslandWorth(@Nullable SuperiorPlayer asker) {\n        this.handle.calcIslandWorth(asker);\n    }\n\n    @Override\n    public void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) {\n        this.handle.calcIslandWorth(asker, callback);\n    }\n\n    @Override\n    public IslandCalculationAlgorithm getCalculationAlgorithm() {\n        return this.handle.getCalculationAlgorithm();\n    }\n\n    @Override\n    public void updateBorder() {\n        this.handle.updateBorder();\n    }\n\n    @Override\n    public void updateIslandFly(SuperiorPlayer superiorPlayer) {\n        this.handle.updateIslandFly(superiorPlayer);\n    }\n\n    @Override\n    public int getIslandSize() {\n        return this.handle.getIslandSize();\n    }\n\n    @Override\n    public void setIslandSize(int islandSize) {\n        this.handle.setIslandSize(islandSize);\n    }\n\n    @Override\n    public int getIslandSizeRaw() {\n        return this.handle.getIslandSizeRaw();\n    }\n\n    @Override\n    public String getDiscord() {\n        return this.handle.getDiscord();\n    }\n\n    @Override\n    public void setDiscord(String discord) {\n        this.handle.setDiscord(discord);\n    }\n\n    @Override\n    public String getPaypal() {\n        return this.handle.getPaypal();\n    }\n\n    @Override\n    public void setPaypal(String paypal) {\n        this.handle.setPaypal(paypal);\n    }\n\n    @Override\n    public Biome getBiome() {\n        return this.handle.getBiome();\n    }\n\n    @Override\n    public void setBiome(Biome biome) {\n        this.handle.setBiome(biome);\n    }\n\n    @Override\n    public void setBiome(Biome biome, boolean updateBlocks) {\n        this.handle.setBiome(biome, updateBlocks);\n    }\n\n    @Override\n    public boolean isLocked() {\n        return this.handle.isLocked();\n    }\n\n    @Override\n    public void setLocked(boolean locked) {\n        this.handle.setLocked(locked);\n    }\n\n    @Override\n    public boolean isIgnored() {\n        return this.handle.isIgnored();\n    }\n\n    @Override\n    public void setIgnored(boolean ignored) {\n        this.handle.setIgnored(ignored);\n    }\n\n    @Override\n    public void sendMessage(String message) {\n        this.handle.sendMessage(message);\n    }\n\n    @Override\n    public void sendMessage(String message, UUID... ignoredMembers) {\n        this.handle.sendMessage(message, ignoredMembers);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent) {\n        this.handle.sendMessage(messageComponent);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, Object... args) {\n        this.handle.sendMessage(messageComponent, args);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers) {\n        this.handle.sendMessage(messageComponent, ignoredMembers);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers, Object... args) {\n        this.handle.sendMessage(messageComponent, ignoredMembers, args);\n    }\n\n    @Override\n    public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) {\n        this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut);\n    }\n\n    @Override\n    public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) {\n        this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut, ignoredMembers);\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers) {\n        this.handle.executeCommand(command, onlyOnlineMembers);\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) {\n        this.handle.executeCommand(command, onlyOnlineMembers, ignoredMembers);\n    }\n\n    @Override\n    public boolean isBeingRecalculated() {\n        return this.handle.isBeingRecalculated();\n    }\n\n    @Override\n    public void updateLastTime() {\n        this.handle.updateLastTime();\n    }\n\n    @Override\n    public void setCurrentlyActive() {\n        this.handle.setCurrentlyActive();\n    }\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        this.handle.completeMission(mission);\n    }\n\n    @Override\n    public void setCurrentlyActive(boolean active) {\n        this.handle.setCurrentlyActive(active);\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        this.handle.resetMission(mission);\n    }\n\n    @Override\n    public boolean isCurrentlyActive() {\n        return this.handle.isCurrentlyActive();\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return this.handle.hasCompletedMission(mission);\n    }\n\n    @Override\n    public long getLastTimeUpdate() {\n        return this.handle.getLastTimeUpdate();\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        return this.handle.canCompleteMissionAgain(mission);\n    }\n\n    @Override\n    public void setLastTimeUpdate(long lastTimeUpdate) {\n        this.handle.setLastTimeUpdate(lastTimeUpdate);\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        return this.handle.getAmountMissionCompleted(mission);\n    }\n\n    @Override\n    public IslandBank getIslandBank() {\n        return this.handle.getIslandBank();\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        this.handle.setAmountMissionCompleted(mission, finishCount);\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return this.handle.getBankLimit();\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return this.handle.getCompletedMissions();\n    }\n\n    @Override\n    public void setBankLimit(BigDecimal bankLimit) {\n        this.handle.setBankLimit(bankLimit);\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        return this.handle.getCompletedMissionsWithAmounts();\n    }\n\n    @Override\n    public BigDecimal getBankLimitRaw() {\n        return this.handle.getBankLimitRaw();\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return this.handle.getDatabaseBridge();\n    }\n\n    @Override\n    public boolean giveInterest(boolean checkOnlineOwner) {\n        return this.handle.giveInterest(checkOnlineOwner);\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        return this.handle.getPersistentDataContainer();\n    }\n\n    @Override\n    public long getLastInterestTime() {\n        return this.handle.getLastInterestTime();\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return this.handle.isPersistentDataContainerEmpty();\n    }\n\n    @Override\n    public void setLastInterestTime(long lastInterest) {\n        this.handle.setLastInterestTime(lastInterest);\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        this.handle.savePersistentDataContainer();\n    }\n\n    @Override\n    public long getNextInterest() {\n        return this.handle.getNextInterest();\n    }\n\n    @Override\n    public void handleBlockPlace(Block block) {\n        this.handle.handleBlockPlace(block);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block) {\n        return this.handle.handleBlockPlaceWithResult(block);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key) {\n        this.handle.handleBlockPlace(key);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key) {\n        return this.handle.handleBlockPlaceWithResult(key);\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount) {\n        this.handle.handleBlockPlace(block, amount);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) {\n        return this.handle.handleBlockPlaceWithResult(block, amount);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount) {\n        this.handle.handleBlockPlace(key, amount);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) {\n        return this.handle.handleBlockPlaceWithResult(key, amount);\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        this.handle.handleBlockPlace(block, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        return this.handle.handleBlockPlaceWithResult(block, amount, flags);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        this.handle.handleBlockPlace(key, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        return this.handle.handleBlockPlaceWithResult(key, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Block block, @Size int amount, boolean save) {\n        this.handle.handleBlockPlace(block, amount, save);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, @Size int amount, boolean save) {\n        this.handle.handleBlockPlace(key, amount, save);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, BigInteger amount, boolean save) {\n        this.handle.handleBlockPlace(key, amount, save);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, BigInteger amount, boolean save, boolean updateLastTimeStatus) {\n        this.handle.handleBlockPlace(key, amount, save, updateLastTimeStatus);\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks) {\n        this.handle.handleBlocksPlace(blocks);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks) {\n        return this.handle.handleBlocksPlaceWithResult(blocks);\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        this.handle.handleBlocksPlace(blocks, flags);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        return this.handle.handleBlocksPlaceWithResult(blocks, flags);\n    }\n\n    @Override\n    public void handleBlockBreak(Block block) {\n        this.handle.handleBlockBreak(block);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block) {\n        return this.handle.handleBlockBreakWithResult(block);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key) {\n        this.handle.handleBlockBreak(key);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key) {\n        return this.handle.handleBlockBreakWithResult(key);\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount) {\n        this.handle.handleBlockBreak(block, amount);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) {\n        return this.handle.handleBlockBreakWithResult(block, amount);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount) {\n        this.handle.handleBlockBreak(key, amount);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) {\n        return this.handle.handleBlockBreakWithResult(key, amount);\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        this.handle.handleBlockBreak(block, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        return this.handle.handleBlockBreakWithResult(block, amount, flags);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        this.handle.handleBlockBreak(key, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        return this.handle.handleBlockBreakWithResult(key, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Block block, @Size int amount, boolean save) {\n        this.handle.handleBlockBreak(block, amount, save);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, @Size int amount, boolean save) {\n        this.handle.handleBlockBreak(key, amount, save);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, BigInteger amount, boolean save) {\n        this.handle.handleBlockBreak(key, amount, save);\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks) {\n        this.handle.handleBlocksBreak(blocks);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks) {\n        return this.handle.handleBlocksBreakWithResult(blocks);\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        this.handle.handleBlocksBreak(blocks, flags);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        return this.handle.handleBlocksBreakWithResult(blocks, flags);\n    }\n\n    @Override\n    public boolean isChunkDirty(World world, int chunkX, int chunkZ) {\n        return this.handle.isChunkDirty(world, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) {\n        return this.handle.isChunkDirty(worldName, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return this.handle.isChunkDirty(worldInfo, chunkX, chunkZ);\n    }\n\n    @Override\n    public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) {\n        this.handle.markChunkDirty(world, chunkX, chunkZ, save);\n    }\n\n    @Override\n    public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        this.handle.markChunkDirty(worldInfo, chunkX, chunkZ, save);\n    }\n\n    @Override\n    public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) {\n        this.handle.markChunkEmpty(world, chunkX, chunkZ, save);\n    }\n\n    @Override\n    public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        this.handle.markChunkEmpty(worldInfo, chunkX, chunkZ, save);\n    }\n\n    @Override\n    public BigInteger getBlockCountAsBigInteger(Key key) {\n        return this.handle.getBlockCountAsBigInteger(key);\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCountsAsBigInteger() {\n        return this.handle.getBlockCountsAsBigInteger();\n    }\n\n    @Override\n    public BigInteger getExactBlockCountAsBigInteger(Key key) {\n        return this.handle.getExactBlockCountAsBigInteger(key);\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        this.handle.clearBlockCounts();\n    }\n\n    @Override\n    public IslandBlocksTrackerAlgorithm getBlocksTracker() {\n        return this.handle.getBlocksTracker();\n    }\n\n    @Override\n    public BigDecimal getWorth() {\n        return this.handle.getWorth();\n    }\n\n    @Override\n    public BigDecimal getRawWorth() {\n        return this.handle.getRawWorth();\n    }\n\n    @Override\n    public BigDecimal getBonusWorth() {\n        return this.handle.getBonusWorth();\n    }\n\n    @Override\n    public void setBonusWorth(BigDecimal bonusWorth) {\n        this.handle.setBonusWorth(bonusWorth);\n    }\n\n    @Override\n    public BigDecimal getBonusLevel() {\n        return this.handle.getBonusLevel();\n    }\n\n    @Override\n    public void setBonusLevel(BigDecimal bonusLevel) {\n        this.handle.setBonusLevel(bonusLevel);\n    }\n\n    @Override\n    public BigDecimal getIslandLevel() {\n        return this.handle.getIslandLevel();\n    }\n\n    @Override\n    public BigDecimal getRawLevel() {\n        return this.handle.getRawLevel();\n    }\n\n    @Override\n    public UpgradeLevel getUpgradeLevel(Upgrade upgrade) {\n        return this.handle.getUpgradeLevel(upgrade);\n    }\n\n    @Override\n    public void setUpgradeLevel(Upgrade upgrade, int level) {\n        this.handle.setUpgradeLevel(upgrade, level);\n    }\n\n    @Override\n    public Map<String, Integer> getUpgrades() {\n        return this.handle.getUpgrades();\n    }\n\n    @Override\n    public void syncUpgrades() {\n        this.handle.syncUpgrades();\n    }\n\n    @Override\n    public void updateUpgrades() {\n        this.handle.updateUpgrades();\n    }\n\n    @Override\n    public long getLastTimeUpgrade() {\n        return this.handle.getLastTimeUpgrade();\n    }\n\n    @Override\n    public boolean hasActiveUpgradeCooldown() {\n        return this.handle.hasActiveUpgradeCooldown();\n    }\n\n    @Override\n    public double getCropGrowthMultiplier() {\n        return this.handle.getCropGrowthMultiplier();\n    }\n\n    @Override\n    public void setCropGrowthMultiplier(double cropGrowth) {\n        this.handle.setCropGrowthMultiplier(cropGrowth);\n    }\n\n    @Override\n    public double getCropGrowthRaw() {\n        return this.handle.getCropGrowthRaw();\n    }\n\n    @Override\n    public double getSpawnerRatesMultiplier() {\n        return this.handle.getSpawnerRatesMultiplier();\n    }\n\n    @Override\n    public void setSpawnerRatesMultiplier(double spawnerRates) {\n        this.handle.setSpawnerRatesMultiplier(spawnerRates);\n    }\n\n    @Override\n    public double getSpawnerRatesRaw() {\n        return this.handle.getSpawnerRatesRaw();\n    }\n\n    @Override\n    public double getMobDropsMultiplier() {\n        return this.handle.getMobDropsMultiplier();\n    }\n\n    @Override\n    public void setMobDropsMultiplier(double mobDrops) {\n        this.handle.setMobDropsMultiplier(mobDrops);\n    }\n\n    @Override\n    public double getMobDropsRaw() {\n        return this.handle.getMobDropsRaw();\n    }\n\n    @Override\n    public int getBlockLimit(Key key) {\n        return this.handle.getBlockLimit(key);\n    }\n\n    @Override\n    public int getExactBlockLimit(Key key) {\n        return this.handle.getExactBlockLimit(key);\n    }\n\n    @Override\n    public Key getBlockLimitKey(Key key) {\n        return this.handle.getBlockLimitKey(key);\n    }\n\n    @Override\n    public Map<Key, Integer> getBlocksLimits() {\n        return this.handle.getBlocksLimits();\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomBlocksLimits() {\n        return this.handle.getCustomBlocksLimits();\n    }\n\n    @Override\n    public void clearBlockLimits() {\n        this.handle.clearBlockLimits();\n    }\n\n    @Override\n    public void setBlockLimit(Key key, int limit) {\n        this.handle.setBlockLimit(key, limit);\n    }\n\n    @Override\n    public void removeBlockLimit(Key key) {\n        this.handle.removeBlockLimit(key);\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key) {\n        return this.handle.hasReachedBlockLimit(key);\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key, @Size int amount) {\n        return this.handle.hasReachedBlockLimit(key, amount);\n    }\n\n    @Override\n    public int getEntityLimit(EntityType entityType) {\n        return this.handle.getEntityLimit(entityType);\n    }\n\n    @Override\n    public int getEntityLimit(Key key) {\n        return this.handle.getEntityLimit(key);\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesLimitsAsKeys() {\n        return this.handle.getEntitiesLimitsAsKeys();\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomEntitiesLimits() {\n        return this.handle.getCustomEntitiesLimits();\n    }\n\n    @Override\n    public void clearEntitiesLimits() {\n        this.handle.clearEntitiesLimits();\n    }\n\n    @Override\n    public void setEntityLimit(EntityType entityType, int limit) {\n        this.handle.setEntityLimit(entityType, limit);\n    }\n\n    @Override\n    public void setEntityLimit(Key key, int limit) {\n        this.handle.setEntityLimit(key, limit);\n    }\n\n    @Override\n    public void removeEntityLimit(Key key) {\n        this.handle.removeEntityLimit(key);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType) {\n        return this.handle.hasReachedEntityLimit(entityType);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key) {\n        return this.handle.hasReachedEntityLimit(key);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType, @Size int amount) {\n        return this.handle.hasReachedEntityLimit(entityType, amount);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key, @Size int amount) {\n        return this.handle.hasReachedEntityLimit(key, amount);\n    }\n\n    @Override\n    public IslandEntitiesTrackerAlgorithm getEntitiesTracker() {\n        return this.handle.getEntitiesTracker();\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return this.handle.getTeamLimit();\n    }\n\n    @Override\n    public void setTeamLimit(int teamLimit) {\n        this.handle.setTeamLimit(teamLimit);\n    }\n\n    @Override\n    public int getTeamLimitRaw() {\n        return this.handle.getTeamLimitRaw();\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return this.handle.getWarpsLimit();\n    }\n\n    @Override\n    public void setWarpsLimit(int warpsLimit) {\n        this.handle.setWarpsLimit(warpsLimit);\n    }\n\n    @Override\n    public int getWarpsLimitRaw() {\n        return this.handle.getWarpsLimitRaw();\n    }\n\n    @Override\n    public void setPotionEffect(PotionEffectType type, int level) {\n        this.handle.setPotionEffect(type, level);\n    }\n\n    @Override\n    public void removePotionEffect(PotionEffectType type) {\n        this.handle.removePotionEffect(type);\n    }\n\n    @Override\n    public int getPotionEffectLevel(PotionEffectType type) {\n        return this.handle.getPotionEffectLevel(type);\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getPotionEffects() {\n        return this.handle.getPotionEffects();\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getCustomPotionEffects() {\n        return this.handle.getCustomPotionEffects();\n    }\n\n    @Override\n    public void applyEffects(SuperiorPlayer superiorPlayer) {\n        this.handle.applyEffects(superiorPlayer);\n    }\n\n    @Override\n    public void applyEffects() {\n        this.handle.applyEffects();\n    }\n\n    @Override\n    public void removeEffects(SuperiorPlayer superiorPlayer) {\n        this.handle.removeEffects(superiorPlayer);\n    }\n\n    @Override\n    public void removeEffects() {\n        this.handle.removeEffects();\n    }\n\n    @Override\n    public void clearEffects() {\n        this.handle.clearEffects();\n    }\n\n    @Override\n    public void setRoleLimit(PlayerRole playerRole, int limit) {\n        this.handle.setRoleLimit(playerRole, limit);\n    }\n\n    @Override\n    public void removeRoleLimit(PlayerRole playerRole) {\n        this.handle.removeRoleLimit(playerRole);\n    }\n\n    @Override\n    public int getRoleLimit(PlayerRole playerRole) {\n        return this.handle.getRoleLimit(playerRole);\n    }\n\n    @Override\n    public int getRoleLimitRaw(PlayerRole playerRole) {\n        return this.handle.getRoleLimitRaw(playerRole);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getRoleLimits() {\n        return this.handle.getRoleLimits();\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getCustomRoleLimits() {\n        return this.handle.getCustomRoleLimits();\n    }\n\n    @Override\n    public WarpCategory createWarpCategory(String name) {\n        return this.handle.createWarpCategory(name);\n    }\n\n    @Nullable\n    @Override\n    public WarpCategory getWarpCategory(String name) {\n        return this.handle.getWarpCategory(name);\n    }\n\n    @Nullable\n    @Override\n    public WarpCategory getWarpCategory(int slot) {\n        return this.handle.getWarpCategory(slot);\n    }\n\n    @Override\n    public void renameCategory(WarpCategory warpCategory, String newName) {\n        this.handle.renameCategory(warpCategory, newName);\n    }\n\n    @Override\n    public void deleteCategory(WarpCategory warpCategory) {\n        this.handle.deleteCategory(warpCategory);\n    }\n\n    @Override\n    public Map<String, WarpCategory> getWarpCategories() {\n        return this.handle.getWarpCategories();\n    }\n\n    @Override\n    public IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory) {\n        return this.handle.createWarp(name, location, warpCategory);\n    }\n\n    @Override\n    public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, WarpCategory warpCategory) {\n        return this.handle.createWarp(name, worldInfo, position, warpCategory);\n    }\n\n    @Override\n    public void renameWarp(IslandWarp islandWarp, String newName) {\n        this.handle.renameWarp(islandWarp, newName);\n    }\n\n    @Nullable\n    @Override\n    public IslandWarp getWarp(Location location) {\n        return this.handle.getWarp(location);\n    }\n\n    @Nullable\n    @Override\n    public IslandWarp getWarp(String name) {\n        return this.handle.getWarp(name);\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) {\n        this.handle.warpPlayer(superiorPlayer, warpName);\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) {\n        this.handle.warpPlayer(superiorPlayer, warpName, force);\n    }\n\n    @Override\n    public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) {\n        this.handle.deleteWarp(superiorPlayer, location);\n    }\n\n    @Override\n    public void deleteWarp(String name) {\n        this.handle.deleteWarp(name);\n    }\n\n    @Override\n    public Map<String, IslandWarp> getIslandWarps() {\n        return this.handle.getIslandWarps();\n    }\n\n    @Override\n    public Rating getRating(SuperiorPlayer superiorPlayer) {\n        return this.handle.getRating(superiorPlayer);\n    }\n\n    @Override\n    public void setRating(SuperiorPlayer superiorPlayer, Rating rating) {\n        this.handle.setRating(superiorPlayer, rating);\n    }\n\n    @Override\n    public void removeRating(SuperiorPlayer superiorPlayer) {\n        this.handle.removeRating(superiorPlayer);\n    }\n\n    @Override\n    public double getTotalRating() {\n        return this.handle.getTotalRating();\n    }\n\n    @Override\n    public int getRatingAmount() {\n        return this.handle.getRatingAmount();\n    }\n\n    @Override\n    public Map<UUID, Rating> getRatings() {\n        return this.handle.getRatings();\n    }\n\n    @Override\n    public void removeRatings() {\n        this.handle.removeRatings();\n    }\n\n    @Override\n    public boolean hasSettingsEnabled(IslandFlag islandFlag) {\n        return this.handle.hasSettingsEnabled(islandFlag);\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> getAllSettings() {\n        return this.handle.getAllSettings();\n    }\n\n    @Override\n    public void enableSettings(IslandFlag islandFlag) {\n        this.handle.enableSettings(islandFlag);\n    }\n\n    @Override\n    public void disableSettings(IslandFlag islandFlag) {\n        this.handle.disableSettings(islandFlag);\n    }\n\n    @Override\n    public void resetSettings() {\n        this.handle.resetSettings();\n    }\n\n    @Override\n    public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) {\n        this.handle.setGeneratorPercentage(key, percentage, dimension);\n    }\n\n    @Override\n    public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension,\n                                          @Nullable SuperiorPlayer caller, boolean callEvent) {\n        return this.handle.setGeneratorPercentage(key, percentage, dimension, caller, callEvent);\n    }\n\n    @Override\n    public int getGeneratorPercentage(Key key, Dimension dimension) {\n        return this.handle.getGeneratorPercentage(key, dimension);\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorPercentages(Dimension dimension) {\n        return this.handle.getGeneratorPercentages(dimension);\n    }\n\n    @Override\n    public void setGeneratorAmount(Key key, int amount, Dimension dimension) {\n        this.handle.setGeneratorAmount(key, amount, dimension);\n    }\n\n    @Override\n    public void removeGeneratorAmount(Key key, Dimension dimension) {\n        this.handle.removeGeneratorAmount(key, dimension);\n    }\n\n    @Override\n    public int getGeneratorAmount(Key key, Dimension dimension) {\n        return this.handle.getGeneratorAmount(key, dimension);\n    }\n\n    @Override\n    public int getGeneratorTotalAmount(Dimension dimension) {\n        return this.handle.getGeneratorTotalAmount(dimension);\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorAmounts(Dimension dimension) {\n        return this.handle.getGeneratorAmounts(dimension);\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomGeneratorAmounts(Dimension dimension) {\n        return this.handle.getCustomGeneratorAmounts(dimension);\n    }\n\n    @Override\n    public void clearGeneratorAmounts(Dimension dimension) {\n        this.handle.clearGeneratorAmounts(dimension);\n    }\n\n    @Nullable\n    @Override\n    public Key generateBlock(Location location, boolean optimizeDefaultBlock) {\n        return this.handle.generateBlock(location, optimizeDefaultBlock);\n    }\n\n    @Override\n    public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) {\n        return this.handle.generateBlock(location, dimension, optimizeDefaultBlock);\n    }\n\n    @Override\n    public boolean wasSchematicGenerated(Dimension dimension) {\n        return this.handle.wasSchematicGenerated(dimension);\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension) {\n        this.handle.setSchematicGenerate(dimension);\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension, boolean generated) {\n        this.handle.setSchematicGenerate(dimension, generated);\n    }\n\n    @Override\n    public Collection<Dimension> getGeneratedSchematics() {\n        return this.handle.getGeneratedSchematics();\n    }\n\n    @Override\n    public String getSchematicName() {\n        return this.handle.getSchematicName();\n    }\n\n    @Override\n    public int getPosition(SortingType sortingType) {\n        return this.handle.getPosition(sortingType);\n    }\n\n    @Override\n    public IslandChest[] getChest() {\n        return this.handle.getChest();\n    }\n\n    @Override\n    public int getChestSize() {\n        return this.handle.getChestSize();\n    }\n\n    @Override\n    public void setChestRows(int index, int rows) {\n        this.handle.setChestRows(index, rows);\n    }\n\n    @Override\n    public int compareTo(Island o) {\n        return this.handle.compareTo(o);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\n\npublic class DelegateIslandChest implements IslandChest {\n\n    protected final IslandChest handle;\n\n    protected DelegateIslandChest(IslandChest handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public Island getIsland() {\n        return this.handle.getIsland();\n    }\n\n    @Override\n    public int getIndex() {\n        return this.handle.getIndex();\n    }\n\n    @Override\n    public int getRows() {\n        return this.handle.getRows();\n    }\n\n    @Override\n    public void setRows(int rows) {\n        this.handle.setRows(rows);\n    }\n\n    @Override\n    public ItemStack[] getContents() {\n        return this.handle.getContents();\n    }\n\n    @Override\n    public void openChest(SuperiorPlayer superiorPlayer) {\n        this.handle.openChest(superiorPlayer);\n    }\n\n    @Override\n    public Inventory getInventory() {\n        return this.handle.getInventory();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\n\npublic class DelegateIslandPreview implements IslandPreview {\n\n    protected final IslandPreview handle;\n\n    protected DelegateIslandPreview(IslandPreview handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public SuperiorPlayer getPlayer() {\n        return this.handle.getPlayer();\n    }\n\n    @Override\n    public Location getLocation() {\n        return this.handle.getLocation();\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        return this.handle.getLocation(location);\n    }\n\n    @Override\n    public String getSchematic() {\n        return this.handle.getSchematic();\n    }\n\n    @Override\n    public String getIslandName() {\n        return this.handle.getIslandName();\n    }\n\n    @Override\n    public GameMode getPreviousGameMode() {\n        return this.handle.getPreviousGameMode();\n    }\n\n    @Override\n    public void handleConfirm() {\n        this.handle.handleConfirm();\n    }\n\n    @Override\n    public void handleCancel() {\n        this.handle.handleCancel();\n    }\n\n    @Override\n    public void handleEscape() {\n        this.handle.handleEscape();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport java.util.Map;\n\npublic class DelegatePermissionNode implements PermissionNode {\n\n    protected final PermissionNode handle;\n\n    protected DelegatePermissionNode(PermissionNode handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege islandPrivilege) {\n        return this.handle.hasPermission(islandPrivilege);\n    }\n\n    @Override\n    public void setPermission(IslandPrivilege islandPrivilege, boolean value) {\n        this.handle.setPermission(islandPrivilege, value);\n    }\n\n    @Override\n    public Map<IslandPrivilege, Boolean> getCustomPermissions() {\n        return this.handle.getCustomPermissions();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.annotations.Size;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder;\nimport com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.enums.SyncStatus;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic interface Island extends Comparable<Island>, IMissionsHolder, IPersistentDataHolder, IDatabaseBridgeHolder {\n\n    /*\n     *  General methods\n     */\n\n    /**\n     * Get the owner of the island.\n     */\n    SuperiorPlayer getOwner();\n\n    /**\n     * Get the unique-id of the island.\n     */\n    UUID getUniqueId();\n\n    /**\n     * Get the creation time of the island.\n     */\n    long getCreationTime();\n\n    /**\n     * Get the creation time of the island, in a formatted string.\n     */\n    String getCreationTimeDate();\n\n    /**\n     * Re-sync the island with a new dates formatter.\n     */\n    void updateDatesFormatter();\n\n    /**\n     * Get the island cache.\n     */\n    IslandCache getCache();\n\n    /*\n     *  Player related methods\n     */\n\n    /**\n     * Get the list of members of the island.\n     *\n     * @param includeOwner Whether the owner should be returned.\n     */\n    List<SuperiorPlayer> getIslandMembers(boolean includeOwner);\n\n    /**\n     * Get the list of members of the island with specific roles.\n     *\n     * @param playerRoles The roles to filter with.\n     */\n    List<SuperiorPlayer> getIslandMembers(PlayerRole... playerRoles);\n\n    /**\n     * Get the list of all banned players.\n     */\n    List<SuperiorPlayer> getBannedPlayers();\n\n    /**\n     * Get the list of all visitors that are on the island, including vanished ones.\n     */\n    List<SuperiorPlayer> getIslandVisitors();\n\n    /**\n     * Get the list of all visitors that are on the island.\n     *\n     * @param vanishPlayers Should vanish players be included?\n     */\n    List<SuperiorPlayer> getIslandVisitors(boolean vanishPlayers);\n\n    /**\n     * Get the list of all the players that are on the island.\n     */\n    List<SuperiorPlayer> getAllPlayersInside();\n\n    /**\n     * Get all the visitors that visited the island until now.\n     */\n    List<SuperiorPlayer> getUniqueVisitors();\n\n    /**\n     * Get all the visitors that visited the island until now, with the time they last visited.\n     */\n    List<Pair<SuperiorPlayer, Long>> getUniqueVisitorsWithTimes();\n\n    /**\n     * Invite a player to the island.\n     *\n     * @param superiorPlayer The player to invite.\n     */\n    void inviteMember(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Revoke an invitation of a player.\n     *\n     * @param superiorPlayer The player to revoke his invite.\n     */\n    void revokeInvite(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Checks whether the player has been invited to the island.\n     */\n    boolean isInvited(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get all the invited players of the island.\n     */\n    List<SuperiorPlayer> getInvitedPlayers();\n\n    /**\n     * Add a player to the island.\n     *\n     * @param superiorPlayer The player to add.\n     * @param playerRole     The role to give to the player.\n     */\n    void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole);\n\n    /**\n     * Kick a member from the island.\n     *\n     * @param superiorPlayer The player to kick.\n     * @deprecated See {@link #removeMember(SuperiorPlayer, MemberRemoveReason)}\n     */\n    @Deprecated\n    void kickMember(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Remove a member from the island.\n     *\n     * @param superiorPlayer     The player to remove.\n     * @param memberRemoveReason The reason for removal.\n     */\n    void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason);\n\n    /**\n     * Check whether a player is a member of the island.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    boolean isMember(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Ban a member from the island.\n     *\n     * @param superiorPlayer The player to ban.\n     */\n    void banMember(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Ban a member from the island.\n     *\n     * @param superiorPlayer The player to ban.\n     * @param whom           The player that executed the ban command.\n     *                       If null, CONSOLE will be chosen as the banner.\n     */\n    void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom);\n\n    /**\n     * Unban a player from the island.\n     *\n     * @param superiorPlayer The player to unban.\n     */\n    void unbanMember(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Checks whether a player is banned from the island.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    boolean isBanned(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Add a player to the island as a co-op member.\n     *\n     * @param superiorPlayer The player to add.\n     */\n    void addCoop(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Remove a player from being a co-op member.\n     *\n     * @param superiorPlayer The player to remove.\n     */\n    void removeCoop(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Check whether a player is a co-op member of the island.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    boolean isCoop(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the list of all co-op players.\n     */\n    List<SuperiorPlayer> getCoopPlayers();\n\n    /**\n     * Get the coop players limit of the island.\n     */\n    int getCoopLimit();\n\n    /**\n     * Get the coop players limit of the island that was set using a command.\n     */\n    int getCoopLimitRaw();\n\n    /**\n     * Set the coop players limit of the island.\n     *\n     * @param coopLimit The coop players limit to set.\n     */\n    void setCoopLimit(int coopLimit);\n\n    /**\n     * Update status of a player if he's inside the island or not.\n     *\n     * @param superiorPlayer The player to add.\n     */\n    void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside);\n\n    /**\n     * Check whether a player is a visitor of the island or not.\n     *\n     * @param superiorPlayer  The player to check.\n     * @param checkCoopStatus Whether to check for coop status or not.\n     *                        If enabled, coops will not be considered as visitors.\n     */\n    boolean isVisitor(SuperiorPlayer superiorPlayer, boolean checkCoopStatus);\n\n    /*\n     *  Location related methods\n     */\n\n    /**\n     * Get the center location of the island, depends on the world dimension.\n     *\n     * @param dimension The dimension.\n     */\n    Location getCenter(Dimension dimension);\n\n    /**\n     * Get the center position of the island.\n     */\n    BlockPosition getCenterPosition();\n\n    /**\n     * Access the island's world.\n     * This method will load the world safely if it is not loaded.\n     *\n     * @param dimension The dimension of the island world.\n     */\n    CompletableFuture<World> accessIslandWorld(Dimension dimension);\n\n    /**\n     * Get the members' home location of the island, depends on the world dimension.\n     *\n     * @param dimension The dimension.\n     */\n    @Nullable\n    Location getIslandHome(Dimension dimension);\n\n    /**\n     * Get the members' home location of the island, depends on the world dimension.\n     *\n     * @param dimension The dimension.\n     */\n    @Nullable\n    WorldPosition getIslandHomePosition(Dimension dimension);\n\n    /**\n     * Get all the home locations of the island.\n     * If the world is not loaded, the location's getWorld will return null.\n     */\n    Map<Dimension, Location> getIslandHomesAsDimensions();\n\n    /**\n     * Get all the home positions of the island.\n     */\n    Map<Dimension, WorldPosition> getIslandHomes();\n\n    /**\n     * Set the home location of the island.\n     * The location will be set for the world provided in {@param homeLocation}\n     *\n     * @param homeLocation The new home location.\n     */\n    void setIslandHome(Location homeLocation);\n\n    /**\n     * Set the home position of the island.\n     * The world of {@param homeLocation} is ignored.\n     *\n     * @param dimension    The dimension to change home position for.\n     * @param homeLocation The new home location.\n     * @deprecated See {@link #setIslandHome(Dimension, WorldPosition)}\n     */\n    @Deprecated\n    void setIslandHome(Dimension dimension, @Nullable Location homeLocation);\n\n    /**\n     * Set the home position of the island.\n     *\n     * @param dimension    The dimension to change home position for.\n     * @param homePosition The new home position.\n     */\n    void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition);\n\n    /**\n     * Get the visitors' teleport location of the island.\n     * If the world is unloaded, the location's getWorld method will return null.\n     *\n     * @param dimension The dimension to get the visitors-location from.\n     *                  Currently unused, it has no effect.\n     */\n    @Nullable\n    Location getVisitorsLocation(Dimension dimension);\n\n    /**\n     * Get the visitors' teleport position of the island.\n     *\n     * @param dimension The dimension to get the visitors-position from.\n     *                  Currently unused, it has no effect.\n     */\n    @Nullable\n    WorldPosition getVisitorsPosition(Dimension dimension);\n\n    /**\n     * Set the visitors' teleport location of the island.\n     *\n     * @param visitorsLocation The new visitors location.\n     */\n    void setVisitorsLocation(@Nullable Location visitorsLocation);\n\n    /**\n     * Set the visitors' teleport position of the island.\n     *\n     * @param dimension        The dimension to change the visitors-position.\n     *                         Currently unused, it has no effect.\n     * @param visitorsPosition The new visitors position.\n     */\n    void setVisitorsLocation(Dimension dimension, @Nullable WorldPosition visitorsPosition);\n\n    /**\n     * Get the minimum location of the island.\n     * If the world is unloaded, the location's getWorld will return null.\n     */\n    Location getMinimum();\n\n    /**\n     * Get the minimum location of the island.\n     */\n    BlockPosition getMinimumPosition();\n\n    /**\n     * Get the minimum protected location of the island.\n     * If the world is unloaded, the location's getWorld will return null.\n     */\n    Location getMinimumProtected();\n\n    /**\n     * Get the minimum location of the island.\n     */\n    BlockPosition getMinimumProtectedPosition();\n\n    /**\n     * Get the maximum location of the island.\n     * If the world is unloaded, the location's getWorld will return null.\n     */\n    Location getMaximum();\n\n    /**\n     * Get the maximum location of the island.\n     */\n    BlockPosition getMaximumPosition();\n\n    /**\n     * Get the minimum protected location of the island.\n     * If the world is unloaded, the location's getWorld will return null.\n     */\n    Location getMaximumProtected();\n\n    /**\n     * Get the minimum protected location of the island.\n     */\n    BlockPosition getMaximumProtectedPosition();\n\n    /**\n     * Get all the chunks of the island from all the environments.\n     * Similar to {@link #getAllChunks(int)} with 0 as flags parameter.\n     */\n    List<Chunk> getAllChunks();\n\n    /**\n     * Get all the chunks of the island from all the environments.\n     *\n     * @param flags See {@link IslandChunkFlags}\n     */\n    List<Chunk> getAllChunks(@IslandChunkFlags int flags);\n\n    /**\n     * Get all the chunks of the island.\n     * Similar to {@link #getAllChunks(Dimension, int)} with 0 as flags parameter.\n     *\n     * @param dimension The environment to get the chunks from.\n     */\n    List<Chunk> getAllChunks(Dimension dimension);\n\n    /**\n     * Get all the chunks of the island.\n     *\n     * @param dimension The dimension to get the chunks from.\n     * @param flags     See {@link IslandChunkFlags}\n     */\n    List<Chunk> getAllChunks(Dimension dimension, @IslandChunkFlags int flags);\n\n    /**\n     * Get all the loaded chunks of the island.\n     * Similar to {@link #getLoadedChunks(int)} with 0 as flags parameter.\n     */\n    List<Chunk> getLoadedChunks();\n\n    /**\n     * Get all the loaded chunks of the island.\n     *\n     * @param flags See {@link IslandChunkFlags}\n     */\n    List<Chunk> getLoadedChunks(@IslandChunkFlags int flags);\n\n    /**\n     * Get all the loaded chunks of the island.\n     * Similar to {@link #getLoadedChunks(Dimension, int)} with 0 as flags parameter.\n     *\n     * @param dimension The environment to get the chunks from.\n     */\n    List<Chunk> getLoadedChunks(Dimension dimension);\n\n    /**\n     * Get all the loaded chunks of the island.\n     *\n     * @param dimension The dimension to get the chunks from.\n     * @param flags     See {@link IslandChunkFlags}\n     */\n    List<Chunk> getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags);\n\n    /**\n     * Get all the chunks of the island asynchronized, including empty chunks.\n     * Similar to {@link #getAllChunksAsync(Dimension, int, Consumer)}, with 0 as flags parameter.\n     *\n     * @param dimension The dimension to get the chunks from.\n     */\n    List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension);\n\n    /**\n     * Get all the chunks of the island asynchronized, including empty chunks.\n     *\n     * @param dimension The dimension to get the chunks from.\n     * @param flags     See {@link IslandChunkFlags}\n     */\n    List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags);\n\n    /**\n     * Get all the chunks of the island asynchronized, including empty chunks.\n     * Similar to {@link #getAllChunksAsync(Dimension, int, Consumer)}, with 0 as flags parameter.\n     *\n     * @param dimension   The dimension to get the chunks from.\n     * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null.\n     */\n    List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @Nullable Consumer<Chunk> onChunkLoad);\n\n    /**\n     * Get all the chunks of the island asynchronized, including empty chunks.\n     *\n     * @param dimension   The dimension to get the chunks from.\n     * @param flags       See {@link IslandChunkFlags}\n     * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null.\n     */\n    List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags,\n                                                     @Nullable Consumer<Chunk> onChunkLoad);\n\n    /**\n     * Reset all the chunks of the island from all the worlds (will make all chunks empty).\n     * Similar to {@link #resetChunks(int)}, with 0 as flags parameter.\n     */\n    void resetChunks();\n\n    /**\n     * Reset all the chunks of the island from all the worlds (will make all chunks empty).\n     * Similar to {@link #resetChunks(int, Runnable)}, with 0 as flags parameter.\n     *\n     * @param onFinish Callback runnable.\n     */\n    void resetChunks(@Nullable Runnable onFinish);\n\n    /**\n     * Reset all the chunks of the island (will make all chunks empty).\n     * Similar to {@link #resetChunks(Dimension, int)}, with 0 as flags parameter.\n     *\n     * @param dimension The dimension to reset chunks in.\n     */\n    void resetChunks(Dimension dimension);\n\n    /**\n     * Reset all the chunks of the island (will make all chunks empty).\n     *\n     * @param dimension The dimension to reset chunks in.\n     * @param onFinish  Callback runnable.\n     */\n    void resetChunks(Dimension dimension, @Nullable Runnable onFinish);\n\n    /**\n     * Reset all the chunks of the island from all the worlds (will make all chunks empty).\n     *\n     * @param flags See {@link IslandChunkFlags}\n     */\n    void resetChunks(@IslandChunkFlags int flags);\n\n    /**\n     * Reset all the chunks of the island from all the worlds (will make all chunks empty).\n     *\n     * @param flags    See {@link IslandChunkFlags}\n     * @param onFinish Callback runnable.\n     */\n    void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish);\n\n    /**\n     * Reset all the chunks of the island (will make all chunks empty).\n     *\n     * @param dimension The dimension to reset chunks in.\n     * @param flags     See {@link IslandChunkFlags}\n     */\n    void resetChunks(Dimension dimension, @IslandChunkFlags int flags);\n\n    /**\n     * Reset all the chunks of the island (will make all chunks empty).\n     *\n     * @param dimension The dimension to reset chunks in.\n     * @param flags     See {@link IslandChunkFlags}\n     * @param onFinish  Callback runnable.\n     */\n    void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish);\n\n    /**\n     * Check if the location is inside the island's area.\n     * Similar to {@link #isInside(Location, int)} or {@link #isInside(Location, double)} with extraRadius set to 0.\n     *\n     * @param location The location to check.\n     */\n    boolean isInside(Location location);\n\n    /**\n     * Check if the location is inside the island's area.\n     *\n     * @param location    The location to check.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(Location location, int extraRadius);\n\n    /**\n     * Check if the location is inside the island's area.\n     *\n     * @param location    The location to check.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(Location location, double extraRadius);\n\n    /**\n     * Check if the location is inside the island's area.\n     * The world is ignored in this case.\n     * Similar to {@link #isInside(BlockPosition, int)} or {@link #isInside(BlockPosition, double)} with extraRadius set to 0.\n     *\n     * @param blockPosition The position to check.\n     */\n    boolean isInside(BlockPosition blockPosition);\n\n    /**\n     * Check if the position is inside the island's area.\n     * The world is ignored in this case.\n     *\n     * @param blockPosition The position to check.\n     * @param extraRadius   Add extra radius to the range.\n     */\n    boolean isInside(BlockPosition blockPosition, int extraRadius);\n\n    /**\n     * Check if the position is inside the island's area.\n     *\n     * @param blockPosition The position to check.\n     * @param extraRadius   Add extra radius to the range.\n     */\n    boolean isInside(BlockPosition blockPosition, double extraRadius);\n\n    /**\n     * Check if the location is inside the island's area.\n     * The world is ignored in this case.\n     * Similar to {@link #isInside(WorldPosition, int)} or {@link #isInside(WorldPosition, double)} with extraRadius set to 0.\n     *\n     * @param worldPosition The position to check.\n     */\n    boolean isInside(WorldPosition worldPosition);\n\n    /**\n     * Check if the position is inside the island's area.\n     * The world is ignored in this case.\n     *\n     * @param worldPosition The position to check.\n     * @param extraRadius   Add extra radius to the range.\n     */\n    boolean isInside(WorldPosition worldPosition, int extraRadius);\n\n    /**\n     * Check if the position is inside the island's area.\n     *\n     * @param worldPosition The position to check.\n     * @param extraRadius   Add extra radius to the range.\n     */\n    boolean isInside(WorldPosition worldPosition, double extraRadius);\n\n    /**\n     * Check if a chunk is inside the island's area.\n     * Similar to {@link #isInside(World, int, int)}\n     *\n     * @param chunk The chunk to check.\n     */\n    boolean isInside(Chunk chunk);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    boolean isInside(World world, int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     *\n     * @param world       The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(World world, int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     *\n     * @param world       The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(World world, int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0.\n     *\n     * @param worldInfo The world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     */\n    boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     *\n     * @param worldInfo   The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's area.\n     *\n     * @param worldInfo   The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Check if a chunk position is inside the island's area.\n     * The world in this case is ignored.\n     * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0.\n     *\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    boolean isInside(int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk position is inside the island's area.\n     * The world in this case is ignored.\n     *\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk position is inside the island's area.\n     * The world in this case is ignored.\n     *\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the range.\n     */\n    boolean isInside(int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Check if the location is inside the island's protected area.\n     *\n     * @param location The location to check.\n     */\n    boolean isInsideRange(Location location);\n\n    /**\n     * Check if the location is inside the island's protected area.\n     *\n     * @param location    The location to check.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(Location location, int extraRadius);\n\n    /**\n     * Check if the location is inside the island's protected area.\n     *\n     * @param location    The location to check.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(Location location, double extraRadius);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param blockPosition The position to check.\n     */\n    boolean isInsideRange(BlockPosition blockPosition);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param blockPosition The position to check.\n     * @param extraRadius   Add extra radius to the protected range.\n     */\n    boolean isInsideRange(BlockPosition blockPosition, int extraRadius);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param blockPosition The position to check.\n     * @param extraRadius   Add extra radius to the protected range.\n     */\n    boolean isInsideRange(BlockPosition blockPosition, double extraRadius);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param worldPosition The position to check.\n     */\n    boolean isInsideRange(WorldPosition worldPosition);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param worldPosition The position to check.\n     * @param extraRadius   Add extra radius to the protected range.\n     */\n    boolean isInsideRange(WorldPosition worldPosition, int extraRadius);\n\n    /**\n     * Check if the position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param worldPosition The position to check.\n     * @param extraRadius   Add extra radius to the protected range.\n     */\n    boolean isInsideRange(WorldPosition worldPosition, double extraRadius);\n\n    /**\n     * Check if the chunk is inside the island's protected area.\n     *\n     * @param chunk The chunk to check.\n     */\n    boolean isInsideRange(Chunk chunk);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    boolean isInsideRange(World world, int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     *\n     * @param world       The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     *\n     * @param world       The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0.\n     *\n     * @param worldInfo The world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     */\n    boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     *\n     * @param worldInfo   The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk location is inside the island's protected area.\n     *\n     * @param worldInfo   The world of the chunk.\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Check if a chunk position is inside the island's protected area.\n     * The world in this case is ignored.\n     * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0.\n     *\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    boolean isInsideRange(int chunkX, int chunkZ);\n\n    /**\n     * Check if a chunk position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(int chunkX, int chunkZ, int extraRadius);\n\n    /**\n     * Check if a chunk position is inside the island's protected area.\n     * The world in this case is ignored.\n     *\n     * @param chunkX      The x-coords of the chunk.\n     * @param chunkZ      The z-coords of the chunk.\n     * @param extraRadius Add extra radius to the protected range.\n     */\n    boolean isInsideRange(int chunkX, int chunkZ, double extraRadius);\n\n    /**\n     * Is the normal world enabled for the island?\n     *\n     * @deprecated See {@link #isDimensionEnabled(Dimension)}\n     */\n    @Deprecated\n    boolean isNormalEnabled();\n\n    /**\n     * Enable/disable the normal world for the island.\n     *\n     * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)}\n     */\n    @Deprecated\n    void setNormalEnabled(boolean enabled);\n\n    /**\n     * Is the nether world enabled for the island?\n     *\n     * @deprecated See {@link #isDimensionEnabled(Dimension)}\n     */\n    @Deprecated\n    boolean isNetherEnabled();\n\n    /**\n     * Enable/disable the nether world for the island.\n     *\n     * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)}\n     */\n    @Deprecated\n    void setNetherEnabled(boolean enabled);\n\n    /**\n     * Is the end world enabled for the island?\n     *\n     * @deprecated See {@link #isDimensionEnabled(Dimension)}\n     */\n    @Deprecated\n    boolean isEndEnabled();\n\n    /**\n     * Enable/disable the end world for the island.\n     *\n     * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)}\n     */\n    @Deprecated\n    void setEndEnabled(boolean enabled);\n\n    /**\n     * Checks if a specific dimension is enabled for the island\n     *\n     * @param dimension The dimension to check.\n     */\n    boolean isDimensionEnabled(Dimension dimension);\n\n    /**\n     * Enable/disable a world for the island.\n     *\n     * @param dimension The dimension to enable/disable.\n     * @param enabled   Status.\n     */\n    void setDimensionEnabled(Dimension dimension, boolean enabled);\n\n    /**\n     * Get the unlocked worlds.\n     */\n    Collection<Dimension> getUnlockedWorlds();\n\n    /*\n     *  Permissions related methods\n     */\n\n    /**\n     * Check if a CommandSender has a permission.\n     *\n     * @param sender          The command-sender to check.\n     * @param islandPrivilege The permission to check.\n     */\n    boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege);\n\n    /**\n     * Check if a player has a permission.\n     *\n     * @param superiorPlayer  The player to check.\n     * @param islandPrivilege The permission to check.\n     */\n    boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege);\n\n    /**\n     * Check if a role has a permission.\n     *\n     * @param playerRole      The role to check.\n     * @param islandPrivilege The permission to check.\n     */\n    boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege);\n\n    /**\n     * Set a permission to a specific role.\n     *\n     * @param playerRole      The role to set the permission to.\n     * @param islandPrivilege The permission to set.\n     * @param value           The value to give the permission (Unused)\n     * @deprecated See {@link #setPermission(PlayerRole, IslandPrivilege)}\n     */\n    @Deprecated\n    void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value);\n\n    /**\n     * Set a permission to a specific role.\n     *\n     * @param playerRole      The role to set the permission to.\n     * @param islandPrivilege The permission to set.\n     */\n    void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege);\n\n    /**\n     * Reset the roles permissions to default values.\n     */\n    void resetPermissions();\n\n    /**\n     * Set a permission to a specific player.\n     *\n     * @param superiorPlayer  The player to set the permission to.\n     * @param islandPrivilege The permission to set.\n     * @param value           The value to give the permission.\n     */\n    void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value);\n\n    /**\n     * Reset player permissions to default values.\n     */\n    void resetPermissions(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the permission-node of a player.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    PermissionNode getPermissionNode(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the required role for a specific permission.\n     *\n     * @param islandPrivilege The permission to check.\n     */\n    PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege);\n\n    /**\n     * Get all the custom player permissions of the island.\n     */\n    Map<SuperiorPlayer, PermissionNode> getPlayerPermissions();\n\n    /**\n     * Get the permissions and their required roles.\n     */\n    Map<IslandPrivilege, PlayerRole> getRolePermissions();\n\n    /*\n     *  General methods\n     */\n\n    /**\n     * Checks whether the island is the spawn island.\n     */\n    boolean isSpawn();\n\n    /**\n     * Set the name of the island.\n     *\n     * @param islandName The name to set.\n     */\n    void setName(String islandName);\n\n    /**\n     * Get the name of the island in respect to color-support.\n     * This method will call {@link #getFormattedName()} or {@link #getStrippedName()}, depends on color-support.\n     */\n    String getName();\n\n    /**\n     * Get the name of the island in its stripped form.\n     *\n     * @deprecated See {@link #getStrippedName()}\n     */\n    @Deprecated\n    String getRawName();\n\n    /**\n     * Get the name of the island in its stripped form.\n     * Unlike {@link #getName()}, this method will always return the stripped form of the name.\n     */\n    String getStrippedName();\n\n    /**\n     * Get the name of the island in its color-formatted form.\n     * Unlike {@link #getName()}, this method will always return the color-formatted form of the name.\n     */\n    String getFormattedName();\n\n    /**\n     * Get the description of the island.\n     */\n    String getDescription();\n\n    /**\n     * Set the description of the island.\n     *\n     * @param description The description to set.\n     */\n    void setDescription(String description);\n\n    /**\n     * Disband the island.\n     */\n    void disbandIsland();\n\n    /**\n     * Transfer the island's leadership to another player.\n     *\n     * @param superiorPlayer The player to transfer the leadership to.\n     * @return True if the transfer was succeed, otherwise false.\n     */\n    boolean transferIsland(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Replace a player with a new player.\n     *\n     * @param originalPlayer The old player to be replaced.\n     * @param newPlayer      The new player.\n     *                       If null, the original player should just be removed.\n     *                       If this is the owner of the island, the island will be disbanded.\n     */\n    void replacePlayers(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer);\n\n    /**\n     * Recalculate the island's worth value.\n     *\n     * @param asker The player who makes the operation.\n     */\n    void calcIslandWorth(@Nullable SuperiorPlayer asker);\n\n    /**\n     * Recalculate the island's worth value.\n     *\n     * @param asker    The player who makes the operation.\n     * @param callback Runnable which will be ran when process is finished.\n     */\n    void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback);\n\n    /**\n     * Get the calculation algorithm used by this island.\n     */\n    IslandCalculationAlgorithm getCalculationAlgorithm();\n\n    /**\n     * Update the border of all the players inside the island.\n     */\n    void updateBorder();\n\n    /**\n     * Update the fly status for a player on this island.\n     *\n     * @param superiorPlayer The player to update.\n     */\n    void updateIslandFly(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the island radius of the island.\n     */\n    int getIslandSize();\n\n    /**\n     * Set the radius of the island.\n     *\n     * @param islandSize The radius for the island.\n     */\n    void setIslandSize(int islandSize);\n\n    /**\n     * Get the island radius of the island that was set with a command.\n     */\n    int getIslandSizeRaw();\n\n    /**\n     * Get the discord that is associated with the island.\n     */\n    String getDiscord();\n\n    /**\n     * Set the discord that will be associated with the island.\n     */\n    void setDiscord(String discord);\n\n    /**\n     * Get the paypal that is associated with the island.\n     */\n    String getPaypal();\n\n    /**\n     * Get the paypal that will be associated with the island.\n     */\n    void setPaypal(String paypal);\n\n    /**\n     * The current biome of the island.\n     */\n    Biome getBiome();\n\n    /**\n     * Change the biome of the island's area.\n     */\n    void setBiome(Biome biome);\n\n    /**\n     * Change the biome of the island's area.\n     *\n     * @param updateBlocks Whether the blocks get updated or not.\n     */\n    void setBiome(Biome biome, boolean updateBlocks);\n\n    /**\n     * Check whether the island is locked to visitors.\n     */\n    boolean isLocked();\n\n    /**\n     * Lock or unlock the island to visitors.\n     *\n     * @param locked Whether the island should be locked to visitors.\n     */\n    void setLocked(boolean locked);\n\n    /**\n     * Checks whether the island is ignored in the top islands.\n     */\n    boolean isIgnored();\n\n    /**\n     * Set whether the island should be ignored in the top islands.\n     */\n    void setIgnored(boolean ignored);\n\n    /**\n     * Send a plain message to all the members of the island.\n     *\n     * @param message The message to send\n     */\n    void sendMessage(String message);\n\n    /**\n     * Send a plain message to all the members of the island.\n     *\n     * @param message        The message to send\n     * @param ignoredMembers An array of ignored members.\n     */\n    void sendMessage(String message, UUID... ignoredMembers);\n\n    /**\n     * Send a message to all the members of the island.\n     *\n     * @param messageComponent The message to send\n     */\n    void sendMessage(IMessageComponent messageComponent);\n\n    /**\n     * Send a message to all the members of the island.\n     *\n     * @param messageComponent The message to send\n     * @param args             Arguments for the component.\n     */\n    void sendMessage(IMessageComponent messageComponent, Object... args);\n\n    /**\n     * Send a message to all the members of the island.\n     *\n     * @param messageComponent The message to send\n     * @param ignoredMembers   An array of ignored members.\n     */\n    void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers);\n\n    /**\n     * Send a message to all the members of the island.\n     *\n     * @param messageComponent The message to send\n     * @param ignoredMembers   An array of ignored members.\n     * @param args             Arguments for the component.\n     */\n    void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers, Object... args);\n\n    /**\n     * Send a plain message to all the members of the island.\n     *\n     * @param title    The main title to send.\n     * @param subtitle The sub title to send.\n     * @param fadeIn   The fade-in duration in ticks.\n     * @param duration The title duration in ticks.\n     * @param fadeOut  The fade-out duration in ticks.\n     */\n    void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut);\n\n    /**\n     * Send a plain message to all the members of the island.\n     *\n     * @param title          The main title to send.\n     * @param subtitle       The sub title to send.\n     * @param fadeIn         The fade-in duration in ticks.\n     * @param duration       The title duration in ticks.\n     * @param fadeOut        The fade-out duration in ticks.\n     * @param ignoredMembers An array of ignored members.\n     */\n    void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers);\n\n    /**\n     * Execute a command on all the members of the island.\n     * You can use {player-name} as a placeholder for the member's name.\n     *\n     * @param command           The command to execute.\n     * @param onlyOnlineMembers Whether the command should be executed only for online members.\n     */\n    void executeCommand(String command, boolean onlyOnlineMembers);\n\n    /**\n     * Execute a command on all the members of the island.\n     * You can use {player-name} as a placeholder for the member's name.\n     *\n     * @param command           The command to execute.\n     * @param onlyOnlineMembers Whether the command should be executed only for online members.\n     * @param ignoredMembers    An array of ignored members.\n     */\n    void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers);\n\n    /**\n     * Checks whether the island is being recalculated currently.\n     */\n    boolean isBeingRecalculated();\n\n    /**\n     * Update the last time the island was used.\n     */\n    void updateLastTime();\n\n    /**\n     * Flag the island as a currently active island.\n     */\n    void setCurrentlyActive();\n\n    /**\n     * Set whether the island is currently active.\n     * Active islands are islands that have at least one island member online.\n     *\n     * @param active Whether the island is active.\n     */\n    void setCurrentlyActive(boolean active);\n\n    /**\n     * Check whether the island is currently active.\n     * Active islands are islands that have at least one island member online.\n     */\n    boolean isCurrentlyActive();\n\n    /**\n     * Get the last time the island was updated.\n     * In case the island is active, -1 will be returned.\n     */\n    long getLastTimeUpdate();\n\n    /**\n     * Set the last time the island was updated.\n     *\n     * @param lastTimeUpdate The last time the island was updated.\n     */\n    void setLastTimeUpdate(long lastTimeUpdate);\n\n    /*\n     *  Bank related methods\n     */\n\n    /**\n     * Get the bank of the island.\n     */\n    IslandBank getIslandBank();\n\n    /**\n     * Get the limit of the bank.\n     */\n    BigDecimal getBankLimit();\n\n    /**\n     * Set a new limit for the bank.\n     *\n     * @param bankLimit The limit to set. Use -1 to remove the limit.\n     */\n    void setBankLimit(BigDecimal bankLimit);\n\n    /**\n     * Get the limit of the bank that was set using a command.\n     */\n    BigDecimal getBankLimitRaw();\n\n    /**\n     * Give the bank interest to this island.\n     *\n     * @param checkOnlineOwner Check if the island-owner was online recently.\n     * @return Whether the money was given.\n     */\n    boolean giveInterest(boolean checkOnlineOwner);\n\n    /**\n     * Get the last time that the bank interest was given.\n     */\n    long getLastInterestTime();\n\n    /**\n     * Set the last time that the bank interest was given.\n     *\n     * @param lastInterest The time it was given.\n     */\n    void setLastInterestTime(long lastInterest);\n\n    /**\n     * Get the duration until the bank interest will be given again, in seconds\n     */\n    long getNextInterest();\n\n    /*\n     *  Worth related methods\n     */\n\n    /**\n     * Handle a placement of a block.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block The block that was placed.\n     */\n    void handleBlockPlace(Block block);\n\n    /**\n     * Handle a placement of a block.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block The block that was placed.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Block block);\n\n    /**\n     * Handle a placement of a block's key.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key The block's key that was placed.\n     */\n    void handleBlockPlace(Key key);\n\n    /**\n     * Handle a placement of a block's key.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key The block's key that was placed.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Key key);\n\n    /**\n     * Handle a placement of a block with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block  The block that was placed.\n     * @param amount The amount of the block.\n     */\n    void handleBlockPlace(Block block, @Size int amount);\n\n    /**\n     * Handle a placement of a block with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block  The block that was placed.\n     * @param amount The amount of the block.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     */\n    void handleBlockPlace(Key key, @Size int amount);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount);\n\n    /**\n     * Handle a placement of a block with a specific amount.\n     *\n     * @param block  The block that was placed.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a placement of a block with a specific amount.\n     *\n     * @param block  The block that was placed.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a placement of a block with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param block  The block that was placed.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into database.\n     * @deprecated See {@link #handleBlockPlace(Block, int, int)}\n     */\n    @Deprecated\n    void handleBlockPlace(Block block, @Size int amount, boolean save);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into database.\n     * @deprecated See {@link #handleBlockPlace(Key, int, int)}\n     */\n    @Deprecated\n    void handleBlockPlace(Key key, @Size int amount, boolean save);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param key    The block's key that was placed.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into database.\n     * @deprecated See {@link #handleBlockPlace(Key, int, int)}\n     */\n    @Deprecated\n    void handleBlockPlace(Key key, @Size BigInteger amount, boolean save);\n\n    /**\n     * Handle a placement of a block's key with a specific amount.\n     *\n     * @param key                  The block's key that was placed.\n     * @param amount               The amount of the block.\n     * @param save                 Whether the block counts should be saved into database.\n     * @param updateLastTimeStatus Whether to update last time island was updated or not.\n     * @deprecated See {@link #handleBlockPlace(Key, int, int)}\n     */\n    @Deprecated\n    void handleBlockPlace(Key key, @Size BigInteger amount, boolean save, boolean updateLastTimeStatus);\n\n    /**\n     * Handle placements of many blocks in one time.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param blocks All the blocks to place.\n     */\n    void handleBlocksPlace(Map<Key, Integer> blocks);\n\n    /**\n     * Handle placements of many blocks in one time.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param blocks All the blocks to place.\n     * @return Results per block key. Only non-successful results will be returned.\n     */\n    Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks);\n\n    /**\n     * Handle placements of many blocks in one time.\n     *\n     * @param blocks All the blocks to place.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlocksPlace(Map<Key, Integer> blocks, @IslandBlockFlags int flags);\n\n    /**\n     * Handle placements of many blocks in one time.\n     *\n     * @param blocks All the blocks to place.\n     * @param flags  See {@link IslandBlockFlags}\n     * @return Results per block key. Only non-successful results will be returned.\n     */\n    Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a break of a block.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block The block that was broken.\n     */\n    void handleBlockBreak(Block block);\n\n    /**\n     * Handle a break of a block.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block The block that was broken.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockBreakWithResult(Block block);\n\n    /**\n     * Handle a break of a block's key.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key The block's key that was broken.\n     */\n    void handleBlockBreak(Key key);\n\n    /**\n     * Handle a break of a block's key.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key The block's key that was broken.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockBreakWithResult(Key key);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block  The block that was broken.\n     * @param amount The amount of the block.\n     */\n    void handleBlockBreak(Block block, @Size int amount);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param block  The block that was broken.\n     * @param amount The amount of the block.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount);\n\n    /**\n     * Handle a break of a block's key with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     */\n    void handleBlockBreak(Key key, @Size int amount);\n\n    /**\n     * Handle a break of a block's key with a specific amount.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     * @return The result of the block place.\n     */\n    BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     *\n     * @param block  The block that was broken.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     *\n     * @param block  The block that was broken.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a break of a block's key with a specific amount.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a break of a block's key with a specific amount.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, @IslandBlockFlags int flags);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param block  The block that was broken.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into the database.\n     * @deprecated See {@link #handleBlockBreak(Block, int, int)}\n     */\n    @Deprecated\n    void handleBlockBreak(Block block, @Size int amount, boolean save);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into the database.\n     * @deprecated See {@link #handleBlockBreak(Key, int, int)}\n     */\n    @Deprecated\n    void handleBlockBreak(Key key, @Size int amount, boolean save);\n\n    /**\n     * Handle a break of a block with a specific amount.\n     * This will update the last time status of the island.\n     *\n     * @param key    The block's key that was broken.\n     * @param amount The amount of the block.\n     * @param save   Whether the block counts should be saved into the database.\n     * @deprecated See {@link #handleBlockBreak(Key, int, int)}\n     */\n    @Deprecated\n    void handleBlockBreak(Key key, @Size BigInteger amount, boolean save);\n\n    /**\n     * Handle break of many blocks in one time.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param blocks All the blocks to break.\n     */\n    void handleBlocksBreak(Map<Key, Integer> blocks);\n\n    /**\n     * Handle break of many blocks in one time.\n     * This will save the block counts and update the last time status of the island.\n     *\n     * @param blocks All the blocks to break.\n     * @return Results per block key. Only non-successful results will be returned.\n     */\n    Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks);\n\n    /**\n     * Handle break of many blocks in one time.\n     *\n     * @param blocks All the blocks to break.\n     * @param flags  See {@link IslandBlockFlags}\n     */\n    void handleBlocksBreak(Map<Key, Integer> blocks, @IslandBlockFlags int flags);\n\n    /**\n     * Handle break of many blocks in one time.\n     *\n     * @param blocks All the blocks to break.\n     * @param flags  See {@link IslandBlockFlags}\n     * @return Results per block key. Only non-successful results will be returned.\n     */\n    Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks, @IslandBlockFlags int flags);\n\n    /**\n     * Check whether a chunk has blocks inside it.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     */\n    boolean isChunkDirty(World world, int chunkX, int chunkZ);\n\n    /**\n     * Check whether a chunk has blocks inside it.\n     *\n     * @param worldName The name of the world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     */\n    boolean isChunkDirty(String worldName, int chunkX, int chunkZ);\n\n    /**\n     * Check whether a chunk has blocks inside it.\n     *\n     * @param worldInfo The world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     */\n    boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ);\n\n    /**\n     * Mark a chunk as it has blocks inside it.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     * @param save   Whether to save the changes to database.\n     */\n    void markChunkDirty(World world, int chunkX, int chunkZ, boolean save);\n\n    /**\n     * Mark a chunk as it has blocks inside it.\n     *\n     * @param worldInfo The world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     * @param save      Whether to save the changes to database.\n     */\n    void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save);\n\n    /**\n     * Mark a chunk as it has no blocks inside it.\n     *\n     * @param world  The world of the chunk.\n     * @param chunkX The x-coords of the chunk.\n     * @param chunkZ The z-coords of the chunk.\n     * @param save   Whether to save the changes to database.\n     */\n    void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save);\n\n    /**\n     * Mark a chunk as it has no blocks inside it.\n     *\n     * @param worldInfo The world of the chunk.\n     * @param chunkX    The x-coords of the chunk.\n     * @param chunkZ    The z-coords of the chunk.\n     * @param save      Whether to save the changes to database.\n     */\n    void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save);\n\n    /**\n     * Get the amount of blocks that are on the island.\n     *\n     * @param key The block's key to check.\n     */\n    BigInteger getBlockCountAsBigInteger(Key key);\n\n    /**\n     * Get all the blocks that are on the island.\n     */\n    Map<Key, BigInteger> getBlockCountsAsBigInteger();\n\n    /**\n     * Get the amount of blocks that are on the island.\n     * Unlike getBlockCount(Key), this method returns the count for\n     * the exactly block that is given as a parameter.\n     *\n     * @param key The block's key to check.\n     */\n    BigInteger getExactBlockCountAsBigInteger(Key key);\n\n    /**\n     * Clear all the block counts of the island.\n     */\n    void clearBlockCounts();\n\n    /**\n     * Get the blocks-tracker used by this island.\n     */\n    IslandBlocksTrackerAlgorithm getBlocksTracker();\n\n    /**\n     * Get the worth value of the island, including the money in the bank.\n     */\n    BigDecimal getWorth();\n\n    /**\n     * Get the worth value of the island, excluding bonus worth and the money in the bank.\n     */\n    BigDecimal getRawWorth();\n\n    /**\n     * Get the bonus worth of the island.\n     */\n    BigDecimal getBonusWorth();\n\n    /**\n     * Set a bonus worth for the island.\n     *\n     * @param bonusWorth The bonus to give.\n     */\n    void setBonusWorth(BigDecimal bonusWorth);\n\n    /**\n     * Get the bonus level of the island.\n     */\n    BigDecimal getBonusLevel();\n\n    /**\n     * Set a bonus level for the island.\n     *\n     * @param bonusLevel The bonus to give.\n     */\n    void setBonusLevel(BigDecimal bonusLevel);\n\n    /**\n     * Get the level of the island.\n     */\n    BigDecimal getIslandLevel();\n\n    /**\n     * Get the level value of the island, excluding the bonus level.\n     */\n    BigDecimal getRawLevel();\n\n    /*\n     *  Upgrades related methods\n     */\n\n    /**\n     * Get the level of an upgrade for the island.\n     *\n     * @param upgrade The upgrade to check.\n     */\n    UpgradeLevel getUpgradeLevel(Upgrade upgrade);\n\n    /**\n     * Set the level of an upgrade for the island.\n     *\n     * @param upgrade The upgrade to set the level.\n     * @param level   The level to set.\n     */\n    void setUpgradeLevel(Upgrade upgrade, int level);\n\n    /**\n     * Get all the upgrades with their levels.\n     */\n    Map<String, Integer> getUpgrades();\n\n    /**\n     * Sync all the upgrade values again.\n     * This will remove custom values that were set using the set commands.\n     */\n    void syncUpgrades();\n\n    /**\n     * Update the upgrade values from default values of config & upgrades file.\n     */\n    void updateUpgrades();\n\n    /**\n     * Get the last time the island was upgraded.\n     */\n    long getLastTimeUpgrade();\n\n    /**\n     * Check if the island has an active upgrade cooldown.\n     */\n    boolean hasActiveUpgradeCooldown();\n\n    /**\n     * Get the crop-growth multiplier for the island.\n     */\n    double getCropGrowthMultiplier();\n\n    /**\n     * Set the crop-growth multiplier for the island.\n     *\n     * @param cropGrowth The multiplier to set.\n     */\n    void setCropGrowthMultiplier(double cropGrowth);\n\n    /**\n     * Get the crop-growth multiplier for the island that was set using a command.\n     */\n    double getCropGrowthRaw();\n\n    /**\n     * Get the spawner-rates multiplier for the island.\n     */\n    double getSpawnerRatesMultiplier();\n\n    /**\n     * Set the spawner-rates multiplier for the island.\n     *\n     * @param spawnerRates The multiplier to set.\n     */\n    void setSpawnerRatesMultiplier(double spawnerRates);\n\n    /**\n     * Get the spawner-rates multiplier for the island that was set using a command.\n     */\n    double getSpawnerRatesRaw();\n\n    /**\n     * Get the mob-drops multiplier for the island.\n     */\n    double getMobDropsMultiplier();\n\n    /**\n     * Set the mob-drops multiplier for the island.\n     *\n     * @param mobDrops The multiplier to set.\n     */\n    void setMobDropsMultiplier(double mobDrops);\n\n    /**\n     * Get the mob-drops multiplier for the island that was set using a command.\n     */\n    double getMobDropsRaw();\n\n    /**\n     * Get the block limit of a block.\n     *\n     * @param key The block's key to check.\n     */\n    int getBlockLimit(Key key);\n\n    /**\n     * Get the block limit of a block.\n     * Unlike getBlockLimit(Key), this method returns the count for\n     * the exactly block that is given as a parameter.\n     *\n     * @param key The block's key to check.\n     */\n    int getExactBlockLimit(Key key);\n\n    /**\n     * Get the block key used as a limit for another block key.\n     *\n     * @param key The block's key to check.\n     */\n    Key getBlockLimitKey(Key key);\n\n    /**\n     * Get all the blocks limits for the island.\n     */\n    Map<Key, Integer> getBlocksLimits();\n\n    /**\n     * Get all the custom blocks limits for the island.\n     */\n    Map<Key, Integer> getCustomBlocksLimits();\n\n    /**\n     * Clear all the block limits of the island.\n     */\n    void clearBlockLimits();\n\n    /**\n     * Set the block limit of a block.\n     *\n     * @param key   The block's key to set the limit to.\n     * @param limit The limit to set.\n     */\n    void setBlockLimit(Key key, int limit);\n\n    /**\n     * Remove the limit of a block.\n     *\n     * @param key The block's key to remove it's limit.\n     */\n    void removeBlockLimit(Key key);\n\n    /**\n     * A method to check if a specific block has reached the limit.\n     * This method checks for the block and it's global block key.\n     *\n     * @param key The block's key to check.\n     */\n    boolean hasReachedBlockLimit(Key key);\n\n    /**\n     * A method to check if a specific block has reached the limit.\n     * This method checks for the block and it's global block key.\n     *\n     * @param key    The block's key to check.\n     * @param amount Amount of the block to be placed.\n     */\n    boolean hasReachedBlockLimit(Key key, int amount);\n\n    /**\n     * Get the entity limit of an entity.\n     *\n     * @param entityType The entity's type to check.\n     */\n    int getEntityLimit(EntityType entityType);\n\n    /**\n     * Get the entity limit of an entity.\n     *\n     * @param key The key of the entity to check.\n     */\n    int getEntityLimit(Key key);\n\n    /**\n     * Get all the entities limits for the island.\n     */\n    Map<Key, Integer> getEntitiesLimitsAsKeys();\n\n    /**\n     * Get all the custom entities limits for the island.\n     */\n    Map<Key, Integer> getCustomEntitiesLimits();\n\n    /**\n     * Clear all the entities limits from the island.\n     */\n    void clearEntitiesLimits();\n\n    /**\n     * Set the entity limit of an entity.\n     *\n     * @param entityType The entity's type to set the limit to.\n     * @param limit      The limit to set.\n     */\n    void setEntityLimit(EntityType entityType, int limit);\n\n    /**\n     * Set the entity limit of an entity.\n     *\n     * @param key   The key of the entity to set the limit to.\n     * @param limit The limit to set.\n     */\n    void setEntityLimit(Key key, int limit);\n\n    /**\n     * Remove the limit of an entity.\n     *\n     * @param key The entity's key to remove it's limit.\n     */\n    void removeEntityLimit(Key key);\n\n    /**\n     * A method to check if a specific entity has reached the limit.\n     *\n     * @param entityType The entity's type to check.\n     */\n    CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType);\n\n    /**\n     * A method to check if a specific entity has reached the limit.\n     *\n     * @param key The key of the entity to check.\n     */\n    CompletableFuture<Boolean> hasReachedEntityLimit(Key key);\n\n    /**\n     * A method to check if a specific entity has reached the limit.\n     *\n     * @param amount     The amount of entities that were added.\n     * @param entityType The entity's type to check.\n     */\n    CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType, int amount);\n\n    /**\n     * A method to check if a specific entity has reached the limit.\n     *\n     * @param amount The amount of entities that were added.\n     * @param key    The key of the entity to check.\n     */\n    CompletableFuture<Boolean> hasReachedEntityLimit(Key key, int amount);\n\n    /**\n     * Get the entities tracker used by the island.\n     */\n    IslandEntitiesTrackerAlgorithm getEntitiesTracker();\n\n    /**\n     * Get the team limit of the island.\n     */\n    int getTeamLimit();\n\n    /**\n     * Set the team limit of the island.\n     *\n     * @param teamLimit The team limit to set.\n     */\n    void setTeamLimit(int teamLimit);\n\n    /**\n     * Get the team limit of the island that was set with a command.\n     */\n    int getTeamLimitRaw();\n\n    /**\n     * Get the warps limit of the island.\n     */\n    int getWarpsLimit();\n\n    /**\n     * Set the warps limit for the island.\n     *\n     * @param warpsLimit The limit to set.\n     */\n    void setWarpsLimit(int warpsLimit);\n\n    /**\n     * Get the warps limit of the island that was set using a command.\n     */\n    int getWarpsLimitRaw();\n\n    /**\n     * Add a potion effect to the island.\n     *\n     * @param type  The potion effect to add.\n     * @param level The level of the potion effect.\n     *              If the level is 0 or below, then the effect will be removed.\n     */\n    void setPotionEffect(PotionEffectType type, int level);\n\n    /**\n     * Remove a potion effect from the island.\n     *\n     * @param type The potion effect to remove.\n     */\n    void removePotionEffect(PotionEffectType type);\n\n    /**\n     * Get the level of an island effect.\n     *\n     * @param type The potion to check.\n     * @return The level of the potion. If 0, it means that this is not an active effect on the island.\n     */\n    int getPotionEffectLevel(PotionEffectType type);\n\n    /**\n     * Get a list of all active island effects with their levels.\n     */\n    Map<PotionEffectType, Integer> getPotionEffects();\n\n    /**\n     * Get a list of all custom active island effects with their levels.\n     */\n    Map<PotionEffectType, Integer> getCustomPotionEffects();\n\n\n    /**\n     * Give all the island effects to a player.\n     * If the player is offline, nothing will happen.\n     *\n     * @param superiorPlayer The player to give the effect to.\n     */\n    void applyEffects(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Give all the island effects to the players inside the island.\n     */\n    void applyEffects();\n\n    /**\n     * Remove all the island effects from a player.\n     * If the player is offline, nothing will happen.\n     *\n     * @param superiorPlayer The player to remove the effects to.\n     */\n    void removeEffects(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Remove all the island effects from the players inside the island.\n     */\n    void removeEffects();\n\n    /**\n     * Remove all the effects from the island.\n     */\n    void clearEffects();\n\n    /**\n     * Set the limit of the amount of players that can have the role in the island.\n     *\n     * @param playerRole The role to set the limit to.\n     * @param limit      The limit to set.\n     */\n    void setRoleLimit(PlayerRole playerRole, int limit);\n\n    /**\n     * Remove the limit of the amount of players that can have the role in the island.\n     *\n     * @param playerRole The role to remove the limit.\n     */\n    void removeRoleLimit(PlayerRole playerRole);\n\n    /**\n     * Get the limit of players that can have the same role at a time.\n     *\n     * @param playerRole The role to check.\n     */\n    int getRoleLimit(PlayerRole playerRole);\n\n    /**\n     * Get the limit of players that can have the same role at a time that was set using a command.\n     *\n     * @param playerRole The role to check.\n     */\n    int getRoleLimitRaw(PlayerRole playerRole);\n\n    /**\n     * Get all the role limits for the island.\n     */\n    Map<PlayerRole, Integer> getRoleLimits();\n\n    /**\n     * Get all the custom role limits for the island.\n     */\n    Map<PlayerRole, Integer> getCustomRoleLimits();\n\n    /*\n     *  Warps related methods\n     */\n\n    /**\n     * Create a new warp category.\n     * If a category already exists, it will be returned instead of a new created one.\n     *\n     * @param name The name of the category.\n     */\n    WarpCategory createWarpCategory(String name);\n\n    /**\n     * Get a warp category.\n     *\n     * @param name The name of the category.\n     */\n    @Nullable\n    WarpCategory getWarpCategory(String name);\n\n    /**\n     * Get a warp category by the slot inside the manage menu.\n     *\n     * @param slot The slot to check.\n     */\n    @Nullable\n    WarpCategory getWarpCategory(int slot);\n\n    /**\n     * Rename a category.\n     *\n     * @param warpCategory The category to rename.\n     * @param newName      A new name to set.\n     */\n    void renameCategory(WarpCategory warpCategory, String newName);\n\n    /**\n     * Delete a warp category.\n     * All the warps inside it will be deleted as well.\n     *\n     * @param warpCategory The category to delete.\n     */\n    void deleteCategory(WarpCategory warpCategory);\n\n    /**\n     * Get all the warp categories of the island.\n     */\n    Map<String, WarpCategory> getWarpCategories();\n\n    /**\n     * Create a warp for the island.\n     *\n     * @param name         The name of the warp.\n     * @param location     The location of the warp.\n     * @param warpCategory The category to add the island.\n     * @return The new island warp object.\n     */\n    IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory);\n\n    /**\n     * Create a warp for the island.\n     *\n     * @param name         The name of the warp.\n     * @param worldInfo    The world of the warp.\n     * @param position     The position of the warp.\n     * @param warpCategory The category to add the island.\n     * @return The new island warp object.\n     */\n    IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory);\n\n    /**\n     * Rename a warp.\n     *\n     * @param islandWarp The warp to rename.\n     * @param newName    A new name to set.\n     */\n    void renameWarp(IslandWarp islandWarp, String newName);\n\n    /**\n     * Get an island warp in a specific location.\n     *\n     * @param location The location to check.\n     */\n    @Nullable\n    IslandWarp getWarp(Location location);\n\n    /**\n     * Get an island warp by it's name..\n     *\n     * @param name The name to check.\n     */\n    @Nullable\n    IslandWarp getWarp(String name);\n\n    /**\n     * Teleport a player to a warp.\n     *\n     * @param superiorPlayer The player to teleport.\n     * @param warpName       The warp's name to teleport the player to.\n     */\n    void warpPlayer(SuperiorPlayer superiorPlayer, String warpName);\n\n    /**\n     * Teleport a player to a warp.\n     *\n     * @param superiorPlayer The player to teleport.\n     * @param warpName       The warp's name to teleport the player to.\n     * @param force          Force teleportation of the player\n     */\n    void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force);\n\n    /**\n     * Delete a warp from the island.\n     *\n     * @param superiorPlayer The player who requested the operation.\n     * @param location       The location of the warp.\n     */\n    void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location);\n\n    /**\n     * Delete a warp from the island.\n     *\n     * @param name The warp's name to delete.\n     */\n    void deleteWarp(String name);\n\n    /**\n     * Get all the warps of the island.\n     */\n    Map<String, IslandWarp> getIslandWarps();\n\n    /*\n     *  Ratings related methods\n     */\n\n    /**\n     * Get the rating that a player has given the island.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    Rating getRating(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Set a rating of a player.\n     *\n     * @param superiorPlayer The player that sets the rating.\n     * @param rating         The rating to set.\n     */\n    void setRating(SuperiorPlayer superiorPlayer, Rating rating);\n\n    /**\n     * Remove a rating of a player.\n     *\n     * @param superiorPlayer The player to remove the rating of.\n     */\n    void removeRating(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the total rating of the island.\n     */\n    double getTotalRating();\n\n    /**\n     * Get the amount of ratings that have have been given to the island.\n     */\n    int getRatingAmount();\n\n    /**\n     * Get all the ratings of the island.\n     */\n    Map<UUID, Rating> getRatings();\n\n    /**\n     * Remove all the ratings of the island.\n     */\n    void removeRatings();\n\n    /*\n     *  Settings related methods\n     */\n\n    /**\n     * Check whether a settings is enabled or not.\n     *\n     * @param islandFlag The settings to check.\n     */\n    boolean hasSettingsEnabled(IslandFlag islandFlag);\n\n    /**\n     * Get all the settings of the island.\n     * If the byte value is 1, the setting is enabled. Otherwise, it's disabled.\n     */\n    Map<IslandFlag, Byte> getAllSettings();\n\n    /**\n     * Enable an island settings.\n     *\n     * @param islandFlag The settings to enable.\n     */\n    void enableSettings(IslandFlag islandFlag);\n\n    /**\n     * Disable an island settings.\n     *\n     * @param islandFlag The settings to disable.\n     */\n    void disableSettings(IslandFlag islandFlag);\n\n    /**\n     * Reset the island settings to default values.\n     */\n    void resetSettings();\n\n    /*\n     *  Generator related methods\n     */\n\n    /**\n     * Set a percentage for a specific key in a specific world.\n     * Percentage can be between 0 and 100 (0 will remove the key from the list).\n     * Calling this method will not make events get fired.\n     * <p>\n     * This function sets the amount of the key using the following formula:\n     * amount = (percentage * total_amount) / (1 - percentage)\n     * <p>\n     * If the percentage is 100, the rest of the amounts will be cleared and\n     * the material's amount will be set to 1.\n     * <p>\n     * The amount is rounded to ensure a smaller loss, and currently it's 1%~ loss.\n     *\n     * @param key        The block to change the generator rate of.\n     * @param percentage The percentage to set the new rate.\n     * @param dimension  The world to change the rates in.\n     */\n    void setGeneratorPercentage(Key key, int percentage, Dimension dimension);\n\n    /**\n     * Set a percentage for a specific key in a specific world.\n     * Percentage can be between 0 and 100 (0 will remove the key from the list).\n     * <p>\n     * This function sets the amount of the key using the following formula:\n     * amount = (percentage * total_amount) / (1 - percentage)\n     * <p>\n     * If the percentage is 100, the rest of the amounts will be cleared and\n     * the material's amount will be set to 1.\n     * <p>\n     * The amount is rounded to ensure a smaller loss, and currently it's 1%~ loss.\n     *\n     * @param key        The block to change the generator rate of.\n     * @param percentage The percentage to set the new rate.\n     * @param dimension  The world to change the rates in.\n     * @param caller     The player that changes the percentages (used for the event).\n     *                   If null, it means the console did the operation.\n     * @param callEvent  Whether to call the {@link IslandChangeGeneratorRateEvent}\n     * @return Whether the operation succeed.\n     * The operation may fail if callEvent is true and the event was cancelled.\n     */\n    boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension,\n                                   @Nullable SuperiorPlayer caller, boolean callEvent);\n\n    /**\n     * Get the percentage for a specific key in a specific world.\n     * The formula is (amount * 100) / total_amount.\n     *\n     * @param key       The material key\n     * @param dimension The world dimension.\n     */\n    int getGeneratorPercentage(Key key, Dimension dimension);\n\n    /**\n     * Get the percentages of the materials for the cobblestone generator in the island for a specific world.\n     */\n    Map<String, Integer> getGeneratorPercentages(Dimension dimension);\n\n    /**\n     * Set an amount for a specific key in a specific world.\n     */\n    void setGeneratorAmount(Key key, @Size int amount, Dimension dimension);\n\n    /**\n     * Remove a rate for a specific key in a specific world.\n     */\n    void removeGeneratorAmount(Key key, Dimension dimension);\n\n    /**\n     * Get the amount of a specific key in a specific world.\n     */\n    int getGeneratorAmount(Key key, Dimension dimension);\n\n    /**\n     * Get the total amount of all the generator keys together.\n     */\n    int getGeneratorTotalAmount(Dimension dimension);\n\n    /**\n     * Get the amounts of the materials for the cobblestone generator in the island.\n     */\n    Map<String, Integer> getGeneratorAmounts(Dimension dimension);\n\n    /**\n     * Get the custom amounts of the materials for the cobblestone generator in the island.\n     */\n    Map<Key, Integer> getCustomGeneratorAmounts(Dimension dimension);\n\n    /**\n     * Clear all the custom generator amounts for this island.\n     */\n    void clearGeneratorAmounts(Dimension dimension);\n\n    /**\n     * Generate a block at a specified location.\n     * The method calculates a block to generate from {@link #getGeneratorAmounts(Dimension)}.\n     * It doesn't look for any conditions for generating it - lava, water, etc are not required.\n     * The method will fail if there are no valid generator rates for the environment.\n     *\n     * @param location             The location to generate block at.\n     * @param optimizeDefaultBlock When set to true and the default block needs to be generated, the plugin will\n     *                             not play any effect, count the block towards the block counts or set the block.\n     *                             This is useful when calling the method from BlockFromToEvent, and instead of letting\n     *                             the plugin do the logic of vanilla, the plugin lets the game do it.\n     * @return The block type that was generated, null if failed.\n     */\n    @Nullable\n    Key generateBlock(Location location, boolean optimizeDefaultBlock);\n\n    /**\n     * Generate a block at a specified location.\n     * The method calculates a block to generate from {@link #getGeneratorAmounts(Dimension)}.\n     * It doesn't look for any conditions for generating it - lava, water, etc are not required.\n     * The method will fail if there are no valid generator rates for the environment.\n     *\n     * @param location             The location to generate block at.\n     * @param dimension            The world to get generator rates from.\n     * @param optimizeDefaultBlock When set to true and the default block needs to be generated, the plugin will\n     *                             not play any effect, count the block towards the block counts or set the block.\n     *                             This is useful when calling the method from BlockFromToEvent, and instead of letting\n     *                             the plugin do the logic of vanilla, the plugin lets the game do it.\n     * @return The block type that was generated, null if failed.\n     */\n    @Nullable\n    Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock);\n\n    /*\n     *  Schematic methods\n     */\n\n    /**\n     * Checks if a schematic was generated already.\n     *\n     * @param dimension The dimension to check.\n     */\n    boolean wasSchematicGenerated(Dimension dimension);\n\n    /**\n     * Set schematic generated flag to true.\n     *\n     * @param dimension The dimension to set.\n     */\n    void setSchematicGenerate(Dimension dimension);\n\n    /**\n     * Set schematic generated flag.\n     *\n     * @param dimension The dimension to set.\n     * @param generated The flag to set.\n     */\n    void setSchematicGenerate(Dimension dimension, boolean generated);\n\n    /**\n     * Get the generated schematics.\n     */\n    Collection<Dimension> getGeneratedSchematics();\n\n    /**\n     * Get the schematic that was used to create the island.\n     */\n    String getSchematicName();\n\n    /*\n     *  Island top methods\n     */\n\n    int getPosition(SortingType sortingType);\n\n    /*\n     *  Vault related methods\n     */\n\n    /**\n     * Get the island chest.\n     */\n    IslandChest[] getChest();\n\n    /**\n     * Get the amount of pages the island chest has.\n     */\n    int getChestSize();\n\n    /**\n     * Set the amount of rows for the chest in a specific index.\n     *\n     * @param index The index of the page (0 or above)\n     * @param rows  The amount of rows for that page.\n     */\n    void setChestRows(int index, int rows);\n\n    /**\n     * Create a new builder for a {@link Island} object.\n     */\n    static Builder newBuilder() {\n        return SuperiorSkyblockAPI.getFactory().createIslandBuilder();\n    }\n\n    /**\n     * The {@link Builder} interface is used to create {@link Island} objects with predefined values.\n     * All of its methods are setters for all the values possible to create an island with.\n     * Use {@link Builder#build()} to create the new {@link Island} object. You must set\n     * {@link Builder#setOwner(SuperiorPlayer)}, {@link Builder#setUniqueId(UUID)} and\n     * {@link Builder#setCenter(Location)} before creating a new {@link Island}\n     */\n    interface Builder {\n\n        Builder setOwner(@Nullable SuperiorPlayer owner);\n\n        @Nullable\n        SuperiorPlayer getOwner();\n\n        Builder setUniqueId(UUID uuid);\n\n        UUID getUniqueId();\n\n        Builder setCenter(Location center);\n\n        Location getCenter();\n\n        Builder setName(String islandName);\n\n        String getName();\n\n        Builder setSchematicName(String schematicName);\n\n        String getScehmaticName();\n\n        Builder setCreationTime(long creationTime);\n\n        long getCreationTime();\n\n        Builder setDiscord(String discord);\n\n        String getDiscord();\n\n        Builder setPaypal(String paypal);\n\n        String getPaypal();\n\n        Builder setBonusWorth(BigDecimal bonusWorth);\n\n        BigDecimal getBonusWorth();\n\n        Builder setBonusLevel(BigDecimal bonusLevel);\n\n        BigDecimal getBonusLevel();\n\n        Builder setLocked(boolean isLocked);\n\n        boolean isLocked();\n\n        Builder setIgnored(boolean isIgnored);\n\n        boolean isIgnored();\n\n        Builder setDescription(String description);\n\n        String getDescription();\n\n        Builder setGeneratedSchematic(Dimension dimension);\n\n        Set<Dimension> getGeneratedSchematics();\n\n        Builder setUnlockedWorld(Dimension dimension);\n\n        Set<Dimension> getUnlockedWorlds();\n\n        Builder setLastTimeUpdated(long lastTimeUpdated);\n\n        long getLastTimeUpdated();\n\n        Builder setDirtyChunk(String worldName, int chunkX, int chunkZ);\n\n        boolean isDirtyChunk(String worldName, int chunkX, int chunkZ);\n\n        Builder setBlockCount(Key block, BigInteger count);\n\n        KeyMap<BigInteger> getBlockCounts();\n\n        Builder setEntityCount(Key entity, BigInteger count);\n\n        KeyMap<BigInteger> getEntityCounts();\n\n        Builder setIslandHome(Location location, Dimension dimension);\n\n        Builder setIslandHome(Dimension dimension, WorldPosition worldPosition);\n\n        Map<Dimension, Location> getIslandHomesAsDimensions();\n\n        Builder addIslandMember(SuperiorPlayer superiorPlayer);\n\n        List<SuperiorPlayer> getIslandMembers();\n\n        Builder addBannedPlayer(SuperiorPlayer superiorPlayer);\n\n        List<SuperiorPlayer> getBannedPlayers();\n\n        Builder setPlayerPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value);\n\n        Map<SuperiorPlayer, PermissionNode> getPlayerPermissions();\n\n        Builder setRolePermission(IslandPrivilege islandPrivilege, PlayerRole requiredRole);\n\n        Map<IslandPrivilege, PlayerRole> getRolePermissions();\n\n        Builder setUpgrade(Upgrade upgrade, int level);\n\n        Map<Upgrade, Integer> getUpgrades();\n\n        Builder setBlockLimit(Key block, int limit);\n\n        KeyMap<Integer> getBlockLimits();\n\n        Builder setRating(SuperiorPlayer superiorPlayer, Rating rating);\n\n        Map<SuperiorPlayer, Rating> getRatings();\n\n        Builder setCompletedMission(Mission<?> mission, int finishCount);\n\n        Map<Mission<?>, Integer> getCompletedMissions();\n\n        Builder setIslandFlag(IslandFlag islandFlag, boolean value);\n\n        Map<IslandFlag, SyncStatus> getIslandFlags();\n\n        Builder setGeneratorRate(Key block, int rate, Dimension dimension);\n\n        Map<Dimension, KeyMap<Integer>> getGeneratorRatesAsDimensions();\n\n        Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime);\n\n        Map<SuperiorPlayer, Long> getUniqueVisitors();\n\n        Builder setEntityLimit(Key entity, int limit);\n\n        KeyMap<Integer> getEntityLimits();\n\n        Builder setIslandEffect(PotionEffectType potionEffectType, int level);\n\n        Map<PotionEffectType, Integer> getIslandEffects();\n\n        Builder setIslandChest(int index, ItemStack[] contents);\n\n        List<ItemStack[]> getIslandChests();\n\n        Builder setRoleLimit(PlayerRole playerRole, int limit);\n\n        Map<PlayerRole, Integer> getRoleLimits();\n\n        Builder setVisitorHome(Location location, Dimension dimension);\n\n        Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition);\n\n        Map<Dimension, Location> getVisitorHomesAsDimensions();\n\n        Builder setIslandSize(int islandSize);\n\n        int getIslandSize();\n\n        Builder setTeamLimit(int teamLimit);\n\n        int getTeamLimit();\n\n        Builder setWarpsLimit(int warpsLimit);\n\n        int getWarpsLimit();\n\n        Builder setCropGrowth(double cropGrowth);\n\n        double getCropGrowth();\n\n        Builder setSpawnerRates(double spawnerRates);\n\n        double getSpawnerRates();\n\n        Builder setMobDrops(double mobDrops);\n\n        double getMobDrops();\n\n        Builder setCoopLimit(int coopLimit);\n\n        int getCoopLimit();\n\n        Builder setBankLimit(BigDecimal bankLimit);\n\n        BigDecimal getBankLimit();\n\n        Builder setBalance(BigDecimal balance);\n\n        BigDecimal getBalance();\n\n        Builder setLastInterestTime(long lastInterestTime);\n\n        long getLastInterestTime();\n\n        Builder addWarp(String name, String category, Location location, boolean isPrivate, @Nullable ItemStack icon);\n\n        Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon);\n\n        boolean hasWarp(String name);\n\n        boolean hasWarp(Location location);\n\n        boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition);\n\n        Builder addWarpCategory(String name, int slot, @Nullable ItemStack icon);\n\n        boolean hasWarpCategory(String name);\n\n        Builder addBankTransaction(BankTransaction bankTransaction);\n\n        List<BankTransaction> getBankTransactions();\n\n        Builder setPersistentData(byte[] persistentData);\n\n        byte[] getPersistentData();\n\n        Island build();\n\n\n    }\n\n}"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.IntType;\n\n/**\n * The integer value element annotated with {@link IslandBlockFlags} represents flags related to what to do\n * when block change is recorded. It is mainly used within the {@link Island} interface and its methods.\n */\n@IntType({IslandBlockFlags.SAVE_BLOCK_COUNTS, IslandBlockFlags.UPDATE_LAST_TIME_STATUS})\npublic @interface IslandBlockFlags {\n\n    /**\n     * Indicates to save block counts into the DB after the block count change.\n     */\n    int SAVE_BLOCK_COUNTS = (1 << 0);\n\n    /**\n     * Indicates to update the last time the island was updated due to the block count change.\n     */\n    int UPDATE_LAST_TIME_STATUS = (1 << 1);\n\n    /**\n     * Indicates to update block counts only for the provided blocks, and do not count global keys, limit keys, etc.\n     */\n    int RAW_BLOCKS = (1 << 2);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandChest.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface IslandChest extends InventoryHolder {\n\n    /**\n     * Get the island of the chest.\n     */\n    Island getIsland();\n\n    /**\n     * Get the index of this chest.\n     */\n    int getIndex();\n\n    /**\n     * Get the amount of rows for this chest.\n     */\n    int getRows();\n\n    /**\n     * Set the amount of rows for this chest.\n     *\n     * @param rows The new amount of rows.\n     */\n    void setRows(int rows);\n\n    /**\n     * Get the contents of the chest.\n     */\n    ItemStack[] getContents();\n\n    /**\n     * Open this chest for a player.\n     */\n    void openChest(SuperiorPlayer superiorPlayer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandChunkFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.IntType;\n\n/**\n * The integer value element annotated with {@link IslandChunkFlags} represents flags related to which chunks\n * to do the action on. It is mainly used within the {@link Island} interface and its methods.\n */\n@IntType({IslandChunkFlags.ONLY_PROTECTED, IslandChunkFlags.NO_EMPTY_CHUNKS})\npublic @interface IslandChunkFlags {\n\n    /**\n     * Indicates to only do the action on chunks within the protected-radius of the island.\n     */\n    int ONLY_PROTECTED = (1 << 0);\n\n    /**\n     * Indicates to only do the action on chunks that have blocks inside them.\n     * It is generally a good practice to use this flag whenever possible to reduce performance impact.\n     */\n    int NO_EMPTY_CHUNKS = (1 << 1);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandFlag.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class IslandFlag implements Enumerable {\n\n    private static final Map<String, IslandFlag> islandFlags = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final int ordinal;\n\n    private IslandFlag(String name) {\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get all the island flags.\n     */\n    public static Collection<IslandFlag> values() {\n        return islandFlags.values();\n    }\n\n    /**\n     * Get an island flag by it's name.\n     *\n     * @param name The name to check.\n     */\n    public static IslandFlag getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        IslandFlag islandFlag = islandFlags.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(islandFlag, \"Couldn't find an IslandFlag with the name \" + name + \".\");\n\n        return islandFlag;\n    }\n\n    /**\n     * Register a new island flag.\n     *\n     * @param name The name for the island flag.\n     */\n    public static void register(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        name = name.toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!islandFlags.containsKey(name), \"IslandFlag with the name \" + name + \" already exists.\");\n\n        islandFlags.put(name, new IslandFlag(name));\n    }\n\n    /**\n     * Get the name of the island flag.\n     */\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public String toString() {\n        return \"IslandFlag{name=\" + name + \"}\";\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\n\n/**\n * Object that handles the data of the island preview task.\n */\npublic interface IslandPreview {\n\n    /**\n     * Get the player that is inside the preview.\n     */\n    SuperiorPlayer getPlayer();\n\n    /**\n     * Get the location of the island preview.\n     */\n    Location getLocation();\n\n    /**\n     * Get the location of the island preview.\n     *\n     * @param location Location object to re-use.\n     */\n    @Nullable\n    Location getLocation(@Nullable Location location);\n\n    /**\n     * Get the requested schematic.\n     */\n    String getSchematic();\n\n    /**\n     * Get the island name that was requested.\n     */\n    String getIslandName();\n\n    /**\n     * Get the game mode that the player had before the preview started.\n     */\n    GameMode getPreviousGameMode();\n\n    /**\n     * Handle confirmation of creation of the island.\n     */\n    void handleConfirm();\n\n    /**\n     * Handle cancellation of the creation of the island.\n     */\n    void handleCancel();\n\n    /**\n     * Handle escaping from the area of the preview.\n     */\n    void handleEscape();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class IslandPrivilege implements Enumerable {\n\n    private static final Map<String, IslandPrivilege> islandPrivileges = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final Type type;\n    private final int ordinal;\n\n    private IslandPrivilege(String name, Type type) {\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.type = type;\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get the name of the island privilege.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Get the type of the privilege.\n     */\n    public Type getType() {\n        return type;\n    }\n\n    @Override\n    public String toString() {\n        return \"IslandPrivilege{name=\" + name + \", type=\" + type + \"}\";\n    }\n\n    /**\n     * Get all the island privileges.\n     */\n    public static Collection<IslandPrivilege> values() {\n        return islandPrivileges.values();\n    }\n\n    /**\n     * Get an island privilege by it's name.\n     *\n     * @param name The name to check.\n     */\n    public static IslandPrivilege getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        IslandPrivilege islandPrivilege = islandPrivileges.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(islandPrivilege, \"Couldn't find an IslandPrivilege with the name \" + name + \".\");\n\n        return islandPrivilege;\n    }\n\n    /**\n     * Register a new {@link Type#ACTION} island privilege.\n     *\n     * @param name The name for the island privilege.\n     */\n    public static void register(String name) {\n        register(name, Type.ACTION);\n    }\n\n    /**\n     * Register a new island privilege.\n     *\n     * @param name The name for the island privilege.\n     * @param type The type of the privilege.\n     */\n    public static void register(String name, Type type) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkNotNull(type, \"name parameter cannot be null.\");\n\n        name = name.toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!islandPrivileges.containsKey(name), \"IslandPrivilege with the name \" + name + \" already exists.\");\n\n        islandPrivileges.put(name, new IslandPrivilege(name, type));\n    }\n\n    /**\n     * Represents the type of IslandPrivilege.\n     */\n    public enum Type {\n\n        /**\n         * The ACTION type is given for privileges that allow player to do actions on islands.\n         * Privileges of this type can be given to visitors, coops and players that are not part of the island team.\n         */\n        ACTION,\n\n        /**\n         * The COMMAND type is given for privileges that give access to commands on the island.\n         * Privileges of this type can only be given to players that are part of the island.\n         */\n        COMMAND\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/PermissionNode.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport java.util.Map;\n\npublic interface PermissionNode extends Cloneable {\n\n    /**\n     * Check whether or not the node has a permission.\n     *\n     * @param islandPrivilege The privilege to check.\n     */\n    boolean hasPermission(IslandPrivilege islandPrivilege);\n\n    /**\n     * Set whether or not the node should have a permission.\n     *\n     * @param islandPrivilege The privilege to set.\n     * @param value           The value to set.\n     */\n    void setPermission(IslandPrivilege islandPrivilege, boolean value);\n\n    /**\n     * Get all permissions set using the provided method.\n     * This does not include default permissions.\n     */\n    Map<IslandPrivilege, Boolean> getCustomPermissions();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/PlayerRole.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\npublic interface PlayerRole {\n\n    /**\n     * Get the id of the role.\n     */\n    int getId();\n\n    /**\n     * Get the name of the role.\n     */\n    String getName();\n\n    /**\n     * Get the display-name of the role.\n     * This is shown in chat, placeholders, etc.\n     */\n    String getDisplayName();\n\n    /**\n     * Get the weight of the role in the ladder.\n     */\n    int getWeight();\n\n    /**\n     * Check whether or not the role is higher than another role.\n     *\n     * @param role The role to check.\n     */\n    boolean isHigherThan(PlayerRole role);\n\n    /**\n     * Check whether or not the role is less than another role.\n     *\n     * @param role The role to check.\n     */\n    boolean isLessThan(PlayerRole role);\n\n    /**\n     * Check whether or not the role is the first role in the ladder.\n     */\n    boolean isFirstRole();\n\n    /**\n     * Check whether or not the role is the last role in the ladder.\n     */\n    boolean isLastRole();\n\n    /**\n     * Check whether or not the role is the role is in the ladder.\n     */\n    boolean isRoleLadder();\n\n    /**\n     * Get the next role in the ladder.\n     * Will return null if the role is not in the ladder, or it's the last role in the ladder.\n     */\n    @Nullable\n    PlayerRole getNextRole();\n\n    /**\n     * Get the previous role in the ladder.\n     * Will return null if the role is not in the ladder, or it's the first role in the ladder.\n     */\n    @Nullable\n    PlayerRole getPreviousRole();\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class SortingType implements Comparator<Island>, Enumerable {\n\n    private static final Map<String, SortingType> sortingTypes = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private static final Comparator<Island> ISLAND_NAMES_COMPARATOR = (o1, o2) -> {\n        String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner() == null ? \"null\" : o1.getOwner().getName() : o1.getStrippedName();\n        String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner() == null ? \"null\" : o2.getOwner().getName() : o2.getStrippedName();\n        return firstName.compareTo(secondName);\n    };\n\n    private final String name;\n    private final Comparator<Island> comparator;\n    private final int ordinal;\n\n    private SortingType(String name, Comparator<Island> comparator, boolean handleEqualsIslands) {\n        this.name = name;\n        this.comparator = !handleEqualsIslands ? comparator : (o1, o2) -> {\n            int compare = comparator.compare(o1, o2);\n            return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare;\n        };\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get all the sorting types.\n     */\n    public static Collection<SortingType> values() {\n        return sortingTypes.values();\n    }\n\n    /**\n     * Get a sorting type by it's name.\n     *\n     * @param name The name to check.\n     */\n    public static SortingType getByName(String name) {\n        return sortingTypes.get(name);\n    }\n\n    /**\n     * Register a new sorting type.\n     *\n     * @param name       The name for the sorting type.\n     * @param comparator The comparator for sorting the islands.\n     */\n    public static void register(String name, Comparator<Island> comparator) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkNotNull(comparator, \"comparator parameter cannot be null.\");\n\n        register(name, comparator, true);\n    }\n\n    /**\n     * Register a new sorting type.\n     *\n     * @param name                The name for the sorting type.\n     * @param comparator          The comparator for sorting the islands.\n     * @param handleEqualsIslands Should the plugin handle equals islands?\n     *                            If that's false, you should handle it on your own.\n     */\n    public static void register(String name, Comparator<Island> comparator, boolean handleEqualsIslands) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkNotNull(comparator, \"comparator parameter cannot be null.\");\n        Preconditions.checkState(!sortingTypes.containsKey(name), \"SortingType with the name \" + name + \" already exists.\");\n\n        SortingType sortingType = new SortingType(name, comparator, handleEqualsIslands);\n        sortingTypes.put(name, sortingType);\n        SuperiorSkyblockAPI.getGrid().registerSortingType(sortingType);\n    }\n\n    /**\n     * Get the name of the sorting type.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Get the comparator of the sorting type.\n     */\n    public Comparator<Island> getComparator() {\n        return comparator;\n    }\n\n    @Override\n    public int compare(Island o1, Island o2) {\n        return comparator.compare(o1, o2);\n    }\n\n    @Override\n    public String toString() {\n        return \"SortingType{name=\" + name + \"}\";\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigInteger;\nimport java.util.Map;\n\npublic class DelegateIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm {\n\n    protected final IslandBlocksTrackerAlgorithm handle;\n\n    protected DelegateIslandBlocksTrackerAlgorithm(IslandBlocksTrackerAlgorithm handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public boolean trackBlock(Key key, BigInteger amount) {\n        return this.handle.trackBlock(key, amount);\n    }\n\n    @Override\n    public boolean untrackBlock(Key key, BigInteger amount) {\n        return this.handle.untrackBlock(key, amount);\n    }\n\n    @Override\n    public BigInteger getBlockCount(Key key) {\n        return this.handle.getBlockCount(key);\n    }\n\n    @Override\n    public BigInteger getExactBlockCount(Key key) {\n        return this.handle.getExactBlockCount(key);\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCounts() {\n        return this.handle.getBlockCounts();\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        this.handle.clearBlockCounts();\n    }\n\n    @Override\n    public void setLoadingDataMode(boolean loadingDataMode) {\n        this.handle.setLoadingDataMode(loadingDataMode);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class DelegateIslandCalculationAlgorithm implements IslandCalculationAlgorithm {\n\n    protected final IslandCalculationAlgorithm handle;\n\n    protected DelegateIslandCalculationAlgorithm(IslandCalculationAlgorithm handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    @Deprecated\n    public CompletableFuture<IslandCalculationResult> calculateIsland() {\n        return this.handle.calculateIsland();\n    }\n\n    @Override\n    public CompletableFuture<IslandCalculationResult> calculateIsland(Island island) {\n        return this.handle.calculateIsland(island);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.util.Map;\n\npublic class DelegateIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm {\n\n    protected final IslandEntitiesTrackerAlgorithm handle;\n\n    protected DelegateIslandEntitiesTrackerAlgorithm(IslandEntitiesTrackerAlgorithm handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public boolean trackEntity(Key key, int amount) {\n        return this.handle.trackEntity(key, amount);\n    }\n\n    @Override\n    public boolean untrackEntity(Key key, int amount) {\n        return this.handle.untrackEntity(key, amount);\n    }\n\n    @Override\n    public int getEntityCount(Key key) {\n        return this.handle.getEntityCount(key);\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesCounts() {\n        return this.handle.getEntitiesCounts();\n    }\n\n    @Override\n    public void clearEntityCounts() {\n        this.handle.clearEntityCounts();\n    }\n\n    @Override\n    public void recalculateEntityCounts() {\n        this.handle.recalculateEntityCounts();\n    }\n\n    @Override\n    public boolean canRecalculateEntityCounts() {\n        return this.handle.canRecalculateEntityCounts();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandBlocksTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigInteger;\nimport java.util.Map;\n\npublic interface IslandBlocksTrackerAlgorithm {\n\n    /**\n     * Track a new block with a specific amount.\n     *\n     * @param key    The block's key that should be tracked.\n     * @param amount The amount of the block.\n     * @return Whether the block was successfully tracked.\n     */\n    boolean trackBlock(Key key, BigInteger amount);\n\n    /**\n     * Untrack a block with a specific amount.\n     *\n     * @param key    The block's key that should be untracked.\n     * @param amount The amount of the block.\n     * @return Whether the block was successfully untracked.\n     */\n    boolean untrackBlock(Key key, BigInteger amount);\n\n    /**\n     * Get the amount of blocks that are on the island.\n     *\n     * @param key The block's key to check.\n     */\n    BigInteger getBlockCount(Key key);\n\n    /**\n     * Get the amount of blocks that are on the island.\n     * Unlike getBlockCount(Key), this method returns the count for\n     * the exactly block that is given as a parameter.\n     *\n     * @param key The block's key to check.\n     */\n    BigInteger getExactBlockCount(Key key);\n\n    /**\n     * Get all the blocks that are on the island.\n     */\n    Map<Key, BigInteger> getBlockCounts();\n\n    /**\n     * Clear all the block counts of the island.\n     */\n    void clearBlockCounts();\n\n    /**\n     * Set whether the tracker should be in \"loading data mode\" or not.\n     * When loading mode is enabled, the tracker should only track blocks for the given blocks\n     * and not their variants (limits, global blocks, etc)\n     *\n     * @param loadingDataMode loading mode\n     */\n    void setLoadingDataMode(boolean loadingDataMode);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandCalculationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigInteger;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface IslandCalculationAlgorithm {\n\n    /**\n     * Calculate the island blocks of the island.\n     *\n     * @return CompletableFuture instance of the result.\n     * @deprecated See {@link #calculateIsland(Island)}\n     */\n    @Deprecated\n    default CompletableFuture<IslandCalculationResult> calculateIsland() {\n        throw new UnsupportedOperationException(\"This method is not supported anymore. Use calculateIsland(Island) instead.\");\n    }\n\n    /**\n     * Calculate the island blocks of the island.\n     *\n     * @param island The island to calculate blocks for.\n     * @return CompletableFuture instance of the result.\n     */\n    CompletableFuture<IslandCalculationResult> calculateIsland(Island island);\n\n    /**\n     * Represents calculation result.\n     */\n    interface IslandCalculationResult {\n\n        /**\n         * Get all block-counts that were calculated.\n         */\n        Map<Key, BigInteger> getBlockCounts();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandEntitiesTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.algorithms;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.util.Map;\n\npublic interface IslandEntitiesTrackerAlgorithm {\n\n    /**\n     * Track a new entity with a specific amount.\n     *\n     * @param key    The entity's key that should be tracked.\n     * @param amount The amount of the entity.\n     * @return Whether the entity was successfully tracked.\n     */\n    boolean trackEntity(Key key, int amount);\n\n    /**\n     * Untrack a entity with a specific amount.\n     *\n     * @param key    The entity's key that should be untracked.\n     * @param amount The amount of the entity.\n     * @return Whether the entity was successfully untracked.\n     */\n    boolean untrackEntity(Key key, int amount);\n\n    /**\n     * Get the amount of entities that are on the island.\n     *\n     * @param key The entity's key to check.\n     */\n    int getEntityCount(Key key);\n\n    /**\n     * Get all the entities that are on the island.\n     */\n    Map<Key, Integer> getEntitiesCounts();\n\n    /**\n     * Clear all the entity counts of the island.\n     */\n    void clearEntityCounts();\n\n    /**\n     * Recalculate entity counts on the island.\n     */\n    void recalculateEntityCounts();\n\n    /**\n     * Check if it possible to recalculate entity counts on the island.\n     */\n    boolean canRecalculateEntityCounts();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/BankTransaction.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.bank;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\n\npublic interface BankTransaction {\n\n    /**\n     * Get the player that made the transaction.\n     * Can be null if the console has made the transaction.\n     */\n    @Nullable\n    UUID getPlayer();\n\n    /**\n     * Get the transaction action.\n     */\n    BankAction getAction();\n\n    /**\n     * Get the position of the transaction\n     */\n    int getPosition();\n\n    /**\n     * Get the time the transaction was made.\n     */\n    long getTime();\n\n    /**\n     * Get formatted time of the time the transaction was made.\n     */\n    String getDate();\n\n    /**\n     * Get the reason for failure of the transaction.\n     * If succeed, an empty string will be returned.\n     * <p>\n     * Some fail reasons, such as \"Not enough money\", will not be logged.\n     */\n    String getFailureReason();\n\n    /**\n     * Get the amount that was withdrawn or deposited.\n     * If the transaction failed, -1 will be returned.\n     */\n    BigDecimal getAmount();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.bank;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\n\npublic class DelegateBankTransaction implements BankTransaction {\n\n    protected final BankTransaction handle;\n\n    protected DelegateBankTransaction(BankTransaction handle) {\n        this.handle = handle;\n    }\n\n    @Nullable\n    @Override\n    public UUID getPlayer() {\n        return this.handle.getPlayer();\n    }\n\n    @Override\n    public BankAction getAction() {\n        return this.handle.getAction();\n    }\n\n    @Override\n    public int getPosition() {\n        return this.handle.getPosition();\n    }\n\n    @Override\n    public long getTime() {\n        return this.handle.getTime();\n    }\n\n    @Override\n    public String getDate() {\n        return this.handle.getDate();\n    }\n\n    @Override\n    public String getFailureReason() {\n        return this.handle.getFailureReason();\n    }\n\n    @Override\n    public BigDecimal getAmount() {\n        return this.handle.getAmount();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.bank;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class DelegateIslandBank implements IslandBank {\n\n    protected final IslandBank handle;\n\n    public DelegateIslandBank(IslandBank handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public BigDecimal getBalance() {\n        return this.handle.getBalance();\n    }\n\n    @Override\n    public void setBalance(BigDecimal balance) {\n        this.handle.setBalance(balance);\n    }\n\n    @Override\n    public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        return this.handle.depositMoney(superiorPlayer, amount);\n    }\n\n    @Override\n    public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount) {\n        return this.handle.depositAdminMoney(commandSender, amount);\n    }\n\n    @Override\n    public boolean canDepositMoney(BigDecimal amount) {\n        return this.handle.canDepositMoney(amount);\n    }\n\n    @Override\n    public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List<String> commandsToExecute) {\n        return this.handle.withdrawMoney(superiorPlayer, amount, commandsToExecute);\n    }\n\n    @Override\n    public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount) {\n        return this.handle.withdrawAdminMoney(commandSender, amount);\n    }\n\n    @Override\n    public List<BankTransaction> getAllTransactions() {\n        return this.handle.getAllTransactions();\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions(SuperiorPlayer superiorPlayer) {\n        return this.handle.getTransactions(superiorPlayer);\n    }\n\n    @Override\n    public List<BankTransaction> getConsoleTransactions() {\n        return this.handle.getConsoleTransactions();\n    }\n\n    @Override\n    public void loadTransaction(BankTransaction bankTransaction) {\n        this.handle.loadTransaction(bankTransaction);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/IslandBank.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.bank;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic interface IslandBank {\n\n    /**\n     * Get balance in bank.\n     */\n    BigDecimal getBalance();\n\n    /**\n     * Set the balance in the bank.\n     * This will not create any records, and used to load the balance from the database.\n     */\n    void setBalance(BigDecimal balance);\n\n    /**\n     * Deposit money into the bank.\n     *\n     * @param superiorPlayer The player that deposited the money.\n     * @param amount         The amount to deposit.\n     * @return The transaction details.\n     */\n    BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount);\n\n    /**\n     * Deposit money into the bank, without taking money from any player.\n     *\n     * @param commandSender The player that deposited the money.\n     * @param amount        The amount to deposit.\n     * @return The transaction details.\n     */\n    BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount);\n\n    /**\n     * Whether it's possible to deposit money into the bank without exceeding the bank limit.\n     *\n     * @param amount The amount of money to deposit.\n     */\n    boolean canDepositMoney(BigDecimal amount);\n\n    /**\n     * Withdraw money from the bank.\n     *\n     * @param superiorPlayer    The player that withdrawn the money.\n     * @param amount            The amount to withdraw.\n     * @param commandsToExecute Commands to execute instead of using the default economy provider.\n     *                          The commands can use {0} as player's name placeholder, and {1} for the amount.\n     * @return The transaction details.\n     */\n    BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List<String> commandsToExecute);\n\n    /**\n     * Withdraw money from the bank, without giving it to any player.\n     *\n     * @param commandSender The player that withdrawn the money.\n     * @param amount        The amount to withdraw.\n     * @return The transaction details.\n     */\n    BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount);\n\n    /**\n     * Get all the transactions of the bank, sorted by the time they were created.\n     */\n    List<BankTransaction> getAllTransactions();\n\n    /**\n     * Get all the transactions made by a player.\n     */\n    List<BankTransaction> getTransactions(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get all the transactions made by CONSOLE.\n     */\n    List<BankTransaction> getConsoleTransactions();\n\n    /**\n     * Load a transaction log.\n     * Used to load transactions from the database.\n     *\n     * @param bankTransaction The transaction object to load.\n     */\n    void loadTransaction(BankTransaction bankTransaction);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.cache;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.util.function.Function;\n\n/**\n * Island caches can be used by other plugins to store temporary data for an island, retrieve it, etc.\n * The cache is not persistent between server sessions. For persistent data solution, see {@link Island#getPersistentDataContainer()}\n * Data can be stored and retrieved by registering custom {@link IslandCacheKey} for your plugin.\n * The cache is thread-safe and can be accessed from multiple threads.\n */\npublic interface IslandCache {\n\n    /**\n     * Get the island this cache is for.\n     */\n    Island getIsland();\n\n    /**\n     * Store data in this cache.\n     *\n     * @param key   The key to store.\n     * @param value The value to store.\n     * @return The old value that was stored in the cache, or null if not data was cached.\n     */\n    @Nullable\n    <T> T store(IslandCacheKey<T> key, T value);\n\n    /**\n     * Remove data from this cache.\n     *\n     * @param key The cache key.\n     * @return The old value that was stored in the cache, or null if not data was cached.\n     */\n    @Nullable\n    <T> T remove(IslandCacheKey<T> key);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key The cache key\n     * @return The value stored for the provided key, or null if no data was cached.\n     */\n    @Nullable\n    <T> T get(IslandCacheKey<T> key);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key The cache key\n     * @param def The value to return in case the cache did not contain the provided key\n     * @return The value stored for the provided key.\n     */\n    <T> T getOrDefault(IslandCacheKey<T> key, T def);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key             The cache key\n     * @param mappingFunction The value to store in case the cache did not contain the provided key\n     * @return The value stored for the provided key.\n     */\n    <T> T computeIfAbsent(IslandCacheKey<T> key, Function<IslandCacheKey<T>, T> mappingFunction);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.cache;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class IslandCacheKey<T> implements Enumerable {\n\n    private static final Map<String, IslandCacheKey<?>> islandCacheKeys = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final Class<T> valueType;\n    private final int ordinal;\n\n    private IslandCacheKey(String name, Class<T> valueType) {\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.valueType = valueType;\n        this.ordinal = ordinalCounter++;\n    }\n\n    /**\n     * Get the name of the island cache key.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Get the type of the value for this cache-key.\n     */\n    public Class<T> getValueType() {\n        return valueType;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    @Override\n    public String toString() {\n        return \"IslandCacheKey{name=\" + name + \"}\";\n    }\n\n    /**\n     * Get all the island cache keys.\n     */\n    public static Collection<IslandCacheKey<?>> values() {\n        return islandCacheKeys.values();\n    }\n\n    /**\n     * Get an island cache key by its name.\n     *\n     * @param name The name to check.\n     */\n    public static IslandCacheKey<?> getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        IslandCacheKey<?> islandCacheKey = islandCacheKeys.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(islandCacheKey, \"Couldn't find an IslandCacheKey with the name \" + name + \".\");\n\n        return islandCacheKey;\n    }\n\n    /**\n     * Register a new island cache key.\n     *\n     * @param name The name for the island cache key.\n     */\n    public static <T> void register(String name, Class<T> valueType) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        name = name.toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!islandCacheKeys.containsKey(name), \"IslandCacheKey with the name \" + name + \" already exists.\");\n\n        islandCacheKeys.put(name, new IslandCacheKey<>(name, valueType));\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport org.bukkit.Location;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic class DelegateIslandsContainer implements IslandsContainer {\n\n    protected final IslandsContainer handle;\n\n    protected DelegateIslandsContainer(IslandsContainer handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public void addIsland(Island island) {\n        this.handle.addIsland(island);\n    }\n\n    @Override\n    public void removeIsland(Island island) {\n        this.handle.removeIsland(island);\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandByUUID(UUID uuid) {\n        return this.handle.getIslandByUUID(uuid);\n    }\n\n    @Override\n    public Island getIslandByName(String name) {\n        return this.handle.getIslandByName(name);\n    }\n\n    @Override\n    public void updateIslandName(Island island, String oldName) {\n        this.handle.updateIslandName(island, oldName);\n    }\n\n    @Nullable\n    @Override\n    @Deprecated\n    public Island getIslandByLeader(UUID uuid) {\n        return this.handle.getIslandByLeader(uuid);\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandAtPosition(int position, SortingType sortingType) {\n        return this.handle.getIslandAtPosition(position, sortingType);\n    }\n\n    @Override\n    public int getIslandPosition(Island island, SortingType sortingType) {\n        return this.handle.getIslandPosition(island, sortingType);\n    }\n\n    @Override\n    public int getIslandsAmount() {\n        return this.handle.getIslandsAmount();\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandAt(Location location) {\n        return this.handle.getIslandAt(location);\n    }\n\n    @Override\n    @Deprecated\n    public void transferIsland(UUID oldLeader, UUID newLeader) {\n        this.handle.transferIsland(oldLeader, newLeader);\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType, @Nullable Runnable onFinish) {\n        this.handle.sortIslands(sortingType, onFinish);\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish) {\n        this.handle.sortIslands(sortingType, forceSort, onFinish);\n    }\n\n    @Override\n    public void notifyChange(SortingType sortingType, Island island) {\n        this.handle.notifyChange(sortingType, island);\n    }\n\n    @Override\n    public List<Island> getSortedIslands(SortingType sortingType) {\n        return this.handle.getSortedIslands(sortingType);\n    }\n\n    @Override\n    public List<Island> getIslandsUnsorted() {\n        return this.handle.getIslandsUnsorted();\n    }\n\n    @Override\n    public void addSortingType(SortingType sortingType, boolean sort) {\n        this.handle.addSortingType(sortingType, sort);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic interface IslandsContainer {\n\n    /**\n     * Add an island to the islands container.\n     *\n     * @param island The island to add.\n     */\n    void addIsland(Island island);\n\n    /**\n     * Remove an island from the islands container.\n     *\n     * @param island The island to remove.\n     */\n    void removeIsland(Island island);\n\n    /**\n     * Get an island by its uuid.\n     *\n     * @param uuid The uuid of the island.\n     */\n    @Nullable\n    Island getIslandByUUID(UUID uuid);\n\n    /**\n     * Get an island by its name.\n     *\n     * @param name The name of the island.\n     */\n    @Nullable\n    Island getIslandByName(String name);\n\n    /**\n     * Update an island with a new name.\n     *\n     * @param island  The island to update.\n     * @param oldName The old name of the island.\n     */\n    void updateIslandName(Island island, String oldName);\n\n    /**\n     * Get an island by its leader's uuid.\n     *\n     * @param uuid The uuid of the island's leader.\n     * @deprecated Not supported anymore.\n     */\n    @Nullable\n    @Deprecated\n    default Island getIslandByLeader(UUID uuid) {\n        return SuperiorSkyblockAPI.getGrid().getIsland(uuid);\n    }\n\n    /**\n     * Get an island by its position in the top-islands.\n     *\n     * @param position    The position of the island.\n     * @param sortingType The sorting-type to get islands from.\n     */\n    @Nullable\n    Island getIslandAtPosition(int position, SortingType sortingType);\n\n    /**\n     * Get the position of an island in the top-islands.\n     *\n     * @param island      The island to get position of.\n     * @param sortingType The sorting-type to get islands from.\n     */\n    int getIslandPosition(Island island, SortingType sortingType);\n\n    /**\n     * Get the amount of islands on the server.\n     */\n    int getIslandsAmount();\n\n    /**\n     * Get an island at a location.\n     *\n     * @param location The location to get island in.\n     */\n    @Nullable\n    Island getIslandAt(Location location);\n\n    /**\n     * Transfer an island from a player to another one.\n     * Warning: If you don't know what you're doing, do not use this method.\n     * Instead, use {@link Island#transferIsland(SuperiorPlayer)}.\n     *\n     * @param oldLeader The uuid of the current leader.\n     * @param newLeader The uuid of the new leader.\n     * @deprecated Not supported anymore.\n     */\n    @Deprecated\n    default void transferIsland(UUID oldLeader, UUID newLeader) {\n\n    }\n\n    /**\n     * Sort islands for the top-islands.\n     * The islands will not get sorted if only one island exists, or no changes\n     * were tracked by {@link #notifyChange(SortingType, Island)}\n     *\n     * @param sortingType The type of sorting to use.\n     * @param onFinish    Callback method\n     */\n    void sortIslands(SortingType sortingType, @Nullable Runnable onFinish);\n\n    /**\n     * Sort islands for the top-islands.\n     *\n     * @param sortingType The type of sorting to use.\n     * @param forceSort   Whether to force-sort the islands.\n     *                    When true, islands will get sorted even if only one island exists.\n     * @param onFinish    Callback method\n     */\n    void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish);\n\n    /**\n     * Notify about a change of a value for a specific sorting type for an island.\n     *\n     * @param sortingType The sorting-type.\n     * @param island      The island that had its value changed.\n     */\n    void notifyChange(SortingType sortingType, Island island);\n\n    /**\n     * Get all islands sorted by a specific sorting-type.\n     *\n     * @param sortingType The type of sorting to use.\n     */\n    List<Island> getSortedIslands(SortingType sortingType);\n\n    /**\n     * Get all islands.\n     */\n    List<Island> getIslandsUnsorted();\n\n    /**\n     * Add a new sorting-type.\n     *\n     * @param sortingType The sorting-type to add.\n     * @param sort        Whether to sort the islands or not when the sorting-type is added.\n     */\n    void addSortingType(SortingType sortingType, boolean sort);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.warps;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\n\npublic class DelegateIslandWarp implements IslandWarp {\n\n    protected final IslandWarp handle;\n\n    protected DelegateIslandWarp(IslandWarp handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public Island getIsland() {\n        return this.handle.getIsland();\n    }\n\n    @Override\n    public String getName() {\n        return this.handle.getName();\n    }\n\n    @Override\n    public void setName(String name) {\n        this.handle.setName(name);\n    }\n\n    @Override\n    public Location getLocation() {\n        return this.handle.getLocation();\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        return this.handle.getLocation(location);\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        this.handle.setLocation(location);\n    }\n\n    @Override\n    public WorldPosition getPosition() {\n        return this.handle.getPosition();\n    }\n\n    @Override\n    public Dimension getPositionDimension() {\n        return this.handle.getPositionDimension();\n    }\n\n    @Override\n    public void setPosition(Dimension dimension, WorldPosition worldPosition) {\n        this.handle.setPosition(dimension, worldPosition);\n    }\n\n    @Override\n    public boolean hasPrivateFlag() {\n        return this.handle.hasPrivateFlag();\n    }\n\n    @Override\n    public void setPrivateFlag(boolean privateFlag) {\n        this.handle.setPrivateFlag(privateFlag);\n    }\n\n    @Nullable\n    @Override\n    public ItemStack getRawIcon() {\n        return this.handle.getRawIcon();\n    }\n\n    @Nullable\n    @Override\n    public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) {\n        return this.handle.getIcon(superiorPlayer);\n    }\n\n    @Override\n    public void setIcon(@Nullable ItemStack icon) {\n        this.handle.setIcon(icon);\n    }\n\n    @Override\n    public WarpCategory getCategory() {\n        return this.handle.getCategory();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.warps;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\npublic class DelegateWarpCategory implements WarpCategory {\n\n    protected final WarpCategory handle;\n\n    protected DelegateWarpCategory(WarpCategory handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public Island getIsland() {\n        return this.handle.getIsland();\n    }\n\n    @Override\n    public String getName() {\n        return this.handle.getName();\n    }\n\n    @Override\n    public void setName(String name) {\n        this.handle.setName(name);\n    }\n\n    @Override\n    public List<IslandWarp> getWarps() {\n        return this.handle.getWarps();\n    }\n\n    @Override\n    public int getSlot() {\n        return this.handle.getSlot();\n    }\n\n    @Override\n    public void setSlot(int slot) {\n        this.handle.setSlot(slot);\n    }\n\n    @Override\n    public ItemStack getRawIcon() {\n        return this.handle.getRawIcon();\n    }\n\n    @Override\n    public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) {\n        return this.handle.getIcon(superiorPlayer);\n    }\n\n    @Override\n    public void setIcon(@Nullable ItemStack icon) {\n        this.handle.setIcon(icon);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.warps;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface IslandWarp {\n\n    /**\n     * Get the island of this warp.\n     */\n    Island getIsland();\n\n    /**\n     * Get the name of the warp.\n     */\n    String getName();\n\n    /**\n     * Set the name of the warp.\n     * Do not call this method - use Island#renameWarp instead!\n     *\n     * @param name The new name to set.\n     */\n    void setName(String name);\n\n    /**\n     * Get the location of the warp.\n     */\n    Location getLocation();\n\n    /**\n     * Get the location of the warp.\n     *\n     * @param location Location object to re-use.\n     */\n    @Nullable\n    Location getLocation(@Nullable Location location);\n\n    /**\n     * Set the location of the warp.\n     *\n     * @param location The new location to set.\n     */\n    void setLocation(Location location);\n\n    /**\n     * Get the position of the warp.\n     */\n    WorldPosition getPosition();\n\n    /**\n     * Get the dimension of the position of the warp.\n     */\n    Dimension getPositionDimension();\n\n    /**\n     * Set the position of the warp.\n     *\n     * @param dimension     The dimension of the new position to set.\n     * @param worldPosition The new position to set.\n     */\n    void setPosition(Dimension dimension, WorldPosition worldPosition);\n\n    /**\n     * Check if the warp is private or public to visitors.\n     */\n    boolean hasPrivateFlag();\n\n    /**\n     * Set the private flag of the island warp.\n     *\n     * @param privateFlag The flag to set.\n     */\n    void setPrivateFlag(boolean privateFlag);\n\n    /**\n     * Get the icon of the warp.\n     * May be null if the warp has no special icon.\n     */\n    @Nullable\n    ItemStack getRawIcon();\n\n    /**\n     * Get the icon of the warp after all placeholders are parsed.\n     * May be null if the warp has no special icon.\n     *\n     * @param superiorPlayer The player to parse the placeholders for\n     */\n    @Nullable\n    ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer);\n\n    /**\n     * Set the icon of the warp.\n     * May be null if the warp should have no special icon.\n     *\n     * @param icon The icon to set.\n     */\n    void setIcon(@Nullable ItemStack icon);\n\n    /**\n     * Get the category of the warp.\n     */\n    WarpCategory getCategory();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/WarpCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.island.warps;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\npublic interface WarpCategory {\n\n    /**\n     * Get the island of this category.\n     */\n    Island getIsland();\n\n    /**\n     * Get the name of the warp category.\n     */\n    String getName();\n\n    /**\n     * Set a new name to the category.\n     * Do not call this method - use Island#renameCategory instead!\n     *\n     * @param name The new name to set.\n     */\n    void setName(String name);\n\n    /**\n     * Get all the warps of this category.\n     */\n    List<IslandWarp> getWarps();\n\n    /**\n     * Get the slot of the category.\n     */\n    int getSlot();\n\n    /**\n     * Set the slot of the category.\n     *\n     * @param slot The slot to set.\n     */\n    void setSlot(int slot);\n\n    /**\n     * Get the icon of the category.\n     */\n    ItemStack getRawIcon();\n\n    /**\n     * Get the icon of the category after all placeholders are parsed.\n     *\n     * @param superiorPlayer The player to parse the placeholders for\n     */\n    ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer);\n\n    /**\n     * Set the icon of the category.\n     *\n     * @param icon The icon to set. If null, default icon will be set.\n     */\n    void setIcon(@Nullable ItemStack icon);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/key/CustomKeyParser.java",
    "content": "package com.bgsoftware.superiorskyblock.api.key;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface CustomKeyParser {\n\n    /**\n     * Get a custom key for a block.\n     * Please note: this method should support async calls.\n     *\n     * @param location The location of the block.\n     */\n    @Nullable\n    default Key getCustomKey(Location location) {\n        return null;\n    }\n\n    /**\n     * Get a custom key for an entity.\n     * Please note: this method should support async calls.\n     *\n     * @param entity The entity to check.\n     */\n    @Nullable\n    default Key getCustomKey(Entity entity) {\n        return null;\n    }\n\n    /**\n     * Get a custom key for an item-stack.\n     * Please note: this method should support async calls.\n     *\n     * @param itemStack The item-stack to parse.\n     * @param def       The original key of the item.\n     */\n    default Key getCustomKey(ItemStack itemStack, Key def) {\n        return def;\n    }\n\n    /**\n     * Check if a key was created by this parser.\n     *\n     * @param key The key to check.\n     */\n    boolean isCustomKey(Key key);\n\n    /**\n     * Get the custom item of the custom key.\n     * The provided key is guaranteed to pass the {@link #isCustomKey(Key)} check.\n     *\n     * @param key The key to get the custom item for.\n     * @return The item stack for that custom key, or null for using the default one.\n     */\n    @Nullable\n    default ItemStack getCustomKeyItem(Key key) {\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/key/Key.java",
    "content": "package com.bgsoftware.superiorskyblock.api.key;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\n/**\n * Used as a wrapper for objects into material & data object.\n */\npublic interface Key extends Comparable<Key> {\n\n    /**\n     * Get the key of an entity type.\n     *\n     * @param entityType The entity type to create key for.\n     */\n    static Key of(EntityType entityType) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(entityType);\n    }\n\n    /**\n     * Get the key of an entity type.\n     *\n     * @param entityTypeName The name of the entity type to create key for.\n     */\n    static Key ofEntityType(String entityTypeName) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getEntityTypeKey(entityTypeName);\n    }\n\n    /**\n     * Get the key of an entity.\n     *\n     * @param entity The entity to check.\n     */\n    static Key of(Entity entity) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(entity);\n    }\n\n    /**\n     * Get the key of a block.\n     *\n     * @param block The block to create key for.\n     */\n    static Key of(Block block) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(block);\n    }\n\n    /**\n     * Get the key of a block-state.\n     *\n     * @param blockState The block-state to create key for.\n     */\n    static Key of(BlockState blockState) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(blockState);\n    }\n\n    /**\n     * Get the key of an item-stack.\n     *\n     * @param itemStack The item-stack to create key for.\n     */\n    static Key of(ItemStack itemStack) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(itemStack);\n    }\n\n    /**\n     * Get the key of a material and data.\n     *\n     * @param material The material to create key for.\n     * @param data     The data to create key for.\n     */\n    static Key of(Material material, short data) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(material, data);\n    }\n\n    /**\n     * Get the key of a material.\n     *\n     * @param material The material to create key for.\n     */\n    static Key of(Material material) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(material);\n    }\n\n    /**\n     * Get the key of a material and data.\n     *\n     * @param type The combined material-data pair to create key for.\n     */\n    static Key ofMaterialAndData(String type) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getMaterialAndDataKey(type);\n    }\n\n    /**\n     * Get the key of a spawner block with specific entity type.\n     *\n     * @param entityType The entity type of the spawner to create key for.\n     */\n    static Key ofSpawner(EntityType entityType) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getSpawnerKey(entityType);\n    }\n\n    /**\n     * Get the key of a spawner block with specific entity type.\n     *\n     * @param entityTypeName The name of the entity type of the spawner to create key for.\n     */\n    static Key ofSpawner(String entityTypeName) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getSpawnerKey(entityTypeName);\n    }\n\n    /**\n     * Get the key of a global-key and a sub-key.\n     * It is recommended to use the other Key#of methods whenever possible, and only use this one\n     * for custom keys that has no Key#of methods.\n     *\n     * @param globalKey The global key\n     * @param subKey    The sub key\n     */\n    static Key of(String globalKey, String subKey) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(globalKey, subKey);\n    }\n\n    /**\n     * Get the key of a string.\n     * It is recommended to use the other Key#of methods whenever possible, and only use this one\n     * for custom keys that has no Key#of methods.\n     *\n     * @param key The string to check.\n     */\n    static Key of(String key) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(key);\n    }\n\n    /**\n     * Get the global key of this key instance.\n     */\n    String getGlobalKey();\n\n    /**\n     * Get the sub key of this key instance.\n     */\n    String getSubKey();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/key/KeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.api.key;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\n\n/**\n * {@link Map} implementation for handling keys.\n * The difference between this map and a regular {@link Map} is that this map handles checks for\n * global keys as well as individual ones.\n * <p>\n * For example, if this map has \"STONE\" as a key inside it, the {@link #get(Object)} method will return the value\n * of that key when \"STONE\" is provided, as well as any other key with a different sub-key (\"STONE:0\", for example).\n * <p>\n * However, if this set has \"STONE:0\" as a key, as well as the global key inside it, the {@link #get(Object)} method\n * will return the value of the exact same key and not its global key (Therefore, the value of \"STONE:0\" will be\n * returned if \"STONE:0\" is provided, and the value of \"STONE\" will be provided if \"STONE:1\" is provided)\n */\npublic interface KeyMap<V> extends Map<Key, V> {\n\n    /**\n     * Create a new empty {@link KeyMap<V>} instance.\n     *\n     * @param mapCreator The map creator for the inner-map of the new {@link KeyMap}\n     */\n    static <V> KeyMap<V> createKeyMap(Supplier<Map<String, V>> mapCreator) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(mapCreator);\n    }\n\n    /**\n     * Create a new empty {@link KeyMap<V>} instance based on {@link HashMap}.\n     */\n    static <V> KeyMap<V> createKeyMap() {\n        return createKeyMap(() -> new HashMap<>());\n    }\n\n    /**\n     * Create a new {@link KeyMap<V>} instance from the given map based on {@link HashMap}.\n     * If the provided map is also a {@link KeyMap<V>}, the exact same instance of that map is returned.\n     * Otherwise, the returned {@link KeyMap<V>} is a copy of that map.\n     *\n     * @param map The map to create {@link KeySet} from.\n     */\n    static <V> KeyMap<V> createKeyMap(Map<Key, V> map) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(() -> new HashMap<>(), map);\n    }\n\n    /**\n     * Create a new empty {@link KeyMap<V>} instance based on {@link ConcurrentHashMap}.\n     */\n    static <V> KeyMap<V> createConcurrentKeyMap() {\n        return createKeyMap(() -> new ConcurrentHashMap<>());\n    }\n\n    /**\n     * Create a new {@link KeyMap<V>} instance from the given map based on {@link ConcurrentHashMap}.\n     * If the provided map is also a {@link KeyMap<V>}, the exact same instance of that map is returned.\n     * Otherwise, the returned {@link KeyMap<V>} is a copy of that map.\n     *\n     * @param map The map to create {@link KeySet} from.\n     */\n    static <V> KeyMap<V> createConcurrentKeyMap(Map<Key, V> map) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(() -> new ConcurrentHashMap<>(), map);\n    }\n\n    /**\n     * Create a collector for {@link KeyMap} that can be used in streams.\n     *\n     * @param keyMapper   The key mapper to apply.\n     * @param valueMapper The values mapper to apply.\n     * @param mapCreator  The map creator for the inner-map of the new {@link KeyMap}\n     */\n    static <K, V> Collector<K, ?, KeyMap<V>> getCollector(Function<? super K, ? extends Key> keyMapper,\n                                                          Function<? super K, ? extends V> valueMapper,\n                                                          Supplier<Map<String, V>> mapCreator) {\n        return Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> {\n            throw new IllegalStateException(String.format(\"Duplicate key %s\", v1));\n        }, () -> createKeyMap(mapCreator));\n    }\n\n    /**\n     * Create a collector for {@link KeyMap} based on {@link HashMap} that can be used in streams\n     *\n     * @param keyMapper   The key mapper to apply.\n     * @param valueMapper The values mapper to apply.\n     */\n    static <K, V> Collector<K, ?, KeyMap<V>> getCollector(Function<? super K, ? extends Key> keyMapper,\n                                                          Function<? super K, ? extends V> valueMapper) {\n        return Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> {\n            throw new IllegalStateException(String.format(\"Duplicate key %s\", v1));\n        }, KeyMap::createKeyMap);\n    }\n\n    /**\n     * Get the key that is similar to the provided key.\n     * For example, if {@param original} is \"STONE:0\", and the map contains only \"STONE\", \"STONE\" will be returned.\n     * However, if the map contains \"STONE\" as well as \"STONE:0\", \"STONE:0\" will be returned.\n     * If the key is not inside the map, null will be returned.\n     *\n     * @param original The original key.\n     */\n    @Nullable\n    Key getKey(Key original);\n\n    /**\n     * Get the key that is similar to the provided key.\n     * For example, if {@param original} is \"STONE:0\", and the map contains only \"STONE\", \"STONE\" will be returned.\n     * However, if the map contains \"STONE\" as well as \"STONE:0\", \"STONE:0\" will be returned.\n     * If the key is not inside the map, {@param def} will be returned.\n     *\n     * @param original The original key.\n     * @param def      Default key to be returned if {@param original} is not in the map.\n     */\n    Key getKey(Key original, @Nullable Key def);\n\n    /**\n     * Get a value from the key without checking for global keys or other similar keys.\n     * This means that if the map doesn't contain {@param key}, {@param def} will be returned.\n     * This is a similar behavior to a regular {@link Map}\n     *\n     * @param key The key to check\n     * @param def The default value to return.\n     */\n    V getRaw(Key key, V def);\n\n    /**\n     * See {@link java.util.Collection#removeIf(Predicate)}\n     */\n    boolean removeIf(Predicate<Key> predicate);\n\n    /**\n     * Return a regular {@link java.util.HashMap} with the keys and values of this map.\n     */\n    Map<Key, V> asMap();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/key/KeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.api.key;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\n/**\n * {@link Set} implementation for handling keys.\n * The difference between this set and a regular {@link Set} is that this set handles checks for\n * global keys as well as individual ones.\n * <p>\n * For example, if this set has \"STONE\" as a key inside it, the {@link #contains(Object)} method will return true\n * if \"STONE\" is provided, as well as any other key with a different sub-key (\"STONE:0\", for example).\n * <p>\n * However, if this set only has \"STONE:0\" as a key inside it, the {@link #contains(Object)} method will only return\n * true for the exact same keys (Therefore, \"STONE\" will return false alongside of any other key with a different\n * sub-key)\n */\npublic interface KeySet extends Set<Key> {\n\n    /**\n     * Create a new empty {@link KeySet} instance.\n     *\n     * @param setCreator The set creator for the inner-set of the new {@link KeySet}\n     */\n    static KeySet createKeySet(Supplier<Set<String>> setCreator) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeySet(setCreator);\n    }\n\n    /**\n     * Create a new empty {@link KeySet} instance based on {@link HashSet}\n     */\n    static KeySet createKeySet() {\n        return createKeySet(HashSet::new);\n    }\n\n    /**\n     * Create a new {@link KeySet} instance from the given collection based on {@link HashSet}.\n     * If the provided collection is also a {@link KeySet}, the exact same instance of that set is returned.\n     * Otherwise, the returned {@link KeySet} is a copy of that collection.\n     *\n     * @param collection The collection to create {@link KeySet} from.\n     */\n    static KeySet createKeySet(Collection<Key> collection) {\n        return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeySet(HashSet::new, collection);\n    }\n\n    /**\n     * Get the key that is similar to the provided key.\n     * For example, if {@param original} is \"STONE:0\", and the set contains only \"STONE\", \"STONE\" will be returned.\n     * However, if the set contains \"STONE\" as well as \"STONE:0\", \"STONE:0\" will be returned.\n     * If the key is not inside the map, null will be returned.\n     *\n     * @param original The original key.\n     */\n    @Nullable\n    Key getKey(Key original);\n\n    /**\n     * Get the key that is similar to the provided key.\n     * For example, if {@param original} is \"STONE:0\", and the set contains only \"STONE\", \"STONE\" will be returned.\n     * However, if the set contains \"STONE\" as well as \"STONE:0\", \"STONE:0\" will be returned.\n     * If the key is not inside the map, {@param def} will be returned.\n     *\n     * @param original The original key.\n     * @param def      Default key to be returned if {@param original} is not in the map.\n     */\n    Key getKey(Key original, Key def);\n\n    /**\n     * Return a regular {@link java.util.HashSet} with the keys of this set.\n     */\n    Set<Key> asSet();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/BaseMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\n/**\n * Basic implementation of a menu for easily creating new ones with the API.\n * If you want a {@link PagedMenu}, extend this class and implement the {@link PagedMenu} interface.\n * Make sure you use {@link #addView(MenuView)} and {@link #removeView(MenuView)} when creating and deleting views.\n */\npublic abstract class BaseMenu<V extends MenuView<V, A>, A extends ViewArgs> implements Menu<V, A> {\n\n    protected final List<V> openedMenuViews = new LinkedList<>();\n\n    protected final String identifier;\n    protected final MenuLayout<V> menuLayout;\n    @Nullable\n    protected final GameSound openingSound;\n    protected final boolean isPreviousMoveAllowed;\n    protected final boolean isSkipOneItem;\n\n    protected BaseMenu(String identifier, MenuLayout<V> menuLayout, @Nullable GameSound openingSound,\n                       boolean isPreviousMoveAllowed, boolean isSkipOneItem) {\n        Preconditions.checkNotNull(identifier, \"identifier parameter cannot be null.\");\n        Preconditions.checkNotNull(menuLayout, \"menuLayout parameter cannot be null.\");\n        this.identifier = identifier;\n        this.menuLayout = menuLayout;\n        this.openingSound = openingSound;\n        this.isPreviousMoveAllowed = isPreviousMoveAllowed;\n        this.isSkipOneItem = isSkipOneItem;\n    }\n\n    @Override\n    public String getIdentifier() {\n        return this.identifier;\n    }\n\n    @Override\n    public MenuLayout<V> getLayout() {\n        return this.menuLayout;\n    }\n\n    @Override\n    @Nullable\n    public GameSound getOpeningSound() {\n        return this.openingSound;\n    }\n\n    @Override\n    public boolean isPreviousMoveAllowed() {\n        return this.isPreviousMoveAllowed;\n    }\n\n    @Override\n    public boolean isSkipOneItem() {\n        return this.isSkipOneItem || SuperiorSkyblockAPI.getSettings().isSkipOneItemMenus();\n    }\n\n    @Override\n    public CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(args, \"args parameter cannot be null.\");\n        Preconditions.checkState(superiorPlayer.isOnline(), \"Cannot create view for offline player: \" + superiorPlayer.getName());\n        return this.createView(superiorPlayer, args, superiorPlayer.getOpenedView());\n    }\n\n    @Override\n    public abstract CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView<?, ?> previousMenu);\n\n    @Override\n    public void refreshViews() {\n        synchronized (openedMenuViews) {\n            openedMenuViews.forEach(V::refreshView);\n        }\n    }\n\n    @Override\n    public void refreshViews(Predicate<V> viewFilter) {\n        filterViews(viewFilter, V::refreshView);\n    }\n\n    @Override\n    public void closeViews() {\n        synchronized (openedMenuViews) {\n            openedMenuViews.forEach(V::closeView);\n        }\n    }\n\n    @Override\n    public void closeViews(Predicate<V> viewFilter) {\n        filterViews(viewFilter, V::closeView);\n    }\n\n    public void addView(V view) {\n        synchronized (openedMenuViews) {\n            openedMenuViews.add(view);\n        }\n    }\n\n    public void removeView(V view) {\n        synchronized (openedMenuViews) {\n            openedMenuViews.remove(view);\n        }\n    }\n\n    protected final void filterViews(Predicate<V> viewFilter, Consumer<V> onMatch) {\n        synchronized (openedMenuViews) {\n            openedMenuViews.forEach(view -> {\n                if (viewFilter.test(view))\n                    onMatch.accept(view);\n            });\n        }\n    }\n\n    @Override\n    public void onClick(InventoryClickEvent clickEvent, V menuView) {\n        if (clickEvent.getCurrentItem() == null)\n            return;\n\n        Preconditions.checkNotNull(this.menuLayout, \"menu wasn't initialized properly.\");\n\n        MenuViewButton<V> menuButton = this.menuLayout.getButton(clickEvent.getRawSlot()).createViewButton(menuView);\n\n        String requiredPermission = menuButton.getTemplate().getRequiredPermission();\n        if (requiredPermission != null && !menuView.getInventoryViewer().hasPermission(requiredPermission)) {\n            onButtonClickLackPermission(menuButton, clickEvent);\n            return;\n        }\n\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        GameSound clickSound = menuButton.getTemplate().getClickSound();\n        if (clickSound != null)\n            player.playSound(player.getLocation(), clickSound.getSound(), clickSound.getVolume(), clickSound.getPitch());\n\n        menuButton.getTemplate().getClickCommands().forEach(command ->\n                MenuCommands.getInstance().runCommand(menuView, command, clickEvent));\n\n        if (onPreButtonClick(menuButton, clickEvent))\n            menuButton.onButtonClick(clickEvent);\n    }\n\n    @Override\n    public final void onClose(InventoryCloseEvent closeEvent, V menuView) {\n        removeView(menuView);\n        this.onCloseInternal(closeEvent, menuView);\n    }\n\n    protected abstract boolean onPreButtonClick(MenuViewButton<V> menuButton, InventoryClickEvent clickEvent);\n\n    protected abstract void onButtonClickLackPermission(MenuViewButton<V> menuButton, InventoryClickEvent clickEvent);\n\n    protected abstract void onCloseInternal(InventoryCloseEvent closeEvent, V menuView);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/ISuperiorMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\n\n/**\n * @deprecated See {@link MenuView}\n */\n@Deprecated\npublic interface ISuperiorMenu extends MenuView {\n\n    /**\n     * Clone and open this menu to the {@link #getInventoryViewer()}\n     *\n     * @param previousMenu The previous menu to set.\n     */\n    void cloneAndOpen(@Nullable ISuperiorMenu previousMenu);\n\n    /**\n     * Get the previous menu of this menu.\n     */\n    @Nullable\n    ISuperiorMenu getPreviousMenu();\n\n    /**\n     * Helper method to cast the new {@link MenuView} object to the old {@link ISuperiorMenu} object.\n     */\n    @Deprecated\n    static ISuperiorMenu convertFromView(MenuView<?, ?> menuView) {\n        return SuperiorSkyblockAPI.getMenus().getOldMenuFromView(menuView);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/Menu.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.handlers.MenusManager;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Predicate;\n\n/**\n * Represents a menu of the plugin.\n * You can get an instance of a menu by its identifier using {@link MenusManager#getMenu(String)}\n * The instances of the menus are singleton, and there will be only one instance of each menu per session.\n */\npublic interface Menu<V extends MenuView<V, A>, A extends ViewArgs> {\n\n    /**\n     * Get the identifier of the menu.\n     */\n    String getIdentifier();\n\n    /**\n     * Get the layout of the menu.\n     */\n    MenuLayout<V> getLayout();\n\n    /**\n     * Get the sound to play when opening the menu.\n     */\n    @Nullable\n    GameSound getOpeningSound();\n\n    /**\n     * Get whether it is possible to open the previous opened menu after closing this one.\n     */\n    boolean isPreviousMoveAllowed();\n\n    /**\n     * Get whether this menu should be skipped when it only contains one item.\n     * This is only useful for menus that have their buttons open other menus.\n     */\n    boolean isSkipOneItem();\n\n    /**\n     * Create a new menu view for a player.\n     * If the player already has a view opened, make sure you call {@link MenuView#setPreviousMove(boolean)} on\n     * the opened view and pass 'false' as an argument, otherwise unexpected behavior may occur.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param args           The arguments for the linked {@link V} menu view.\n     */\n    CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args);\n\n    /**\n     * Create a new menu view for a player.\n     * If the player already has a view opened, make sure you call {@link MenuView#setPreviousMove(boolean)} on\n     * the opened view and pass 'false' as an argument, otherwise unexpected behavior may occur.\n     *\n     * @param superiorPlayer The player to open the menu for.\n     * @param args           The arguments for the linked {@link V} menu view.\n     * @param previousMenu   The previous menu to use. In most cases, this will be null.\n     */\n    CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView<?, ?> previousMenu);\n\n    void refreshViews();\n\n    void refreshViews(Predicate<V> viewFilter);\n\n    void closeViews();\n\n    void closeViews(Predicate<V> viewFilter);\n\n    /**\n     * Callback method for when a player clicks on a button in a view of this menu.\n     * This method should do necessary checks, and finally call {@link MenuViewButton#onButtonClick(InventoryClickEvent)}\n     * on the button that was clicked (can be retrieved by using {@link InventoryClickEvent#getRawSlot()} as a slot\n     * passed to {@link MenuLayout#getButton(int)})\n     *\n     * @param clickEvent The event associated with the click.\n     * @param menuView   The menu view that was clicked.\n     */\n    void onClick(InventoryClickEvent clickEvent, V menuView);\n\n    /**\n     * Callback method for when a player closes a view of this menu.\n     * The method has no limits on what can be done inside it, and it depends on your custom {@link V} implementation\n     * of what to do inside it.\n     *\n     * @param closeEvent The associated event.\n     * @param menuView   The menu view that was closed.\n     */\n    void onClose(InventoryCloseEvent closeEvent, V menuView);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuCommands.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\n/**\n * Singleton class used to parse and execute commands from menus.\n * You can get the instance of this executor by calling {@link #getInstance()}\n */\npublic interface MenuCommands {\n\n    void runCommand(MenuView<?, ?> menuView, String command, InventoryClickEvent clickEvent);\n\n    static MenuCommands getInstance() {\n        return SuperiorSkyblockAPI.getMenus().getMenuCommands();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport org.bukkit.block.Biome;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\n\n/**\n * Configuration for creation of new islands.\n * The values from this configuration are used in {@link GridManager#createIsland}\n */\npublic interface MenuIslandCreationConfig {\n\n    /**\n     * Get the schematic that will be used to create the island.\n     */\n    Schematic getSchematic();\n\n    /**\n     * Get the sound to play when the island is successfully created.\n     */\n    @Nullable\n    GameSound getSound();\n\n    /**\n     * Get the commands to execute when island is successfully created.\n     */\n    Collection<String> getCommands();\n\n    /**\n     * Get whether the island-values (worth & level) should be offset to 0 when the island is created.\n     */\n    boolean shouldOffsetIslandValue();\n\n    /**\n     * Custom worth bonus when the island is created.\n     */\n    BigDecimal getBonusWorth();\n\n    /**\n     * Custom level bonus when the island is created.\n     */\n    BigDecimal getBonusLevel();\n\n    /**\n     * Get the spawn offset of the island's home location from where the schematic was placed.\n     */\n    @Nullable\n    BlockOffset getSpawnOffset();\n\n    /**\n     * Get the biome to set to the new island.\n     */\n    Biome getBiome();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/PagedMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu;\n\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\n\n/**\n * Similar to {@link Menu}, but used for describing page-based menus.\n * See {@link Menu}\n */\npublic interface PagedMenu<V extends PagedMenuView<V, A, E>, A extends ViewArgs, E> extends Menu<V, A> {\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/MenuTemplateButton.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.button;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\n/**\n * The template button class is used to store data about the button.\n * For example, the item to display, the sounds and other data of the button, etc.\n */\npublic interface MenuTemplateButton<V extends MenuView<V, ?>> {\n\n    /**\n     * Get the item to display in the menu.\n     * The returned item has no changes to it (placeholders are unparsed, for example).\n     * This item is later used in {@link MenuViewButton#createViewItem()}\n     */\n    @Nullable\n    ItemStack getButtonItem();\n\n    /**\n     * Get the sound to play when clicking the button.\n     */\n    @Nullable\n    GameSound getClickSound();\n\n    /**\n     * Get the commands to run when clicking the button.\n     */\n    List<String> getClickCommands();\n\n    /**\n     * Get the required permission for clicking the button.\n     */\n    @Nullable\n    String getRequiredPermission();\n\n    /**\n     * Get the sound to play when clicking the button without having {@link #getRequiredPermission()} permission.\n     */\n    @Nullable\n    GameSound getLackPermissionSound();\n\n    /**\n     * Get the class type of view buttons created using {@link #createViewButton(MenuView)}\n     */\n    Class<?> getViewButtonType();\n\n    /**\n     * Create a view-button object to be used by the provided menu view.\n     * Unlike the template button, the view button handles the logic for buttons within the view.\n     *\n     * @param menuView The view to create the button for.\n     */\n    MenuViewButton<V> createViewButton(V menuView);\n\n    /**\n     * Create a new {@link Builder} object for a new {@link MenuTemplateButton}.\n     *\n     * @param viewButtonCreator The creator used to create a view-button by the builder.\n     *                          You will probably want to implement your own {@link MenuViewButton} which will be\n     *                          returned by this creator.\n     */\n    static <V extends MenuView<V, ?>> Builder<V> newBuilder(Class<?> viewButtonType, MenuViewButtonCreator<V> viewButtonCreator) {\n        return SuperiorSkyblockAPI.getMenus().createButtonBuilder(viewButtonType, viewButtonCreator);\n    }\n\n    interface Builder<V extends MenuView<V, ?>> {\n\n        /**\n         * Set the item to display in the menu.\n         *\n         * @param buttonItem The item.\n         */\n        Builder<V> setButtonItem(@Nullable ItemStack buttonItem);\n\n        /**\n         * Set the sound to play when clicking the button.\n         *\n         * @param clickSound The sound to play.\n         */\n        Builder<V> setClickSound(@Nullable GameSound clickSound);\n\n        /**\n         * Set the commands to run when clicking the button.\n         *\n         * @param commands The commands to run.\n         */\n        Builder<V> setClickCommands(@Nullable List<String> commands);\n\n        /**\n         * Set the required permission for clicking the button.\n         *\n         * @param requiredPermission The required permission for using the button.\n         */\n        Builder<V> setRequiredPermission(@Nullable String requiredPermission);\n\n        /**\n         * Set the sound to play when clicking the button without having {@link #getRequiredPermission()} permission.\n         *\n         * @param lackPermissionSound The sound to play.\n         */\n        Builder<V> setLackPermissionsSound(@Nullable GameSound lackPermissionSound);\n\n        /**\n         * Get the {@link MenuTemplateButton} from this builder.\n         */\n        MenuTemplateButton<V> build();\n\n    }\n\n    interface MenuViewButtonCreator<V extends MenuView<V, ?>> {\n\n        /**\n         * Create a new {@link MenuViewButton}.\n         * You will probably want to implement your own {@link MenuViewButton} which will be\n         * returned by this creator.\n         */\n        MenuViewButton<V> create(MenuTemplateButton<V> templateButton, V menuView);\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/MenuViewButton.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.button;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton.MenuViewButtonCreator;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\n/**\n * The {@link MenuViewButton} is used to run custom logic for buttons inside menu views.\n * You will want to implement this interface with your own custom logic, and then later use your custom\n * view button with the {@link MenuViewButtonCreator}.\n */\npublic interface MenuViewButton<V extends MenuView<V, ?>> {\n\n    /**\n     * Get the template that was used to create this view button.\n     */\n    MenuTemplateButton<V> getTemplate();\n\n    /**\n     * Get the view that this button is used in.\n     */\n    V getView();\n\n    /**\n     * Create a new view item for this button.\n     * This should use {@link MenuTemplateButton#getButtonItem()}\n     */\n    ItemStack createViewItem();\n\n    /**\n     * Method callback when clicking this button.\n     * The event passed as an argument is already cancelled.\n     *\n     * @param clickEvent The click event.\n     */\n    void onButtonClick(InventoryClickEvent clickEvent);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.button;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.inventory.ItemStack;\n\n/**\n * Similar to {@link MenuTemplateButton}, but used for buttons in page-based menus.\n * See {@link MenuTemplateButton}\n */\npublic interface PagedMenuTemplateButton<V extends MenuView<V, ?>, E> extends MenuTemplateButton<V> {\n\n    /**\n     * Get the item to display inside the menu for items that don't have a valid paged-object.\n     * For example, inside the top-islands menu, this will return the question-mark head (by default).\n     * In most cases, this will return null.\n     */\n    @Nullable\n    ItemStack getNullItem();\n\n    /**\n     * Get the index within the menu of this paged object button.\n     */\n    int getButtonIndex();\n\n    /**\n     * Sets the index within the menu of this paged object button.\n     *\n     * @param buttonIndex The new index to set.\n     */\n    void setButtonIndex(int buttonIndex);\n\n    /**\n     * Create a view-button object to be used by the provided menu view.\n     * Unlike the template button, the view button handles the logic for buttons within the view.\n     *\n     * @param menuView The view to create the button for.\n     */\n    @Override\n    PagedMenuViewButton<V, E> createViewButton(V menuView);\n\n    /**\n     * Create a new {@link Builder} object for a new {@link PagedMenuTemplateButton}.\n     *\n     * @param viewButtonCreator The creator used to create a view-button by the builder.\n     *                          You will probably want to implement your own {@link PagedMenuViewButton} which will be\n     *                          returned by this creator.\n     */\n    static <V extends MenuView<V, ?>, E> Builder<V, E> newBuilder(Class<?> viewButtonType, PagedMenuViewButtonCreator<V, E> viewButtonCreator) {\n        return SuperiorSkyblockAPI.getMenus().createPagedButtonBuilder(viewButtonType, viewButtonCreator);\n    }\n\n    interface Builder<V extends MenuView<V, ?>, E> extends MenuTemplateButton.Builder<V> {\n\n        /**\n         * Set the item to display inside the menu for items that don't have a valid paged-object.\n         *\n         * @param nullItem The item to set.\n         */\n        Builder<V, E> setNullItem(ItemStack nullItem);\n\n        /**\n         * Get the {@link PagedMenuTemplateButton} from this builder.\n         */\n        PagedMenuTemplateButton<V, E> build();\n\n    }\n\n    interface PagedMenuViewButtonCreator<V extends MenuView<V, ?>, E> {\n\n        /**\n         * Create a new {@link PagedMenuViewButton}.\n         * You will probably want to implement your own {@link PagedMenuViewButton} which will be\n         * returned by this creator.\n         */\n        PagedMenuViewButton<V, E> create(PagedMenuTemplateButton<V, E> templateButton, V menuView);\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuViewButton.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.button;\n\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface PagedMenuViewButton<V extends MenuView<V, ?>, E> extends MenuViewButton<V> {\n\n    /**\n     * Set the paged object for this view button.\n     *\n     * @param pagedObject The object to set.\n     */\n    void updateObject(E pagedObject);\n\n    /**\n     * Get the paged object for this view button.\n     */\n    E getPagedObject();\n\n    /**\n     * Modify the button item for this view button.\n     * This is used for parsing additional placeholders for the {@link #getPagedObject()}.\n     *\n     * @param buttonItem The original item, created by {@link PagedMenuTemplateButton#createViewButton(MenuView)}\n     */\n    ItemStack modifyViewItem(ItemStack buttonItem);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/layout/MenuLayout.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.layout;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * The layout class is used to describe the layout of buttons for a menu.\n * It is later used by the plugin to create a new inventory for the menu.\n */\npublic interface MenuLayout<V extends MenuView<V, ?>> {\n\n    /**\n     * Get a button by a slot.\n     *\n     * @param slot The slot to get a button from.\n     * @return The button in this slot.\n     * If no button was explicitly set by the builder, a dummy button will be return.\n     */\n    MenuTemplateButton<V> getButton(int slot);\n\n    /**\n     * Get all the buttons in the layout.\n     */\n    Collection<MenuTemplateButton<V>> getButtons();\n\n    /**\n     * Get the amount of rows for the layout.\n     */\n    int getRowsCount();\n\n    /**\n     * Create a new inventory from this layout.\n     *\n     * @param menuView The view to create the inventory for.\n     */\n    Inventory buildInventory(V menuView);\n\n    /**\n     * Create a new {@link Builder} object for a new {@link MenuLayout}.\n     */\n    static <V extends MenuView<V, ?>> Builder<V> newBuilder() {\n        return SuperiorSkyblockAPI.getMenus().createPatternBuilder();\n    }\n\n    interface Builder<V extends MenuView<V, ?>> {\n\n        /**\n         * Set a title for menu views created by this layout.\n         *\n         * @param title The title to set.\n         */\n        Builder<V> setTitle(String title);\n\n        /**\n         * Set the inventory type for menu views created by this layout.\n         *\n         * @param inventoryType The inventory type to set.\n         */\n        Builder<V> setInventoryType(InventoryType inventoryType);\n\n        /**\n         * Set the rows count for menu views created by this layout.\n         *\n         * @param rowsCount The amount of rows to set.\n         */\n        Builder<V> setRowsCount(int rowsCount);\n\n        /**\n         * Set a button in a slot for this layout.\n         *\n         * @param slot   The slot to set the button.\n         * @param button The button to set.\n         */\n        Builder<V> setButton(int slot, MenuTemplateButton<V> button);\n\n        /**\n         * Fill this layout with the given buttons.\n         *\n         * @param buttons The buttons to fill this layout with.\n         */\n        Builder<V> setButtons(MenuTemplateButton<V>[] buttons);\n\n        /**\n         * Set a button in slots for this layout.\n         *\n         * @param slots         The slot to set the button.\n         * @param buttonBuilder The builder of the button to set.\n         */\n        Builder<V> setButtons(List<Integer> slots, MenuTemplateButton<V> buttonBuilder);\n\n        /**\n         * Map the button in the given slot to the provided button builder.\n         * This will set the slot with the provided button type with the data of the current button.\n         * If no button exists for this slot, this will be the same as {@link #setButton(int, MenuTemplateButton)}\n         *\n         * @param slot          The slot to set the button.\n         * @param buttonBuilder The builder of the button to map.\n         */\n        Builder<V> mapButton(int slot, MenuTemplateButton.Builder<V> buttonBuilder);\n\n        /**\n         * Map the button in the given slots to the provided button builder.\n         * This will set the slots with the provided button type with the data of the current buttons.\n         * If no buttons exist for the slots, this will be the same as {@link #setButtons(List, MenuTemplateButton)}\n         *\n         * @param slots         The slots to set the button.\n         * @param buttonBuilder The builder of the button to map.\n         */\n        Builder<V> mapButtons(List<Integer> slots, MenuTemplateButton.Builder<V> buttonBuilder);\n\n        /**\n         * Get the {@link MenuLayout} from this builder.\n         */\n        MenuLayout<V> build();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/layout/PagedMenuLayout.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.layout;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\n\nimport java.util.List;\n\n/**\n * Similar to {@link MenuLayout}, but used for layout of page-based menus.\n * See {@link MenuLayout}\n */\npublic interface PagedMenuLayout<V extends MenuView<V, ?>> extends MenuLayout<V> {\n\n    /**\n     * Get the amount of paged objects in the layout.\n     */\n    int getObjectsPerPageCount();\n\n    /**\n     * Create a new {@link Builder} object for a new {@link PagedMenuLayout}.\n     */\n    static <V extends PagedMenuView<V, ?, E>, E> Builder<V, E> newBuilder() {\n        return SuperiorSkyblockAPI.getMenus().createPagedPatternBuilder();\n    }\n\n    interface Builder<V extends MenuView<V, ?>, E> extends MenuLayout.Builder<V> {\n\n        /**\n         * Set the previous-page button slots for this layout.\n         *\n         * @param slots The slots to set.\n         */\n        Builder<V, E> setPreviousPageSlots(List<Integer> slots);\n\n        /**\n         * Set the next-page button slots for this layout.\n         *\n         * @param slots The slots to set.\n         */\n        Builder<V, E> setNextPageSlots(List<Integer> slots);\n\n        /**\n         * Set the current-page display button slots for this layout.\n         *\n         * @param slots The slots to set.\n         */\n        Builder<V, E> setCurrentPageSlots(List<Integer> slots);\n\n        /**\n         * Set the page-object button slots for this layout.\n         *\n         * @param slots         The slots to set.\n         * @param buttonBuilder The builder used for the paged-object.\n         */\n        Builder<V, E> setPagedObjectSlots(List<Integer> slots, PagedMenuTemplateButton.Builder<V, E> buttonBuilder);\n\n        /**\n         * Set a custom order for the paged objects for this layout.\n         *\n         * @param slotsOrder The correct order of the slots\n         */\n        Builder<V, E> setCustomLayoutOrder(List<Integer> slotsOrder);\n\n        /**\n         * Get the {@link PagedMenuLayout} from this builder.\n         */\n        @Override\n        PagedMenuLayout<V> build();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/parser/MenuParseException.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.parser;\n\nimport org.bukkit.configuration.file.YamlConfiguration;\n\n/**\n * In case when calling {@link MenuParser#parseMenu(YamlConfiguration)} and it failed to parse the menu,\n * this exception will be thrown with an appropriate message.\n */\npublic class MenuParseException extends Exception {\n\n    public MenuParseException(String message) {\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/parser/MenuParser.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.parser;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.List;\n\n/**\n * Singleton class used to parse menus out of files.\n * You can get the instance of this parser by calling {@link #getInstance()}\n */\npublic interface MenuParser {\n\n    /**\n     * Parse a menu out of the provided config file.\n     *\n     * @param callerName The caller's name.\n     *                   Used to log warnings when parsing the menu that were not critical.\n     * @param config     The config to load the menu from.\n     * @throws MenuParseException In case an error occurred while parsing the menu.\n     */\n    <V extends MenuView<V, ?>> ParseResult<V> parseMenu(String callerName, YamlConfiguration config) throws MenuParseException;\n\n    /**\n     * Parse a paged menu out of the provided config file.\n     *\n     * @param callerName         The caller's name.\n     *                           Used to log warnings when parsing the menu that were not critical.\n     * @param config             The config to load the menu from.\n     * @param pagedButtonBuilder The builder to use to build the paged objects for the menu.\n     * @throws MenuParseException In case an error occurred while parsing the menu.\n     */\n    <V extends PagedMenuView<V, ?, E>, E> ParseResult<V> parseMenu(\n            String callerName, YamlConfiguration config, PagedMenuTemplateButton.Builder<V, E> pagedButtonBuilder) throws MenuParseException;\n\n    /**\n     * Get the instance of the parser.\n     */\n    static MenuParser getInstance() {\n        return SuperiorSkyblockAPI.getMenus().getParser();\n    }\n\n    /**\n     * Represents the result of the parsing.\n     */\n    interface ParseResult<V extends MenuView<V, ?>> {\n\n        /**\n         * Get the layout builder used by the parser.\n         */\n        MenuLayout.Builder<V> getLayoutBuilder();\n\n        /**\n         * Get the opening sound to play.\n         */\n        @Nullable\n        GameSound getOpeningSound();\n\n        /**\n         * Get whether it is possible to open the previous opened menu after closing the current one.\n         */\n        boolean isPreviousMoveAllowed();\n\n        /**\n         * Get whether this menu should be skipped when it only contains one item.\n         * This is only useful for menus that have their buttons open other menus.\n         */\n        boolean isSkipOneItem();\n\n        /**\n         * Get the slots in the layout for a char.\n         *\n         * @param ch The char to get slots for.\n         */\n        List<Integer> getSlotsForChar(char ch);\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/BaseMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.Inventory;\n\npublic abstract class BaseMenuView<V extends MenuView<V, A>, A extends ViewArgs> implements MenuView<V, A> {\n\n    protected final SuperiorPlayer inventoryViewer;\n    protected final Menu<V, A> menu;\n\n    @Nullable\n    protected MenuView<?, ?> previousMenuView;\n    protected boolean previousMove = true;\n\n    protected BaseMenuView(SuperiorPlayer inventoryViewer, Menu<V, A> menu, @Nullable MenuView<?, ?> previousMenuView) {\n        this.inventoryViewer = inventoryViewer;\n        this.menu = menu;\n        this.previousMenuView = previousMenuView;\n    }\n\n    @Override\n    public SuperiorPlayer getInventoryViewer() {\n        return this.inventoryViewer;\n    }\n\n    @Override\n    public Menu<V, A> getMenu() {\n        return this.menu;\n    }\n\n    @Nullable\n    @Override\n    public MenuView<?, ?> getPreviousMenuView() {\n        return this.previousMenuView;\n    }\n\n    @Override\n    public void setPreviousMenuView(@Nullable MenuView<?, ?> previousMenuView, boolean keepOlderViews) {\n        MenuView<?, ?> oldPreviousMenuView = this.previousMenuView;\n        this.previousMenuView = previousMenuView;\n        if (keepOlderViews && oldPreviousMenuView != null && previousMenuView != null)\n            previousMenuView.setPreviousMenuView(oldPreviousMenuView.getPreviousMenuView(), false);\n    }\n\n    @Override\n    public void setPreviousMove(boolean previousMove) {\n        this.previousMove = previousMove;\n    }\n\n    @Override\n    public boolean isPreviousMenu() {\n        return this.previousMove;\n    }\n\n    @Override\n    public abstract void refreshView();\n\n    @Override\n    public abstract void closeView();\n\n    @Override\n    public abstract Inventory getInventory();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/BasePagedMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\n\nimport java.util.List;\n\npublic abstract class BasePagedMenuView<V extends MenuView<V, A>, A extends ViewArgs, E> extends BaseMenuView<V, A> implements PagedMenuView<V, A, E> {\n\n    protected int currentPage = 1;\n\n    protected BasePagedMenuView(SuperiorPlayer inventoryViewer, Menu<V, A> menu, @Nullable MenuView<?, ?> previousMenuView) {\n        super(inventoryViewer, menu, previousMenuView);\n    }\n\n    @Override\n    public void setCurrentPage(int currentPage) {\n        Preconditions.checkArgument(currentPage >= 1, \"invalid page \" + currentPage);\n\n        if (this.currentPage == currentPage)\n            return;\n\n        this.currentPage = currentPage;\n\n        setPreviousMove(false);\n        refreshView();\n    }\n\n    @Override\n    public int getCurrentPage() {\n        return this.currentPage;\n    }\n\n    @Override\n    public abstract List<E> getPagedObjects();\n\n    @Override\n    public abstract void updatePagedObjects();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/MenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.InventoryHolder;\n\n/**\n * The menu view represents an opened menu for a player.\n * While {@link Menu} is used to describe the info about the menu, the view is the actual inventory\n * that is opened for the player.\n */\npublic interface MenuView<V extends MenuView<V, A>, A extends ViewArgs> extends InventoryHolder {\n\n    /**\n     * Get the player currently viewing the menu.\n     */\n    SuperiorPlayer getInventoryViewer();\n\n    /**\n     * Get the menu of this view.\n     */\n    Menu<V, A> getMenu();\n\n    /**\n     * Get the previous menu that was opened for the player.\n     */\n    @Nullable\n    MenuView<?, ?> getPreviousMenuView();\n\n    /**\n     * Set the previous menu to be opened after closing this view.\n     *\n     * @param previousMenuView The menu to open after that.\n     * @param keepOlderViews   If previousMenuView is not null and set to true, older views will be kept.\n     *                         In other words, it will only replace the last previous view.\n     *                         If false, the previous views will be the ones of previousMenuView.\n     */\n    void setPreviousMenuView(@Nullable MenuView<?, ?> previousMenuView, boolean keepOlderViews);\n\n    /**\n     * Set whether closing the menu should open the previous menu.\n     */\n    void setPreviousMove(boolean previousMove);\n\n    /**\n     * Get whether closing the menu should open the previous menu.\n     */\n    boolean isPreviousMenu();\n\n    /**\n     * Refresh this view for the player.\n     * This will re-build the inventory from scratch and update it for the player viewing it.\n     */\n    void refreshView();\n\n    /**\n     * Close the view for the player.\n     * The view can later be reopened using {@link #refreshView()} or by creating a new one from {@link Menu}\n     */\n    void closeView();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/PagedMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.view;\n\nimport java.util.List;\n\n/**\n * Similar to {@link MenuView}, but used for views of page-based menus.\n * See {@link MenuView}\n */\npublic interface PagedMenuView<V extends MenuView<V, A>, A extends ViewArgs, E> extends MenuView<V, A> {\n\n    /**\n     * Set the current page index for the paged menu.\n     * If the page was changed by this method, the view will be updated, similar to a call to {@link #refreshView()}\n     *\n     * @param currentPage The new page to show.\n     */\n    void setCurrentPage(int currentPage);\n\n    /**\n     * Get the current page index of the paged menu.\n     */\n    int getCurrentPage();\n\n    /**\n     * Get all the paged objects of the menu.\n     */\n    List<E> getPagedObjects();\n\n    /**\n     * Update the paged objects for the menu.\n     * This does not update the actual view. To do that, call {@link #refreshView()}\n     */\n    void updatePagedObjects();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/ViewArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.api.menu.view;\n\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\n/**\n * An empty interface used to describe arguments for a {@link MenuView}\n * This argument is later used to create a new view from {@link Menu#createView(SuperiorPlayer, ViewArgs, MenuView)}\n */\npublic interface ViewArgs {\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/IMissionsHolder.java",
    "content": "package com.bgsoftware.superiorskyblock.api.missions;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface IMissionsHolder {\n\n    /**\n     * Complete a mission.\n     *\n     * @param mission The mission to complete.\n     */\n    void completeMission(Mission<?> mission);\n\n    /**\n     * Reset a mission.\n     *\n     * @param mission The mission to reset.\n     */\n    void resetMission(Mission<?> mission);\n\n    /**\n     * Check whether the island has completed the mission before.\n     *\n     * @param mission The mission to check.\n     */\n    boolean hasCompletedMission(Mission<?> mission);\n\n    /**\n     * Check whether the island can complete a mission again.\n     *\n     * @param mission The mission to check.\n     */\n    boolean canCompleteMissionAgain(Mission<?> mission);\n\n    /**\n     * Get the amount of times mission was completed.\n     *\n     * @param mission The mission to check.\n     */\n    int getAmountMissionCompleted(Mission<?> mission);\n\n    /**\n     * Set the amount of times mission was completed.\n     *\n     * @param mission     The mission to set.\n     * @param finishCount The amount of times the mission was completed.\n     */\n    void setAmountMissionCompleted(Mission<?> mission, int finishCount);\n\n    /**\n     * Get the list of the completed missions of the player.\n     */\n    List<Mission<?>> getCompletedMissions();\n\n    /**\n     * Get all the completed missions with the amount of times they were completed.\n     */\n    Map<Mission<?>, Integer> getCompletedMissionsWithAmounts();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java",
    "content": "package com.bgsoftware.superiorskyblock.api.missions;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.plugin.java.JavaPlugin;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic abstract class Mission<V> {\n\n    private final List<String> requiredMissions = new LinkedList<>();\n    private final List<String> requiredChecks = new LinkedList<>();\n    private final Map<SuperiorPlayer, V> missionData = new ConcurrentHashMap<>();\n\n    private String name = null;\n    private MissionCategory missionCategory = null;\n    private Consumer<V> clearMethod = null;\n    private boolean onlyShowIfRequiredCompleted = false;\n    private boolean islandMission = false;\n\n    /**\n     * Get the name of the mission.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Set the name of the mission.\n     *\n     * @param name The name to set.\n     */\n    public void setName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        if (this.name == null)\n            this.name = name;\n    }\n\n    /**\n     * Get the category of the mission.\n     */\n    public MissionCategory getMissionCategory() {\n        return missionCategory;\n    }\n\n    /**\n     * Set the category of the mission.\n     *\n     * @param missionCategory The category to set.\n     */\n    public void setMissionCategory(MissionCategory missionCategory) {\n        Preconditions.checkNotNull(missionCategory, \"missionCategory parameter cannot be null.\");\n        Preconditions.checkArgument(missionCategory.getMissions().contains(this), \"The mission is not inside the given category.\");\n        if (this.missionCategory == null)\n            this.missionCategory = missionCategory;\n    }\n\n    /**\n     * Get the island-mission of the mission.\n     */\n    public boolean getIslandMission() {\n        return islandMission;\n    }\n\n    /**\n     * Set whether or not this mission is an island mission or not.\n     *\n     * @param islandMission The island-mission status.\n     */\n    public void setIslandMission(boolean islandMission) {\n        this.islandMission = islandMission;\n    }\n\n    /**\n     * Set the clear method for the data object.\n     */\n    public void setClearMethod(@Nullable Consumer<V> clearMethod) {\n        this.clearMethod = clearMethod;\n    }\n\n    /**\n     * Add required missions for completing this mission.\n     *\n     * @param missions The array of required missions.\n     */\n    public void addRequiredMission(String... missions) {\n        Preconditions.checkNotNull(missions, \"missions parameter cannot be null.\");\n        requiredMissions.addAll(Arrays.asList(missions));\n    }\n\n    /**\n     * Add required check for completing this mission.\n     * These checks have placeholders support.\n     *\n     * @param checks The array of required missions.\n     */\n    public void addRequiredCheck(String... checks) {\n        Preconditions.checkNotNull(checks, \"checks parameter cannot be null.\");\n        requiredChecks.addAll(Arrays.asList(checks));\n    }\n\n    /**\n     * Get the required missions for completing this mission.\n     */\n    public List<String> getRequiredMissions() {\n        return Collections.unmodifiableList(requiredMissions);\n    }\n\n    /**\n     * Get the required checks for completing this mission.\n     */\n    public List<String> getRequiredChecks() {\n        return Collections.unmodifiableList(requiredChecks);\n    }\n\n    /**\n     * Toggle the onlyShowIfRequiredCompleted flag.\n     */\n    public void toggleOnlyShowIfRequiredCompleted() {\n        onlyShowIfRequiredCompleted = !onlyShowIfRequiredCompleted;\n    }\n\n    /**\n     * Check whether or not the item in the gui should be shown only\n     * if all required missions are completed.\n     */\n    public boolean isOnlyShowIfRequiredCompleted() {\n        return onlyShowIfRequiredCompleted;\n    }\n\n    /**\n     * The load function of the mission.\n     *\n     * @param plugin         The plugin that loaded the mission (The SuperiorSkyblock's JavaPlugin class)\n     * @param missionSection The configuration section of the mission from the config\n     * @throws MissionLoadException if load was not success.\n     */\n    public abstract void load(JavaPlugin plugin, ConfigurationSection missionSection) throws MissionLoadException;\n\n    /**\n     * Unloads this mission.\n     * <p>\n     * There is no need to handle data-saving, this is done automatically by the plugin.\n     */\n    public void unload() {\n\n    }\n\n    /**\n     * Get the progress of a specific player.\n     * Method should return a value between 0.0 and 1.0\n     *\n     * @param superiorPlayer The player to check.\n     */\n    public abstract double getProgress(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Get the progress value of a specific player.\n     * For example: amount of broken cobblestone, amount of kills, etc.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        return 0;\n    }\n\n    /**\n     * Check whether or not a player can complete the mission.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    public boolean canComplete(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return getProgress(superiorPlayer) >= 1.0;\n    }\n\n    /**\n     * Save mission's progress.\n     *\n     * @param section The mission's section in the config.\n     */\n    public void saveProgress(ConfigurationSection section) {\n        // Should be overridden by missions.\n    }\n\n    /**\n     * Load mission's progress.\n     *\n     * @param section The mission's section in the config.\n     */\n    public void loadProgress(ConfigurationSection section) {\n        // Should be overridden by missions.\n    }\n\n    /**\n     * A function that is called when a player is completing the mission.\n     *\n     * @param superiorPlayer The player that completed the mission.\n     */\n    public abstract void onComplete(SuperiorPlayer superiorPlayer);\n\n    /**\n     * A function that is called when a player cannot complete the mission.\n     *\n     * @param superiorPlayer The player that tried to complete the mission.\n     */\n    public abstract void onCompleteFail(SuperiorPlayer superiorPlayer);\n\n    /**\n     * A function that is called in order to clear progress of a player.\n     *\n     * @param superiorPlayer The player to clear the data of.\n     */\n    public void clearData(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        SuperiorPlayer dataKey = getDataKey(superiorPlayer);\n        if (dataKey != null) {\n            V data = missionData.remove(dataKey);\n            if (data != null && clearMethod != null)\n                clearMethod.accept(data);\n        }\n    }\n\n    /**\n     * A function that is called when islands are transferred.\n     *\n     * @param oldPlayer The old owner of the player.\n     * @param newPlayer The new owner of the player.\n     */\n    public void transferData(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) {\n        Preconditions.checkNotNull(oldPlayer, \"oldPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(newPlayer, \"newPlayer parameter cannot be null.\");\n        V data = missionData.remove(oldPlayer);\n        if (data != null)\n            missionData.put(newPlayer, data);\n    }\n\n    /**\n     * Get they data-key for the provided player.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    @Nullable\n    protected SuperiorPlayer getDataKey(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return islandMission ? superiorPlayer.getIsland() == null ? null : superiorPlayer.getIsland().getOwner() : superiorPlayer;\n    }\n\n    /**\n     * Insert data to the mission data.\n     *\n     * @param superiorPlayer The player to change it's data.\n     * @param value          The data to insert.\n     */\n    public void insertData(SuperiorPlayer superiorPlayer, V value) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(value, \"value parameter cannot be null.\");\n        SuperiorPlayer dataKey = getDataKey(superiorPlayer);\n        if (dataKey != null)\n            missionData.put(dataKey, value);\n    }\n\n    /**\n     * Get or create data for a player.\n     *\n     * @param superiorPlayer The player to get data from.\n     * @param createFunction The function that will be run when data doesn't exist yet.\n     */\n    @Nullable\n    public V getOrCreate(SuperiorPlayer superiorPlayer, Function<SuperiorPlayer, ? extends V> createFunction) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(createFunction, \"createFunction parameter cannot be null.\");\n\n        SuperiorPlayer dataKey = getDataKey(superiorPlayer);\n\n        if (dataKey == null)\n            return null;\n\n        return missionData.computeIfAbsent(dataKey, createFunction);\n    }\n\n    /**\n     * Get data for a player.\n     *\n     * @param superiorPlayer The player to get data from.\n     */\n    @Nullable\n    public V get(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        SuperiorPlayer dataKey = getDataKey(superiorPlayer);\n\n        if (dataKey == null)\n            return null;\n\n        return missionData.get(dataKey);\n    }\n\n    /**\n     * Get the entry set of the data map.\n     */\n    protected Set<Map.Entry<SuperiorPlayer, V>> entrySet() {\n        return missionData.entrySet();\n    }\n\n    /**\n     * A function that is called on every item of the menu.\n     * This is used to inject custom placeholders into items.\n     * The method is called async.\n     *\n     * @param superiorPlayer The player that opens the menu.\n     * @param itemStack      The item of the mission.\n     */\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        // Should be overridden by missions.\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        Mission<?> mission = (Mission<?>) o;\n        return Objects.equals(name, mission.name);\n    }\n\n    @Override\n    public String toString() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/MissionCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.api.missions;\n\nimport java.util.List;\n\npublic interface MissionCategory {\n\n    /**\n     * Get the name of the category.\n     */\n    String getName();\n\n    /**\n     * Get the slot of the category in the missions menu.\n     */\n    int getSlot();\n\n    /**\n     * Get all the missions in the category.\n     */\n    List<Mission<?>> getMissions();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/MissionLoadException.java",
    "content": "package com.bgsoftware.superiorskyblock.api.missions;\n\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.plugin.java.JavaPlugin;\n\n/**\n * This exception is used inside {@link Mission#load(JavaPlugin, ConfigurationSection)}\n * when a faulty configuration is used for the mission.\n */\npublic class MissionLoadException extends Exception {\n\n    public MissionLoadException(String error) {\n        super(error);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java",
    "content": "package com.bgsoftware.superiorskyblock.api.modules;\n\nimport java.io.File;\n\n/**\n * All the data needed for a {@link PluginModule} to be initialized correctly.\n */\npublic interface ModuleInitializeData {\n\n    /**\n     * The data folder of the module.\n     * Should return plugins/SuperiorSkyblock2/datastore/modules/{module-name}\n     */\n    File getDataFolder();\n\n    /**\n     * The folder of the module.\n     * Should return plugins/SuperiorSkyblock2/modules/{module-name}\n     */\n    File getModuleFolder();\n\n    /**\n     * The logger of the module.\n     */\n    ModuleLogger getLogger();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLoadTime.java",
    "content": "package com.bgsoftware.superiorskyblock.api.modules;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\n\npublic enum ModuleLoadTime {\n\n    /**\n     * When used, the module will be loaded before the plugin is initialized.\n     * This makes it possible to listen to the PluginInitializeEvent and alter it.\n     */\n    PLUGIN_INITIALIZE,\n\n    /**\n     * When used, the module will be enabled before the plugin loads the worlds for the islands.\n     */\n    BEFORE_WORLD_CREATION,\n\n    /**\n     * When used, the module will be enabled after the worlds are loaded into the game.\n     * Please note that all the managers of the plugin are not loaded at this time, and you cannot use them\n     * inside your {@link PluginModule#onEnable(SuperiorSkyblock)} method. Furthermore, the data of your module\n     * was not yet loaded at this time. If you want to use your data in the {@link PluginModule#onEnable(SuperiorSkyblock)}\n     * method, check out {@link #AFTER_MODULE_DATA_LOAD}.\n     */\n    NORMAL,\n\n    /**\n     * When used, the module will be enabled after its data was loaded by calling the\n     * {@link PluginModule#loadData(SuperiorSkyblock)} method. Please note that not all the managers of the plugin\n     * are loaded at this time, and using them inside your {@link PluginModule#onEnable(SuperiorSkyblock)} may\n     * lead to undefined behavior; access them at your own risk.\n     */\n    AFTER_MODULE_DATA_LOAD,\n\n    /**\n     * When used, the module will be enabled after all the managers were completely loaded.\n     */\n    AFTER_HANDLERS_LOADING\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java",
    "content": "package com.bgsoftware.superiorskyblock.api.modules;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.logging.FileHandler;\nimport java.util.logging.Handler;\nimport java.util.logging.Level;\nimport java.util.logging.LogRecord;\nimport java.util.logging.Logger;\n\n/**\n * Simple implementation of a custom logger for modules.\n */\npublic class ModuleLogger extends Logger {\n\n    private boolean debugMode = false;\n\n    /**\n     * Constructor for the logger.\n     *\n     * @param pluginModule The module that uses the logger.\n     */\n    public ModuleLogger(PluginModule pluginModule) {\n        super(\"SuperiorSkyblock2-\" + pluginModule.getName(), null);\n        this.setParent(SuperiorSkyblockAPI.getSuperiorSkyblock().getLogger());\n        this.setLevel(Level.ALL);\n    }\n\n    public void setDebugMode(boolean debugMode) {\n        this.debugMode = debugMode;\n    }\n\n    public void i(String message) {\n        super.info(message);\n    }\n\n    public void w(String message) {\n        super.warning(message);\n    }\n\n    public void e(String message) {\n        super.severe(message);\n    }\n\n    public void e(String message, Throwable error) {\n        super.severe(message);\n        logError(error);\n    }\n\n    public void d(String message) {\n        if (this.debugMode) {\n            this.info(message);\n        } else {\n            LogRecord logRecord = new LogRecord(Level.INFO, message);\n            for (Handler handler : getHandlers()) {\n                if (handler instanceof ModuleFileHandler) {\n                    handler.publish(logRecord);\n                }\n            }\n        }\n    }\n\n    private void logError(Throwable error) {\n        StringWriter buffer = new StringWriter();\n        PrintWriter pw = new PrintWriter(buffer);\n        error.printStackTrace(pw);\n        super.severe(buffer.toString());\n    }\n\n    /**\n     * Custom interface to distinguish between logger handlers and the module's custom file handler.\n     */\n    public interface ModuleFileHandler {\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleResources.java",
    "content": "package com.bgsoftware.superiorskyblock.api.modules;\n\nimport com.google.common.base.Preconditions;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\n\n/**\n * Class to handle resources for a module.\n */\npublic class ModuleResources {\n\n    private final File moduleFile;\n    private final File moduleFolder;\n    private final ClassLoader classLoader;\n\n    /**\n     * Constructor for the class.\n     *\n     * @param moduleFile   The file of the module.\n     * @param moduleFolder The data folder of the module.\n     * @param classLoader  The class loader of the module.\n     */\n    public ModuleResources(File moduleFile, File moduleFolder, ClassLoader classLoader) {\n        this.moduleFile = moduleFile;\n        this.moduleFolder = moduleFolder;\n        this.classLoader = classLoader;\n    }\n\n    /**\n     * Saves the raw contents of an embedded resource within the module.\n     *\n     * @param resourcePath Path to the resource to save.\n     */\n    public void saveResource(String resourcePath) {\n        Preconditions.checkNotNull(resourcePath, \"resourcePath cannot be null.\");\n        Preconditions.checkArgument(!resourcePath.isEmpty(), \"resourcePath cannot be empty.\");\n\n        resourcePath = resourcePath.replace('\\\\', '/');\n\n        try (InputStream resourceInput = getResource(resourcePath)) {\n            File outFile = new File(this.moduleFolder, resourcePath);\n            int lastIndex = resourcePath.lastIndexOf(47);\n            File outDir = new File(this.moduleFolder, resourcePath.substring(0, Math.max(lastIndex, 0)));\n\n            if (!outDir.exists()) {\n                outDir.mkdirs();\n            }\n\n            try (OutputStream out = new FileOutputStream(outFile)) {\n                byte[] buf = new byte[1024];\n\n                int len;\n                while ((len = resourceInput.read(buf)) > 0) {\n                    out.write(buf, 0, len);\n                }\n            }\n        } catch (IOException ex) {\n            throw new RuntimeException(\"Could not save \" + resourcePath, ex);\n        }\n    }\n\n    /**\n     * Get the raw contents of an embedded resource within the module.\n     *\n     * @param fileName The name of the resource to get contents of.\n     */\n    public InputStream getResource(String fileName) {\n        Preconditions.checkNotNull(fileName, \"fileName cannot be null.\");\n\n        try {\n            URL url = this.classLoader.getResource(fileName);\n            if (url != null) {\n                URLConnection connection = url.openConnection();\n                connection.setUseCaches(false);\n                return connection.getInputStream();\n            }\n        } catch (IOException ignored) {\n        }\n\n        throw new IllegalArgumentException(\"The embedded resource '\" + fileName + \"' cannot be found in \" + this.moduleFile);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java",
    "content": "package com.bgsoftware.superiorskyblock.api.modules;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.logging.Logger;\n\n/**\n * Plugin modules are similar to plugins. The difference between them and regular plugins is that the modules are\n * designed to work only with SuperiorSkyblock, and they are loaded by SuperiorSkyblock and not by the server.\n * The advantages of using modules over plugins is the ability to manage them through the plugin's commands, without\n * needing to restart the server. Moreover, SuperiorSkyblock handles listeners and commands for you - it will register\n * them when needed, unregister them and will do all of that work for you.\n */\npublic abstract class PluginModule {\n\n    private final String moduleName;\n    private final String authorName;\n\n    private File dataFolder;\n    private File moduleFile;\n    private File moduleFolder;\n    private ClassLoader classLoader;\n    private ModuleLogger logger;\n    private ModuleResources moduleResources;\n\n    private boolean initialized = false;\n\n    /**\n     * Constructor for a module.\n     *\n     * @param moduleName The name of the module.\n     * @param authorName The name of the author of the module.\n     */\n    protected PluginModule(String moduleName, String authorName) {\n        this.moduleName = moduleName;\n        this.authorName = authorName;\n    }\n\n    /**\n     * Called when the module is enabled.\n     *\n     * @param plugin Instance of the plugin.\n     */\n    public abstract void onEnable(SuperiorSkyblock plugin);\n\n    /**\n     * Called when the module is reloaded.\n     *\n     * @param plugin Instance of the plugin.\n     */\n    public abstract void onReload(SuperiorSkyblock plugin);\n\n    /**\n     * Called when the module is disabled.\n     *\n     * @param plugin Instance of the plugin.\n     */\n    public abstract void onDisable(SuperiorSkyblock plugin);\n\n    /**\n     * Called when the module can load data about players.\n     * It's called after the plugin's data is loaded.\n     * <p>\n     * This is similar to load data when {@link com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent}\n     * is fired.\n     *\n     * @param plugin Instance of the plugin.\n     */\n    public void loadData(SuperiorSkyblock plugin) {\n\n    }\n\n    /**\n     * Called when the module initialized for the first time.\n     *\n     * @param plugin Instance of the plugin.\n     */\n    protected void onPluginInit(SuperiorSkyblock plugin) {\n        // Can be overridden by custom modules.\n    }\n\n    /**\n     * List of listeners to register for the module.\n     * The plugin will handle the registers for the module - register them when the module is enabled,\n     * and unregister them when it is disabled.\n     *\n     * @param plugin Instance of the plugin.\n     * @return Array of listeners for the module. May be null for no listeners.\n     */\n    @Nullable\n    public abstract Listener[] getModuleListeners(SuperiorSkyblock plugin);\n\n    /**\n     * List of player commands to register for the module.\n     * The plugin will handle the commands for the module - register them when the module is enabled,\n     * and unregister them when it is disabled.\n     *\n     * @param plugin Instance of the plugin.\n     * @return Array of player commands for the module. May be null for no commands.\n     */\n    @Nullable\n    public abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblock plugin);\n\n    /**\n     * List of admin commands to register for the module.\n     * The plugin will handle the commands for the module - register them when the module is enabled,\n     * and unregister them when it is disabled.\n     *\n     * @param plugin Instance of the plugin.\n     * @return Array of player commands for the module. May be null for no commands.\n     */\n    @Nullable\n    public abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblock plugin);\n\n    /**\n     * Get when the module should be enabled.\n     * There are 3 loading stages for modules:\n     * {@link ModuleLoadTime#AFTER_HANDLERS_LOADING} - modules that should be loaded before the worlds are created.\n     * Should be used if the module needs to override the WorldsProvider.\n     * {@link ModuleLoadTime#NORMAL} - modules that should be loaded without any specifications.\n     * Default for all the modules.\n     * {@link ModuleLoadTime#AFTER_HANDLERS_LOADING} - modules that should be loaded after all the plugin handlers.\n     * Should be used if the module is interacting with the built-in handlers on its {@link #onEnable} method.\n     */\n    public ModuleLoadTime getLoadTime() {\n        return ModuleLoadTime.NORMAL;\n    }\n\n    /**\n     * Get the name of the module.\n     */\n    public final String getName() {\n        return moduleName;\n    }\n\n    /**\n     * Get the author of the module.\n     */\n    public final String getAuthor() {\n        return authorName;\n    }\n\n    /**\n     * Get the data folder of the module.\n     * The path for the folder is always plugins/SuperiorSkyblock2/modules/{module-name}/\n     *\n     * @deprecated Misleading name; check out {@link #getModuleFolder()}\n     */\n    @Deprecated\n    public final File getDataFolder() {\n        return this.getModuleFolder();\n    }\n\n    /**\n     * Get the folder of the module.\n     * The path for the folder is always plugins/SuperiorSkyblock2/modules/{module-name}/\n     */\n    public final File getModuleFolder() {\n        return this.moduleFolder;\n    }\n\n    /**\n     * Get the jar file of the module.\n     * May be null if the module was registered without calling {@link #initModuleLoader(File, ClassLoader)}\n     * This is not an expected behavior, and the plugin will never initialize the module with a null file!\n     */\n    @Nullable\n    public final File getModuleFile() {\n        return moduleFile;\n    }\n\n    /**\n     * Get the folder where data of the module can be stored at.\n     * The path for the folder is always plugins/SuperiorSkyblock2/datastore/modules/{module-name}/\n     */\n    public final File getDataStoreFolder() {\n        return this.dataFolder;\n    }\n\n    /**\n     * Get the class loader of the module.\n     * May be null if the module was registered without calling {@link #initModuleLoader(File, ClassLoader)}\n     * This is not an expected behavior, and the plugin will never initialize the module with a null class loader!\n     */\n    @Nullable\n    public final ClassLoader getClassLoader() {\n        return classLoader;\n    }\n\n    /**\n     * Get the logger of the module {@link ModuleLogger}\n     */\n    public final Logger getLogger() {\n        return logger;\n    }\n\n    /**\n     * Check whether the module was initialized or not.\n     * Modules will be initialized after calling to {@link #initModule(SuperiorSkyblock, File, File)}\n     */\n    public final boolean isInitialized() {\n        return initialized;\n    }\n\n    /**\n     * Saves the raw contents of an embedded resource within the module.\n     *\n     * @param resourceName The name of the resource to save.\n     */\n    public final void saveResource(String resourceName) {\n        if (this.moduleResources == null)\n            throw new IllegalArgumentException(\"Cannot save resources for an uninitialized module.\");\n\n        moduleResources.saveResource(resourceName);\n    }\n\n    /**\n     * Get the raw contents of an embedded resource within the module.\n     *\n     * @param resourceName The name of the resource to get contents of.\n     */\n    public final InputStream getResource(String resourceName) {\n        if (this.moduleResources == null)\n            throw new IllegalArgumentException(\"Cannot get resources for an uninitialized module.\");\n\n        return moduleResources.getResource(resourceName);\n    }\n\n    /**\n     * Initialize the module.\n     * This method cannot be called twice - do not call it unless you know what you are doing.\n     *\n     * @param plugin     An instance to the plugin.\n     * @param dataFolder The database folder of the module.\n     */\n    @Deprecated\n    public final void initModule(SuperiorSkyblock plugin, File dataFolder) {\n        this.initModule(plugin, new File(moduleFile.getParentFile(), moduleName), dataFolder);\n    }\n\n    /**\n     * Initialize the module.\n     * This method cannot be called twice - do not call it unless you know what you are doing.\n     *\n     * @param plugin       An instance to the plugin.\n     * @param dataFolder   The database folder of the module.\n     * @param moduleFolder The folder of the module.\n     */\n    @Deprecated\n    public final void initModule(SuperiorSkyblock plugin, File moduleFolder, File dataFolder) {\n        ModuleLogger moduleLogger = new ModuleLogger(this);\n        this.initModule(plugin, new ModuleInitializeData() {\n            @Override\n            public File getDataFolder() {\n                return dataFolder;\n            }\n\n            @Override\n            public File getModuleFolder() {\n                return moduleFolder;\n            }\n\n            @Override\n            public ModuleLogger getLogger() {\n                return moduleLogger;\n            }\n        });\n    }\n\n    /**\n     * Initialize the module.\n     * This method cannot be called twice - do not call it unless you know what you are doing.\n     *\n     * @param plugin  An instance to the plugin.\n     * @param context The initialize context.\n     */\n    public final void initModule(SuperiorSkyblock plugin, ModuleInitializeData context) {\n        if (this.initialized)\n            throw new RuntimeException(\"The module \" + this.moduleName + \" was already initialized.\");\n\n        this.initialized = true;\n\n        File moduleFolder = context.getModuleFolder();\n        if (!moduleFolder.exists() && !moduleFolder.mkdirs())\n            throw new RuntimeException(\"Cannot create module folder for \" + this.moduleName + \".\");\n\n        this.dataFolder = context.getDataFolder();\n        this.moduleFolder = moduleFolder;\n        this.logger = context.getLogger();\n\n        if (this.moduleFile != null && this.classLoader != null)\n            this.moduleResources = new ModuleResources(this.moduleFile, this.moduleFolder, this.classLoader);\n\n        onPluginInit(plugin);\n    }\n\n    /**\n     * Initialize the module's loaders settings.\n     *\n     * @param moduleFile  The file of the module jar.\n     * @param classLoader The class loader used to load the module.\n     */\n    public final void initModuleLoader(File moduleFile, ClassLoader classLoader) {\n        if (initialized)\n            throw new RuntimeException(\"The module \" + moduleName + \" was already initialized.\");\n\n        this.moduleFile = moduleFile;\n        this.classLoader = classLoader;\n    }\n\n    /**\n     * Disable the module.\n     */\n    public final void disableModule() {\n        initialized = false;\n    }\n\n}"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/objects/Enumerable.java",
    "content": "package com.bgsoftware.superiorskyblock.api.objects;\n\n/**\n * This class is used in internal data structures for a more optimized way of doing data lookups.\n * This is mainly used for lookups for {@link com.bgsoftware.superiorskyblock.api.island.IslandPrivilege} and\n * {@link com.bgsoftware.superiorskyblock.api.island.IslandFlag}.\n */\npublic interface Enumerable {\n\n    /**\n     * The ordinal of this enumeration constant.\n     */\n    int ordinal();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/objects/Pair.java",
    "content": "package com.bgsoftware.superiorskyblock.api.objects;\n\nimport java.util.Map;\n\n/**\n * This class represents a pair of elements.\n *\n * @param <E1> First element of this pair.\n * @param <E2> Second element of this pair.\n */\npublic class Pair<E1, E2> {\n\n    private E1 firstElement;\n    private E2 secondElement;\n\n    /**\n     * Create a new pair out of a {@link Map.Entry} object.\n     *\n     * @param entry The entry to create the pair from.\n     */\n    public Pair(Map.Entry<E1, E2> entry) {\n        this(entry.getKey(), entry.getValue());\n    }\n\n    /**\n     * Create a new pair out of two elements.\n     *\n     * @param firstElement  The first element of this pair.\n     * @param secondElement The second element of this pair.\n     */\n    public Pair(E1 firstElement, E2 secondElement) {\n        this.firstElement = firstElement;\n        this.secondElement = secondElement;\n    }\n\n    /**\n     * Get the first element of this pair.\n     */\n    public E1 getKey() {\n        return this.firstElement;\n    }\n\n    /**\n     * Set the first element of this pair.\n     *\n     * @param element The new element to set.\n     */\n    public void setKey(E1 element) {\n        this.firstElement = element;\n    }\n\n    /**\n     * Get the second element of this pair.\n     */\n    public E2 getValue() {\n        return this.secondElement;\n    }\n\n    /**\n     * Set the second element of this pair.\n     *\n     * @param element The new element to set.\n     */\n    public void setValue(E2 element) {\n        this.secondElement = element;\n    }\n\n    @Override\n    public String toString() {\n        return \"{\" + this.firstElement + \"=\" + this.secondElement + \"}\";\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.function.BiConsumer;\n\npublic class DelegatePersistentDataContainer implements PersistentDataContainer {\n\n    protected final PersistentDataContainer handle;\n\n    protected DelegatePersistentDataContainer(PersistentDataContainer handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public boolean has(String key) {\n        return this.handle.has(key);\n    }\n\n    @Override\n    public <T> boolean hasKeyOfType(String key, PersistentDataType<T> type) {\n        return this.handle.hasKeyOfType(key, type);\n    }\n\n    @Nullable\n    @Override\n    public <T> T put(String key, PersistentDataType<T> type, T value) throws IllegalArgumentException, IllegalStateException {\n        return this.handle.put(key, type, value);\n    }\n\n    @Nullable\n    @Override\n    public <T, R> R put(String key, PersistentDataType<T> type, T value, PersistentDataType<R> returnType) throws IllegalArgumentException, IllegalStateException {\n        return this.handle.put(key, type, value, returnType);\n    }\n\n    @Nullable\n    @Override\n    public Object remove(String key) {\n        return this.handle.remove(key);\n    }\n\n    @Nullable\n    @Override\n    public <T> T removeKeyOfType(String key, PersistentDataType<T> type) {\n        return this.handle.removeKeyOfType(key, type);\n    }\n\n    @Nullable\n    @Override\n    public <T> T get(String key, PersistentDataType<T> type) throws IllegalArgumentException {\n        return this.handle.get(key, type);\n    }\n\n    @Nullable\n    @Override\n    public Object get(String key) {\n        return this.handle.get(key);\n    }\n\n    @Override\n    public <T> T getOrDefault(String key, PersistentDataType<T> type, T def) throws IllegalArgumentException {\n        return this.handle.getOrDefault(key, type, def);\n    }\n\n    @Override\n    public Object getOrDefault(String key, Object def) {\n        return this.handle.getOrDefault(key, def);\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return this.handle.isEmpty();\n    }\n\n    @Override\n    public int size() {\n        return this.handle.size();\n    }\n\n    @Override\n    public void forEach(BiConsumer<String, Object> action) {\n        this.handle.forEach(action);\n    }\n\n    @Override\n    public byte[] serialize() {\n        return this.handle.serialize();\n    }\n\n    @Override\n    public void load(byte[] data) throws IllegalArgumentException {\n        this.handle.load(data);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/IPersistentDataHolder.java",
    "content": "package com.bgsoftware.superiorskyblock.api.persistence;\n\n/**\n * Represents an object that can store custom persistent data.\n */\npublic interface IPersistentDataHolder {\n\n    /**\n     * Get the container of custom persistent data of this object.\n     */\n    PersistentDataContainer getPersistentDataContainer();\n\n    /**\n     * Check if the persistent data container is empty.\n     */\n    boolean isPersistentDataContainerEmpty();\n\n    /**\n     * When saving data into the container, it's not immediately saved to database.\n     * Call this method to save the persistent data container into database.\n     */\n    void savePersistentDataContainer();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.function.BiConsumer;\n\npublic interface PersistentDataContainer {\n\n    /**\n     * Check if the provided key has a matching metadata value.\n     *\n     * @param key The key to check.\n     */\n    boolean has(String key);\n\n    /**\n     * Check if the provided key has a matching metadata value of the provided type.\n     *\n     * @param key  The key to check.\n     * @param type The type to check.\n     */\n    <T> boolean hasKeyOfType(String key, PersistentDataType<T> type);\n\n    /**\n     * Store a metadata value matching the provided key and type.\n     *\n     * @param key   The key to store.\n     * @param type  The type of the metadata value.\n     * @param value The metadata value to store.\n     * @return The old metadata value that was stored matching the key, if exists.\n     * @throws IllegalArgumentException If the old metadata value is not of type {@param type}.\n     * @throws IllegalStateException    If {@param type} doesn't have a valid serializer available.\n     */\n    @Nullable\n    <T> T put(String key, PersistentDataType<T> type, T value) throws IllegalArgumentException, IllegalStateException;\n\n    /**\n     * Store a metadata value matching the provided key and type.\n     *\n     * @param key        The key to store.\n     * @param type       The type of the metadata.\n     * @param value      The metadata value to store.\n     * @param returnType The type of the old metadata value.\n     * @return The old metadata value that was stored matching the key, if exists.\n     * @throws IllegalArgumentException If the old metadata value is not of type {@param returnType}.\n     * @throws IllegalStateException    If {@param type} doesn't have a valid serializer available.\n     */\n    @Nullable\n    <T, R> R put(String key, PersistentDataType<T> type, T value, PersistentDataType<R> returnType) throws IllegalArgumentException, IllegalStateException;\n\n    /**\n     * Remove a metadata value matching the provided key.\n     *\n     * @param key The key to remove.\n     * @return The old metadata value that was stored matching the key, if exists.\n     */\n    @Nullable\n    Object remove(String key);\n\n    /**\n     * Remove a metadata value matching the provided key and type.\n     * If the metadata value doesn't match the {@param type}, it will not get removed.\n     *\n     * @param key  The key to remove.\n     * @param type The type of the metadata value to remove.\n     * @return The old metadata value that was stored matching the key, if exists.\n     * If the metadata value does not match the current type, null will be returned.\n     */\n    @Nullable\n    <T> T removeKeyOfType(String key, PersistentDataType<T> type);\n\n    /**\n     * Get a metadata value matching the provided key and type.\n     *\n     * @param key  The key to fetch.\n     * @param type The type of the metadata value to fetch.\n     * @return The metadata value that is stored matching the key, if exists.\n     * @throws IllegalArgumentException If the metadata value is not of type {@param type}.\n     */\n    @Nullable\n    <T> T get(String key, PersistentDataType<T> type) throws IllegalArgumentException;\n\n    /**\n     * Get a metadata value matching the provided key.\n     *\n     * @param key The key to fetch.\n     * @return The metadata value that is stored matching the key, if exists.\n     */\n    @Nullable\n    Object get(String key);\n\n    /**\n     * Get a metadata value matching the provided key and type.\n     *\n     * @param key  The key to fetch.\n     * @param type The type of the metadata value to fetch.\n     * @param def  Value to return in case there is no metadata value matching the provided key.\n     * @return The metadata value that is stored matching the key, or {@param def} otherwise.\n     * @throws IllegalArgumentException If the metadata value is not of type {@param type}.\n     */\n    <T> T getOrDefault(String key, PersistentDataType<T> type, T def) throws IllegalArgumentException;\n\n    /**\n     * Get a metadata value matching the provided key.\n     *\n     * @param key The key to fetch.\n     * @param def Value to return in case there is no metadata value matching the provided key.\n     * @return The metadata value that is stored matching the key, or {@param def} otherwise.\n     */\n    Object getOrDefault(String key, Object def);\n\n    /**\n     * Check whether the container is empty.\n     */\n    boolean isEmpty();\n\n    /**\n     * Get the size of the container.\n     */\n    int size();\n\n    /**\n     * Iterate through all the data of the container.\n     *\n     * @param action The action to perform for each key and value pair.\n     */\n    void forEach(BiConsumer<String, Object> action);\n\n    /**\n     * Get the serialized contents of the container as a bytes array.\n     * The format of the serialized data may be different depending on the implementation of the container.\n     * The serialized data must be loaded without any errors using {@link #load(byte[])}.\n     */\n    byte[] serialize();\n\n    /**\n     * Load contents from the serialized data into the container.\n     * The format of the serialized data may be different depending on the implementation of the container.\n     *\n     * @param data The serialized data.\n     * @throws IllegalArgumentException If the given data cannot be serialized correctly.\n     */\n    void load(byte[] data) throws IllegalArgumentException;\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataType.java",
    "content": "package com.bgsoftware.superiorskyblock.api.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.google.common.base.Preconditions;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\n\n/**\n * Represents a data type that can be stored inside a {@link PersistentDataContainer}.\n *\n * @param <T> The type of the value to store.\n */\npublic class PersistentDataType<T> {\n\n    public static final PersistentDataType<BigDecimal> BIG_DECIMAL = new PersistentDataType<>(BigDecimal.class);\n    public static final PersistentDataType<byte[]> BYTE_ARRAY = new PersistentDataType<>(byte[].class);\n    public static final PersistentDataType<Byte> BYTE = new PersistentDataType<>(Byte.class);\n    public static final PersistentDataType<Double> DOUBLE = new PersistentDataType<>(Double.class);\n    public static final PersistentDataType<Float> FLOAT = new PersistentDataType<>(Float.class);\n    public static final PersistentDataType<int[]> INT_ARRAY = new PersistentDataType<>(int[].class);\n    public static final PersistentDataType<Integer> INTEGER = new PersistentDataType<>(Integer.class);\n    public static final PersistentDataType<Long> LONG = new PersistentDataType<>(Long.class);\n    public static final PersistentDataType<Short> SHORT = new PersistentDataType<>(Short.class);\n    public static final PersistentDataType<String> STRING = new PersistentDataType<>(String.class);\n    public static final PersistentDataType<UUID> UUID = new PersistentDataType<>(UUID.class);\n\n    private final Class<T> type;\n    private final PersistentDataTypeContext<T> context;\n\n    /**\n     * Custom type constructor.\n     *\n     * @param type    The type.\n     * @param context The context class used to serialize and deserialize this data type.\n     */\n    public PersistentDataType(Class<T> type, PersistentDataTypeContext<T> context) {\n        this.type = Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        this.context = Preconditions.checkNotNull(context, \"context parameter cannot be null\");\n    }\n\n    /**\n     * Built-in type constructor.\n     *\n     * @param type The type.\n     */\n    private PersistentDataType(Class<T> type) {\n        this.type = type;\n        this.context = null;\n    }\n\n    public Class<T> getType() {\n        return this.type;\n    }\n\n    @Nullable\n    public PersistentDataTypeContext<T> getContext() {\n        return this.context;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataTypeContext.java",
    "content": "package com.bgsoftware.superiorskyblock.api.persistence;\n\n/**\n * The context class is used to serialize and deserialize a custom data type.\n *\n * @param <T> The type of the data value.\n */\npublic interface PersistentDataTypeContext<T> {\n\n    /**\n     * Serialize the provided value into a bytes buffer.\n     *\n     * @param value The value to serialize.\n     * @return The serialized data.\n     */\n    byte[] serialize(T value);\n\n    /**\n     * Deserialize the provided bytes buffer into a valid value.\n     *\n     * @param data The serialized data.\n     * @return The deserialized value.\n     */\n    T deserialize(byte[] data);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java",
    "content": "package com.bgsoftware.superiorskyblock.api.platform;\n\nimport org.bukkit.event.Event;\nimport org.bukkit.event.EventPriority;\n\n/**\n * The events dispatcher is used to dispatch events to the plugin.\n */\npublic interface IEventsDispatcher {\n\n    /**\n     * Notify about a new game-event.\n     *\n     * @param event    The event that was fired.\n     * @param priority The priority of the event.\n     * @return Whether the event was successfully dispatched.\n     */\n    boolean notifyEvent(Event event, EventPriority priority);\n\n    /**\n     * Whether the default executor should be used if {@link #notifyEvent(Event, EventPriority)} fails.\n     */\n    default boolean shouldFallbackToDefaultExecutorOnFailure() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.HitActionResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\npublic class DelegateSuperiorPlayer implements SuperiorPlayer {\n\n    protected final SuperiorPlayer handle;\n\n    protected DelegateSuperiorPlayer(SuperiorPlayer handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return this.handle.getUniqueId();\n    }\n\n    @Override\n    public String getName() {\n        return this.handle.getName();\n    }\n\n    @Override\n    public PlayerCache getCache() {\n        return this.handle.getCache();\n    }\n\n    @Override\n    public String getTextureValue() {\n        return this.handle.getTextureValue();\n    }\n\n    @Override\n    public void setTextureValue(String textureValue) {\n        this.handle.setTextureValue(textureValue);\n    }\n\n    @Override\n    public void updateLastTimeStatus() {\n        this.handle.updateLastTimeStatus();\n    }\n\n    @Override\n    public void setLastTimeStatus(long lastTimeStatus) {\n        this.handle.setLastTimeStatus(lastTimeStatus);\n    }\n\n    @Override\n    public long getLastTimeStatus() {\n        return this.handle.getLastTimeStatus();\n    }\n\n    @Override\n    public void updateName() {\n        this.handle.updateName();\n    }\n\n    @Override\n    public void setName(String name) {\n        this.handle.setName(name);\n    }\n\n    @Nullable\n    @Override\n    public Player asPlayer() {\n        return this.handle.asPlayer();\n    }\n\n    @Nullable\n    @Override\n    public OfflinePlayer asOfflinePlayer() {\n        return this.handle.asOfflinePlayer();\n    }\n\n    @Override\n    public boolean isOnline() {\n        return this.handle.isOnline();\n    }\n\n    @Override\n    public void runIfOnline(Consumer<Player> toRun) {\n        this.handle.runIfOnline(toRun);\n    }\n\n    @Override\n    public boolean hasFlyGamemode() {\n        return this.handle.hasFlyGamemode();\n    }\n\n    @Nullable\n    @Override\n    public MenuView<?, ?> getOpenedView() {\n        return this.handle.getOpenedView();\n    }\n\n    @Override\n    public boolean isAFK() {\n        return this.handle.isAFK();\n    }\n\n    @Override\n    public boolean isVanished() {\n        return this.handle.isVanished();\n    }\n\n    @Override\n    public boolean isShownAsOnline() {\n        return this.handle.isShownAsOnline();\n    }\n\n    @Override\n    public boolean hasPermission(String permission) {\n        return this.handle.hasPermission(permission);\n    }\n\n    @Override\n    public boolean hasPermissionWithoutOP(String permission) {\n        return this.handle.hasPermissionWithoutOP(permission);\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege permission) {\n        return this.handle.hasPermission(permission);\n    }\n\n    @Override\n    public boolean hasBypassPermission(IslandPrivilege permission) {\n        return this.handle.hasBypassPermission(permission);\n    }\n\n    @Override\n    public HitActionResult canHit(SuperiorPlayer otherPlayer) {\n        return this.handle.canHit(otherPlayer);\n    }\n\n    @Nullable\n    @Override\n    public World getWorld() {\n        return this.handle.getWorld();\n    }\n\n    @Nullable\n    @Override\n    public Location getLocation() {\n        return this.handle.getLocation();\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        return this.handle.getLocation(location);\n    }\n\n    @Override\n    public void teleport(Location location) {\n        this.handle.teleport(location);\n    }\n\n    @Override\n    public void teleport(Location location, @Nullable Consumer<Boolean> teleportResult) {\n        this.handle.teleport(location, teleportResult);\n    }\n\n    @Override\n    public void teleport(Island island) {\n        this.handle.teleport(island);\n    }\n\n    @Override\n    public void teleport(Island island, @Nullable Consumer<Boolean> teleportResult) {\n        this.handle.teleport(island, teleportResult);\n    }\n\n    @Override\n    public void teleport(Island island, Dimension dimension) {\n        this.handle.teleport(island, dimension);\n    }\n\n    @Override\n    public void teleport(Island island, Dimension dimension, Consumer<Boolean> teleportResult) {\n        this.handle.teleport(island, dimension, teleportResult);\n    }\n\n    @Override\n    public boolean isInsideIsland() {\n        return this.handle.isInsideIsland();\n    }\n\n    @Override\n    public SuperiorPlayer getIslandLeader() {\n        return this.handle.getIslandLeader();\n    }\n\n    @Override\n    @Deprecated\n    public void setIslandLeader(SuperiorPlayer islandLeader) {\n        this.handle.setIslandLeader(islandLeader);\n    }\n\n    @Nullable\n    @Override\n    public Island getIsland() {\n        return this.handle.getIsland();\n    }\n\n    @Override\n    public void setIsland(Island island) {\n        this.handle.setIsland(island);\n    }\n\n    @Override\n    public boolean hasIsland() {\n        return this.handle.hasIsland();\n    }\n\n    @Override\n    public void addInvite(Island island) {\n        this.handle.addInvite(island);\n    }\n\n    @Override\n    public void removeInvite(Island island) {\n        this.handle.removeInvite(island);\n    }\n\n    @Override\n    public List<Island> getInvites() {\n        return this.handle.getInvites();\n    }\n\n    @Override\n    public void addCoop(Island island) {\n        this.handle.addCoop(island);\n    }\n\n    @Override\n    public void removeCoop(Island island) {\n        this.handle.removeCoop(island);\n    }\n\n    @Override\n    public List<Island> getCoopIslands() {\n        return this.handle.getCoopIslands();\n    }\n\n    @Override\n    public PlayerRole getPlayerRole() {\n        return this.handle.getPlayerRole();\n    }\n\n    @Override\n    public void setPlayerRole(PlayerRole playerRole) {\n        this.handle.setPlayerRole(playerRole);\n    }\n\n    @Override\n    public int getDisbands() {\n        return this.handle.getDisbands();\n    }\n\n    @Override\n    public void setDisbands(int disbands) {\n        this.handle.setDisbands(disbands);\n    }\n\n    @Override\n    public boolean hasDisbands() {\n        return this.handle.hasDisbands();\n    }\n\n    @Override\n    public Locale getUserLocale() {\n        return this.handle.getUserLocale();\n    }\n\n    @Override\n    public void setUserLocale(Locale locale) {\n        this.handle.setUserLocale(locale);\n    }\n\n    @Override\n    public boolean hasWorldBorderEnabled() {\n        return this.handle.hasWorldBorderEnabled();\n    }\n\n    @Override\n    public void toggleWorldBorder() {\n        this.handle.toggleWorldBorder();\n    }\n\n    @Override\n    public void setWorldBorderEnabled(boolean enabled) {\n        this.handle.setWorldBorderEnabled(enabled);\n    }\n\n    @Override\n    public void updateWorldBorder(@Nullable Island island) {\n        this.handle.updateWorldBorder(island);\n    }\n\n    @Override\n    public boolean hasBlocksStackerEnabled() {\n        return this.handle.hasBlocksStackerEnabled();\n    }\n\n    @Override\n    public void toggleBlocksStacker() {\n        this.handle.toggleBlocksStacker();\n    }\n\n    @Override\n    public void setBlocksStacker(boolean enabled) {\n        this.handle.setBlocksStacker(enabled);\n    }\n\n    @Override\n    public boolean hasSchematicModeEnabled() {\n        return this.handle.hasSchematicModeEnabled();\n    }\n\n    @Override\n    public void toggleSchematicMode() {\n        this.handle.toggleSchematicMode();\n    }\n\n    @Override\n    public void setSchematicMode(boolean enabled) {\n        this.handle.setSchematicMode(enabled);\n    }\n\n    @Override\n    public boolean hasTeamChatEnabled() {\n        return this.handle.hasTeamChatEnabled();\n    }\n\n    @Override\n    public void toggleTeamChat() {\n        this.handle.toggleTeamChat();\n    }\n\n    @Override\n    public void setTeamChat(boolean enabled) {\n        this.handle.setTeamChat(enabled);\n    }\n\n    @Override\n    public boolean hasBypassModeEnabled() {\n        return this.handle.hasBypassModeEnabled();\n    }\n\n    @Override\n    public void toggleBypassMode() {\n        this.handle.toggleBypassMode();\n    }\n\n    @Override\n    public void setBypassMode(boolean enabled) {\n        this.handle.setBypassMode(enabled);\n    }\n\n    @Override\n    public boolean hasToggledPanel() {\n        return this.handle.hasToggledPanel();\n    }\n\n    @Override\n    public void setToggledPanel(boolean toggledPanel) {\n        this.handle.setToggledPanel(toggledPanel);\n    }\n\n    @Override\n    public boolean hasIslandFlyEnabled() {\n        return this.handle.hasIslandFlyEnabled();\n    }\n\n    @Override\n    public void toggleIslandFly() {\n        this.handle.toggleIslandFly();\n    }\n\n    @Override\n    public void setIslandFly(boolean enabled) {\n        this.handle.setIslandFly(enabled);\n    }\n\n    @Override\n    public boolean hasAdminSpyEnabled() {\n        return this.handle.hasAdminSpyEnabled();\n    }\n\n    @Override\n    public void toggleAdminSpy() {\n        this.handle.toggleAdminSpy();\n    }\n\n    @Override\n    public void setAdminSpy(boolean enabled) {\n        this.handle.setAdminSpy(enabled);\n    }\n\n    @Override\n    public BorderColor getBorderColor() {\n        return this.handle.getBorderColor();\n    }\n\n    @Override\n    public void setBorderColor(BorderColor borderColor) {\n        this.handle.setBorderColor(borderColor);\n    }\n\n    @Override\n    public BlockPosition getSchematicPos1() {\n        return this.handle.getSchematicPos1();\n    }\n\n    @Override\n    public void setSchematicPos1(@Nullable Block block) {\n        this.handle.setSchematicPos1(block);\n    }\n\n    @Override\n    public BlockPosition getSchematicPos2() {\n        return this.handle.getSchematicPos2();\n    }\n\n    @Override\n    public void setSchematicPos2(@Nullable Block block) {\n        this.handle.setSchematicPos2(block);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isImmunedToPvP() {\n        return this.handle.isImmunedToPvP();\n    }\n\n    @Override\n    @Deprecated\n    public void setImmunedToPvP(boolean immunedToPvP) {\n        this.handle.setImmunedToPvP(immunedToPvP);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isLeavingFlag() {\n        return this.handle.isLeavingFlag();\n    }\n\n    @Override\n    @Deprecated\n    public void setLeavingFlag(boolean leavingFlag) {\n        this.handle.setLeavingFlag(leavingFlag);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isImmunedToPortals() {\n        return this.handle.isImmunedToPortals();\n    }\n\n    @Override\n    @Deprecated\n    public void setImmunedToPortals(boolean immuneToPortals) {\n        this.handle.setImmunedToPortals(immuneToPortals);\n    }\n\n    @Nullable\n    @Override\n    public BukkitTask getTeleportTask() {\n        return this.handle.getTeleportTask();\n    }\n\n    @Override\n    public void setTeleportTask(@Nullable BukkitTask teleportTask) {\n        this.handle.setTeleportTask(teleportTask);\n    }\n\n    @Override\n    @Deprecated\n    public PlayerStatus getPlayerStatus() {\n        return this.handle.getPlayerStatus();\n    }\n\n    @Override\n    public void setPlayerStatus(PlayerStatus playerStatus) {\n        this.handle.setPlayerStatus(playerStatus);\n    }\n\n    @Override\n    public void removePlayerStatus(PlayerStatus playerStatus) {\n        this.handle.removePlayerStatus(playerStatus);\n    }\n\n    @Override\n    public boolean hasPlayerStatus(PlayerStatus playerStatus) {\n        return this.handle.hasPlayerStatus(playerStatus);\n    }\n\n    @Override\n    public void merge(SuperiorPlayer otherPlayer) {\n        this.handle.merge(otherPlayer);\n    }\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        this.handle.completeMission(mission);\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        this.handle.resetMission(mission);\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return this.handle.hasCompletedMission(mission);\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        return this.handle.canCompleteMissionAgain(mission);\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        return this.handle.getAmountMissionCompleted(mission);\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        this.handle.setAmountMissionCompleted(mission, finishCount);\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return this.handle.getCompletedMissions();\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        return this.handle.getCompletedMissionsWithAmounts();\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return this.handle.getDatabaseBridge();\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        return this.handle.getPersistentDataContainer();\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return this.handle.isPersistentDataContainerEmpty();\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        this.handle.savePersistentDataContainer();\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/PlayerStatus.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player;\n\npublic enum PlayerStatus {\n\n    /**\n     * The player is immuned to PvP and cannot be damaged by other players.\n     */\n    PVP_IMMUNED,\n\n    /**\n     * The player cannot be teleported by portals.\n     */\n    PORTALS_IMMUNED,\n\n    /**\n     * The player cannot take damage from fall damage.\n     */\n    FALL_DAMAGE_IMMUNED,\n\n    /**\n     * The player recently left an island.\n     */\n    LEAVING_ISLAND,\n\n    /**\n     * The player is being teleported by void-teleport.\n     */\n    VOID_TELEPORT,\n\n    /**\n     * The player has no special status.\n     */\n    @Deprecated\n    NONE\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class DelegatePlayerTeleportAlgorithm implements PlayerTeleportAlgorithm {\n\n    protected final PlayerTeleportAlgorithm handle;\n\n    protected DelegatePlayerTeleportAlgorithm(PlayerTeleportAlgorithm handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Location location) {\n        return this.handle.teleport(player, location);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Island island) {\n        return this.handle.teleport(player, island);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Island island, Dimension dimension) {\n        return this.handle.teleport(player, island, dimension);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic interface PlayerTeleportAlgorithm {\n\n    /**\n     * Teleport a player to another location.\n     *\n     * @param player   The player to teleport.\n     * @param location The location to teleport the player to.\n     * @return CompletableFuture with boolean that indicates whether the teleportation was successful.\n     */\n    CompletableFuture<Boolean> teleport(Player player, Location location);\n\n    /**\n     * Teleport a player to an island.\n     *\n     * @param player The player to teleport.\n     * @param island The island to teleport the player to.\n     * @return CompletableFuture with boolean that indicates whether the teleportation was successful.\n     */\n    CompletableFuture<Boolean> teleport(Player player, Island island);\n\n    /**\n     * Teleport a player to an island in a specific dimension.\n     *\n     * @param player    The player to teleport.\n     * @param island    The island to teleport the player to.\n     * @param dimension The dimension to teleport the player to.\n     * @return CompletableFuture with boolean that indicates whether the teleportation was successful.\n     */\n    CompletableFuture<Boolean> teleport(Player player, Island island, Dimension dimension);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.cache;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.function.Function;\n\n/**\n * Player caches can be used by other plugins to store temporary data for a player, retrieve it, etc.\n * The cache is not persistent between server sessions. For persistent data solution, see {@link SuperiorPlayer#getPersistentDataContainer()}\n * Data can be stored and retrieved by registering custom {@link PlayerCacheKey} for your plugin.\n * The cache is thread-safe and can be accessed from multiple threads.\n */\npublic interface PlayerCache {\n\n    /**\n     * Get the player this cache is for.\n     */\n    SuperiorPlayer getPlayer();\n\n    /**\n     * Store data in this cache.\n     *\n     * @param key   The key to store.\n     * @param value The value to store.\n     * @return The old value that was stored in the cache, or null if not data was cached.\n     */\n    @Nullable\n    <T> T store(PlayerCacheKey<T> key, T value);\n\n    /**\n     * Remove data from this cache.\n     *\n     * @param key The cache key.\n     * @return The old value that was stored in the cache, or null if not data was cached.\n     */\n    @Nullable\n    <T> T remove(PlayerCacheKey<T> key);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key The cache key\n     * @return The value stored for the provided key, or null if no data was cached.\n     */\n    @Nullable\n    <T> T get(PlayerCacheKey<T> key);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key The cache key\n     * @param def The value to return in case the cache did not contain the provided key\n     * @return The value stored for the provided key.\n     */\n    <T> T getOrDefault(PlayerCacheKey<T> key, T def);\n\n    /**\n     * Get data that was stored.\n     *\n     * @param key             The cache key\n     * @param mappingFunction The value to store in case the cache did not contain the provided key\n     * @return The value stored for the provided key.\n     */\n    <T> T computeIfAbsent(PlayerCacheKey<T> key, Function<PlayerCacheKey<T>, T> mappingFunction);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.cache;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class PlayerCacheKey<T> implements Enumerable {\n\n    private static final Map<String, PlayerCacheKey<?>> playerCacheKeys = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final Class<T> valueType;\n    private final int ordinal;\n\n    private PlayerCacheKey(String name, Class<T> valueType) {\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.valueType = valueType;\n        this.ordinal = ordinalCounter++;\n    }\n\n    /**\n     * Get the name of the player cache key.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Get the type of the value for this cache-key.\n     */\n    public Class<T> getValueType() {\n        return valueType;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    @Override\n    public String toString() {\n        return \"PlayerCacheKey{name=\" + name + \"}\";\n    }\n\n    /**\n     * Get all the player cache keys.\n     */\n    public static Collection<PlayerCacheKey<?>> values() {\n        return playerCacheKeys.values();\n    }\n\n    /**\n     * Get an player cache key by its name.\n     *\n     * @param name The name to check.\n     */\n    public static PlayerCacheKey<?> getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        PlayerCacheKey<?> playerCacheKey = playerCacheKeys.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(playerCacheKey, \"Couldn't find an PlayerCacheKey with the name \" + name + \".\");\n\n        return playerCacheKey;\n    }\n\n    /**\n     * Register a new player cache key.\n     *\n     * @param name The name for the player cache key.\n     */\n    public static <T> void register(String name, Class<T> valueType) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        name = name.toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!playerCacheKeys.containsKey(name), \"PlayerCacheKey with the name \" + name + \" already exists.\");\n\n        playerCacheKeys.put(name, new PlayerCacheKey<>(name, valueType));\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic class DelegatePlayersContainer implements PlayersContainer {\n\n    protected final PlayersContainer handle;\n\n    protected DelegatePlayersContainer(PlayersContainer handle) {\n        this.handle = handle;\n    }\n\n    @Nullable\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(String name) {\n        return this.handle.getSuperiorPlayer(name);\n    }\n\n    @Nullable\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(UUID uuid) {\n        return this.handle.getSuperiorPlayer(uuid);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayers() {\n        return this.handle.getAllPlayers();\n    }\n\n    @Override\n    public void addPlayer(SuperiorPlayer superiorPlayer) {\n        this.handle.addPlayer(superiorPlayer);\n    }\n\n    @Override\n    public void removePlayer(SuperiorPlayer superiorPlayer) {\n        this.handle.removePlayer(superiorPlayer);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/PlayersContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic interface PlayersContainer {\n\n    /**\n     * Get a player by its name.\n     *\n     * @param name The name of the player.\n     */\n    @Nullable\n    SuperiorPlayer getSuperiorPlayer(String name);\n\n    /**\n     * Get a player by its uuid.\n     *\n     * @param uuid The uuid of the player.\n     */\n    @Nullable\n    SuperiorPlayer getSuperiorPlayer(UUID uuid);\n\n    /**\n     * Get all the players.\n     */\n    List<SuperiorPlayer> getAllPlayers();\n\n    /**\n     * Add a player to the container.\n     *\n     * @param superiorPlayer The player to add.\n     */\n    void addPlayer(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Remove a player from the container.\n     *\n     * @param superiorPlayer The player to remove.\n     */\n    void removePlayer(SuperiorPlayer superiorPlayer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.inventory;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic abstract class ClearAction implements Enumerable {\n\n    private static final Map<String, ClearAction> clearActions = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final int ordinal;\n\n    protected ClearAction(String name) {\n        Preconditions.checkArgument(!clearActions.containsKey(name), \"name already exists.\");\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public final int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get the name of the clear action.\n     */\n    public final String getName() {\n        return name;\n    }\n\n    /**\n     * Execute this {@link ClearAction} on the player {@param player};\n     *\n     * @param player The player to run the clear action on.\n     *               The player instance might be fake for offline players.\n     *               Do not save it elsewhere, only run actions that change its data.\n     */\n    public abstract void doClear(Player player);\n\n    @Override\n    public String toString() {\n        return \"ClearAction{name=\" + name + \"}\";\n    }\n\n    /**\n     * Get all the clear actions.\n     */\n    public static Collection<ClearAction> values() {\n        return clearActions.values();\n    }\n\n    /**\n     * Get a clear action by its name.\n     *\n     * @param name The name to check.\n     */\n    public static ClearAction getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        ClearAction clearAction = clearActions.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(clearAction, \"Couldn't find an ClearAction with the name \" + name + \".\");\n\n        return clearAction;\n    }\n\n    /**\n     * Register a new clear action.\n     *\n     * @param clearAction The clear action to register.\n     */\n    public static void register(ClearAction clearAction) {\n        Preconditions.checkNotNull(clearAction, \"clearAction parameter cannot be null.\");\n\n        String name = clearAction.getName().toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!clearActions.containsKey(name), \"ClearAction with the name \" + name + \" already exists.\");\n\n        clearActions.put(name, clearAction);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/player/respawn/RespawnAction.java",
    "content": "package com.bgsoftware.superiorskyblock.api.player.respawn;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.player.PlayerRespawnEvent;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic abstract class RespawnAction implements Enumerable {\n\n    private static final Map<String, RespawnAction> respawnActions = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final int ordinal;\n\n    protected RespawnAction(String name) {\n        Preconditions.checkArgument(!respawnActions.containsKey(name), \"name already exists.\");\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public final int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get the name of the respawn action.\n     */\n    public final String getName() {\n        return name;\n    }\n\n    @Override\n    public String toString() {\n        return \"RespawnAction{name=\" + name + \"}\";\n    }\n\n    public abstract boolean canPerform(PlayerRespawnEvent event);\n\n    public abstract void perform(PlayerRespawnEvent event);\n\n    /**\n     * Get all the respawn actions.\n     */\n    public static Collection<RespawnAction> values() {\n        return respawnActions.values();\n    }\n\n    /**\n     * Get a respawn action by its name.\n     *\n     * @param name The name to check.\n     */\n    public static RespawnAction getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        RespawnAction respawnAction = respawnActions.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(respawnAction, \"Couldn't find an RespawnAction with the name \" + name + \".\");\n\n        return respawnAction;\n    }\n\n    /**\n     * Register a new respawn action.\n     *\n     * @param respawnAction The respawn action to register.\n     */\n    public static void register(RespawnAction respawnAction) {\n        Preconditions.checkNotNull(respawnAction, \"respawnAction parameter cannot be null.\");\n\n        String name = respawnAction.getName().toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!respawnActions.containsKey(name), \"RespawnAction with the name \" + name + \" already exists.\");\n\n        respawnActions.put(name, respawnAction);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/Schematic.java",
    "content": "package com.bgsoftware.superiorskyblock.api.schematic;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport org.bukkit.Location;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic interface Schematic {\n\n    /**\n     * Get the name of the schematic.\n     */\n    String getName();\n\n    /**\n     * Paste te schematic in a specific location.\n     *\n     * @param island   The island of the schematic.\n     * @param location The location to paste the schematic at.\n     * @param callback A callback runnable that runs when the process finishes\n     */\n    void pasteSchematic(Island island, Location location, Runnable callback);\n\n    /**\n     * Paste te schematic in a specific location.\n     *\n     * @param island    The island of the schematic.\n     * @param location  The location to paste the schematic at.\n     * @param callback  A callback runnable that runs when the process finishes\n     * @param onFailure A consumer that will be ran if the creation fails.\n     */\n    void pasteSchematic(Island island, Location location, Runnable callback, @Nullable Consumer<Throwable> onFailure);\n\n    /**\n     * Adjust schematic's rotations to the given location.\n     *\n     * @param location The location to adjust.\n     * @return The exact same object given as a parameter.\n     */\n    Location adjustRotation(Location location);\n\n    /**\n     * Get the block counts of the schematic.\n     */\n    Map<Key, Integer> getBlockCounts();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java",
    "content": "package com.bgsoftware.superiorskyblock.api.schematic;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\n\n/**\n * This class represents options for creating schematics.\n */\npublic interface SchematicOptions {\n\n    /**\n     * Get the name of the schematic.\n     */\n    String getSchematicName();\n\n    /**\n     * Get the offset in the x-axis of the schematic.\n     */\n    int getOffsetX();\n\n    /**\n     * Get the offset in the y-axis of the schematic.\n     */\n    int getOffsetY();\n\n    /**\n     * Get the offset in the z-axis of the schematic.\n     */\n    int getOffsetZ();\n\n    /**\n     * Get the yaw of the schematic.\n     */\n    float getYaw();\n\n    /**\n     * Get the pitch of the schematic.\n     */\n    float getPitch();\n\n    /**\n     * Get whether the schematic should save air blocks.\n     */\n    boolean shouldSaveAir();\n\n    /**\n     * Create a new builder for a {@link SchematicOptions} object.\n     *\n     * @param schematicName The name of the schematic to create.\n     */\n    static Builder newBuilder(String schematicName) {\n        return SuperiorSkyblockAPI.getFactory().createSchematicOptionsBuilder(schematicName);\n    }\n\n    interface Builder {\n\n        default Builder setOffsetX(int offsetX) {\n            return setOffset(offsetX, 0, 0);\n        }\n\n        default Builder setOffsetY(int offsetY) {\n            return setOffset(0, offsetY, 0);\n        }\n\n        default Builder setOffsetZ(int offsetZ) {\n            return setOffset(0, 0, offsetZ);\n        }\n\n        Builder setOffset(int offsetX, int offsetY, int offsetZ);\n\n        default Builder setYaw(float yaw) {\n            return setDirection(yaw, 0f);\n        }\n\n        default Builder setPitch(float pitch) {\n            return setDirection(0f, pitch);\n        }\n\n        Builder setDirection(float yaw, float pitch);\n\n        Builder setSaveAir(boolean saveAir);\n\n        SchematicOptions build();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/parser/SchematicParseException.java",
    "content": "package com.bgsoftware.superiorskyblock.api.schematic.parser;\n\nimport java.io.DataInputStream;\n\n/**\n * This exception is used inside {@link SchematicParser#parseSchematic(DataInputStream, String)}\n * when a faulty stream is given to the parser.\n */\npublic class SchematicParseException extends Exception {\n\n    public SchematicParseException(String error) {\n        super(error);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/parser/SchematicParser.java",
    "content": "package com.bgsoftware.superiorskyblock.api.schematic.parser;\n\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\n\nimport java.io.DataInputStream;\n\npublic interface SchematicParser {\n\n    /**\n     * Parse a schematic from a stream.\n     *\n     * @param inputStream   The stream to parse the schematic from.\n     * @param schematicName The name of the schematic.\n     * @return A new {@link Schematic} object from the stream.\n     * @throws SchematicParseException If the stream doesn't meet the format of this parser.\n     */\n    Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException;\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/scripts/IScriptEngine.java",
    "content": "package com.bgsoftware.superiorskyblock.api.scripts;\n\nimport javax.script.Bindings;\nimport javax.script.ScriptException;\n\npublic interface IScriptEngine {\n\n    /**\n     * Evaluate an expression.\n     *\n     * @param expression The expression to evaluate.\n     * @return The result of the expression.\n     * @throws ScriptException If the format of the expression is invalid.\n     */\n    Object eval(String expression) throws ScriptException;\n\n    /**\n     * Evaluate an expression.\n     *\n     * @param expression The expression to evaluate.\n     * @param bindings   A bindings map for the expression.\n     * @return The result of the expression.\n     * @throws ScriptException If the format of the expression is invalid.\n     */\n    Object eval(String expression, Bindings bindings) throws ScriptException;\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/bossbar/BossBar.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.bossbar;\n\nimport org.bukkit.entity.Player;\n\npublic interface BossBar {\n\n    /**\n     * Display this boss-bar to a player.\n     *\n     * @param player The player to display the boss-bar to.\n     */\n    void addPlayer(Player player);\n\n    /**\n     * Stop displaying this boss-bar to all the players.\n     */\n    void removeAll();\n\n    /**\n     * Set the progress bar of this boss-bar.\n     *\n     * @param progress The progress to set.\n     */\n    void setProgress(double progress);\n\n    /**\n     * Get the progress bar of this boss-bar.\n     */\n    double getProgress();\n\n    enum Color {\n\n        PINK,\n        BLUE,\n        RED,\n        GREEN,\n        YELLOW,\n        PURPLE,\n        WHITE\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/bossbar/BossBarsService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.bossbar;\n\nimport org.bukkit.entity.Player;\n\npublic interface BossBarsService {\n\n    /**\n     * Create a new boss-bar.\n     *\n     * @param player     The player to create the boss-bar for.\n     * @param message    The message to display in the boss-bar.\n     * @param color      The color of the boss-bar.\n     * @param ticksToRun The time to run the boss-bar.\n     *                   If set to 0 or below, it will stay forever.\n     */\n    BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleResetResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.dragon;\n\npublic enum DragonBattleResetResult {\n\n    /**\n     * The dragon battle could not be reset because they are disabled on the server.\n     */\n    DRAGON_BATTLES_DISABLED,\n\n    /**\n     * The dragon battle could not be reset because the world was never generated before.\n     */\n    WORLD_NOT_GENERATED,\n\n    /**\n     * The dragon battle could not be reset because the world is not unlocked for the island.\n     */\n    WORLD_NOT_UNLOCKED,\n\n    /**\n     * The dragon battle was successfully been reset.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.World;\nimport org.bukkit.entity.EnderDragon;\n\npublic interface DragonBattleService {\n\n    /**\n     * Prepare an end world for dragon fights.\n     *\n     * @param world The world to prepare.\n     */\n    void prepareEndWorld(World world);\n\n    /**\n     * Get the current active ender dragon of an island.\n     * If there is no active fight, null is returned.\n     *\n     * @param island The island to get the dragon for.\n     */\n    @Nullable\n    EnderDragon getEnderDragon(Island island, Dimension dimension);\n\n    /**\n     * Stop the dragon battle fight for an island.\n     * The dragon will be killed and {@link #getEnderDragon(Island, Dimension)} will return null.\n     */\n    void stopEnderDragonBattle(Island island, Dimension dimension);\n\n    /**\n     * Reset the dragon battle fight for an island.\n     *\n     * @param island The island to reset the fight for.\n     */\n    DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension);\n\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/hologram/Hologram.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.hologram;\n\nimport org.bukkit.entity.ArmorStand;\n\npublic interface Hologram {\n\n    /**\n     * Set the name to be displayed for this hologram.\n     *\n     * @param name The new name to set.\n     */\n    void setHologramName(String name);\n\n    /**\n     * Remove the hologram from existence.\n     */\n    void removeHologram();\n\n    /**\n     * Get the actual armor stand entity for this hologram.\n     * This is a custom armor stand for the hologram, and therefore it may not function\n     * similar to Bukkit's regular entities.\n     */\n    ArmorStand getHandle();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/hologram/HologramsService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.hologram;\n\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\npublic interface HologramsService {\n\n    /**\n     * Create a new hologram.\n     *\n     * @param location The location of the new hologram.\n     * @return The new created hologram.\n     */\n    Hologram createHologram(Location location);\n\n    /**\n     * Checks whether an entity is a hologram.\n     *\n     * @param entity The entity to check.\n     */\n    boolean isHologram(Entity entity);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.message;\n\nimport org.bukkit.command.CommandSender;\n\npublic interface IMessageComponent {\n\n    /**\n     * Get the type of this component.\n     */\n    Type getType();\n\n    /**\n     * Get the raw message of this component.\n     *\n     * @deprecated See {@link #getMessage(Object...)}\n     */\n    @Deprecated\n    String getMessage();\n\n    /**\n     * Get the raw message of this component.\n     */\n    default String getMessage(Object... args) {\n        return getMessage();\n    }\n\n    /**\n     * Send this message to a {@link CommandSender}.\n     *\n     * @param sender The {@link CommandSender} to send the message to.\n     * @param args   The arguments of the message.\n     */\n    void sendMessage(CommandSender sender, Object... args);\n\n    enum Type {\n\n        /**\n         * The component represents an action bar.\n         */\n        ACTION_BAR,\n\n        /**\n         * The component represents a boss bar.\n         */\n        BOSS_BAR,\n\n        /**\n         * The component represents a complex message.\n         * Complex messages are raw text that can be sent to players, however they have extra functionalities,\n         * such as clickable messages, hover messages, etc.\n         */\n        COMPLEX_MESSAGE,\n\n        /**\n         * The component represents an empty message.\n         * This type of component is used when the message of the component is empty or invalid.\n         */\n        EMPTY,\n\n        /**\n         * The component represents multiple components.\n         * This type of component is a container for different other components inside it. This gives the ability\n         * to combine different component types for the same message - for example, sending a message while playing\n         * a sound. Therefore, by calling {@link #sendMessage(CommandSender, Object...)} on it, all the components it contains\n         * will be sent at the same time.\n         */\n        MULTIPLE,\n\n        /**\n         * The component represents a raw text message.\n         */\n        RAW_MESSAGE,\n\n        /**\n         * The component represents a sound.\n         * When sending this component, a sound will be played instead of a message to be sent.\n         */\n        SOUND,\n\n        /**\n         * The component represents a title.\n         * Titles are the big text that can be shown in the middle of the screen of a player.\n         */\n        TITLE\n\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/MessagesService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.message;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport net.md_5.bungee.api.chat.BaseComponent;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport org.bukkit.Sound;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.Locale;\n\npublic interface MessagesService {\n\n    /**\n     * Parse a message from config file into a message component.\n     *\n     * @param config The configuration file.\n     * @param path   The path of the message.\n     * @return the parsed component message.\n     */\n    IMessageComponent parseComponent(YamlConfiguration config, String path);\n\n    /**\n     * Get a component of a built-in message of the plugin.\n     *\n     * @param message The name of the message, similar to its name in the lang file of the plugin.\n     * @param locale  The locale to retrieve the message for.\n     *                For player's locale, use {@link SuperiorPlayer#getUserLocale()}\n     */\n    @Nullable\n    IMessageComponent getComponent(String message, Locale locale);\n\n    /**\n     * Create a new builder for message components.\n     */\n    Builder newBuilder();\n\n    /**\n     * Builder class for creating {@link IMessageComponent}s\n     */\n    interface Builder {\n\n        /**\n         * Add an action bar text to the message component.\n         *\n         * @param message The action bar text.\n         * @return true if the action bar was successfully added.\n         */\n        boolean addActionBar(@Nullable String message);\n\n        /**\n         * Add boss bar to the message component.\n         *\n         * @param message The text to be displayed in the boss bar\n         * @param color   The color of the boss bar\n         * @param ticks   The duration of the boss bar, in ticks.\n         * @return true if the boss bar was successfully added.\n         */\n        boolean addBossBar(@Nullable String message, BossBar.Color color, int ticks);\n\n        /**\n         * Add a complex message to the message component.\n         *\n         * @param textComponent The text component.\n         * @return true if the complex message was successfully added.\n         */\n        boolean addComplexMessage(@Nullable TextComponent textComponent);\n\n        /**\n         * Add a complex message to the message component.\n         *\n         * @param baseComponents The base components of the message.\n         * @return true if the complex message was successfully added.\n         */\n        boolean addComplexMessage(@Nullable BaseComponent[] baseComponents);\n\n        /**\n         * Add a raw message to the message component.\n         *\n         * @param message The raw text.\n         * @return true if the raw message was successfully added.\n         */\n        boolean addRawMessage(@Nullable String message);\n\n        /**\n         * Add a sound to the message component.\n         *\n         * @param sound  The sound to be played.\n         * @param volume The volume of the sound.\n         * @param pitch  The pitch of the sound.\n         * @return true if the sound was successfully added.\n         */\n        boolean addSound(Sound sound, float volume, float pitch);\n\n        /**\n         * Add a title to the message component.\n         *\n         * @param titleMessage    The first line of the title.\n         * @param subtitleMessage The second line of the title.\n         * @param fadeIn          The duration of the fade in animation, in ticks.\n         * @param duration        The duration of the title to last, in ticks.\n         * @param fadeOut         The duration of the fade out animation, in ticks.\n         * @return true if the title was successfully added.\n         */\n        boolean addTitle(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut);\n\n        /**\n         * Add another message component to the message component.\n         *\n         * @param messageComponent The other message component to add.\n         * @return true if the message component was successfully added.\n         */\n        boolean addMessageComponent(IMessageComponent messageComponent);\n\n        /**\n         * Build a new message component from the given builder.\n         */\n        IMessageComponent build();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/IslandPlaceholderParser.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.placeholders;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.function.BiFunction;\n\n/**\n * This class represents an island placeholder parser.\n * It should give an output of the parsed value for an island.\n */\npublic interface IslandPlaceholderParser extends BiFunction<Island, SuperiorPlayer, String> {\n\n    /**\n     * Get the result of this placeholder for the given island.\n     *\n     * @param island         The island to parse.\n     * @param superiorPlayer The player that requested the placeholder.\n     * @return The parsed result.\n     */\n    @Override\n    @Nullable\n    String apply(@Nullable Island island, SuperiorPlayer superiorPlayer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/PlaceholdersService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.placeholders;\n\nimport org.bukkit.OfflinePlayer;\n\npublic interface PlaceholdersService {\n\n    /**\n     * Parse placeholders in a given string.\n     *\n     * @param offlinePlayer The player to parse placeholders to.\n     * @param value         The string to parse.\n     * @return The same string with the placeholders after they were parsed.\n     */\n    String parsePlaceholders(OfflinePlayer offlinePlayer, String value);\n\n    /**\n     * Register a new placeholder.\n     *\n     * @param placeholderName     The name of the placeholder.\n     *                            The name is the part in the placeholder after the prefix (`superior_<name>`)\n     * @param placeholderFunction The parser to run when the placeholder is evaluated.\n     *                            It is recommended to cache all values return by the placeholder for best performance.\n     */\n    void registerPlaceholder(String placeholderName, IslandPlaceholderParser placeholderFunction);\n\n    /**\n     * Register a new placeholder.\n     *\n     * @param placeholderName     The name of the placeholder.\n     *                            The name is the part in the placeholder after the prefix (`superior_<name>`)\n     * @param placeholderFunction The parser to run when the placeholder is evaluated.\n     *                            It is recommended to cache all values return by the placeholder for best performance.\n     */\n    void registerPlaceholder(String placeholderName, PlayerPlaceholderParser placeholderFunction);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/PlayerPlaceholderParser.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.placeholders;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.function.Function;\n\n/**\n * This class represents a player placeholder parser.\n * It should give an output of the parsed value for a player.\n */\npublic interface PlayerPlaceholderParser extends Function<SuperiorPlayer, String> {\n\n    /**\n     * Get the result of this placeholder for the given player.\n     *\n     * @param superiorPlayer The player that requested the placeholder.\n     * @return The parsed result.\n     */\n    @Nullable\n    @Override\n    String apply(SuperiorPlayer superiorPlayer);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/EntityPortalResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.portals;\n\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent;\n\npublic enum EntityPortalResult {\n\n    /**\n     * The player is immuned to portal teleports.\n     */\n    PLAYER_IMMUNED_TO_PORTAL,\n\n    /**\n     * The portal is not inside an island.\n     */\n    PORTAL_NOT_IN_ISLAND,\n\n    /**\n     * The player cannot enter the island the portal leads to.\n     */\n    DESTINATION_ISLAND_NOT_PERMITTED,\n\n    /**\n     * The world the portal leads to is not an islands world.\n     */\n    DESTINATION_NOT_ISLAND_WORLD,\n\n    /**\n     * The world the portal leads to is disabled.\n     */\n    DESTINATION_WORLD_DISABLED,\n\n    /**\n     * The world the portal leads to is not unlocked for the island.\n     */\n    WORLD_NOT_UNLOCKED,\n\n    /**\n     * The schematic for the destination world is being generated.\n     */\n    SCHEMATIC_GENERATING_COOLDOWN,\n\n    /**\n     * The {@link IslandEnterPortalEvent} event that had been fired was cancelled.\n     */\n    PORTAL_EVENT_CANCELLED,\n\n    /**\n     * There is no valid schematic for the destination world.\n     */\n    INVALID_SCHEMATIC,\n\n    /**\n     * The entity went through the portal successfully.\n     */\n    SUCCEED\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.portals;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.entity.Entity;\n\npublic interface PortalsManagerService {\n\n    /**\n     * Handle a player going through a portal.\n     *\n     * @param superiorPlayer            The player that entered the portal.\n     * @param portalLocation            The location of the portal.\n     * @param portalType                The type of the portal.\n     * @param destinationLocation       The location that the player should be teleported to.\n     * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Location portalLocation, PortalType portalType,\n                                          Location destinationLocation, boolean checkImmunedPortalsStatus);\n\n    /**\n     * Handle an entity going through a portal.\n     *\n     * @param entity              The entity that entered the portal.\n     * @param portalLocation      The location of the portal.\n     * @param portalType          The type of the portal.\n     * @param destinationLocation The location that the player should be teleported to.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handleEntityPortal(Entity entity, Location portalLocation, PortalType portalType,\n                                          Location destinationLocation);\n\n    /**\n     * Handle a player going through a portal on an island.\n     *\n     * @param superiorPlayer            The player that entered the portal.\n     * @param island                    The island the portal is inside.\n     * @param portalLocation            The location of the portal.\n     * @param portalType                The type of the portal.\n     * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island,\n                                                    Location portalLocation, PortalType portalType,\n                                                    boolean checkImmunedPortalsStatus);\n\n    /**\n     * Handle a player going through a portal on an island.\n     *\n     * @param superiorPlayer            The player that entered the portal.\n     * @param island                    The island the portal is inside.\n     * @param portalLocation            The location of the portal.\n     * @param portalType                The type of the portal.\n     * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports.\n     * @param destinationLocation       The location that the player should be teleported to.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island,\n                                                    Location portalLocation, PortalType portalType,\n                                                    Location destinationLocation, boolean checkImmunedPortalsStatus);\n\n    /**\n     * Handle an entity going through a portal on an island.\n     *\n     * @param entity         The entity that entered the portal.\n     * @param island         The island the portal is inside.\n     * @param portalLocation The location of the portal.\n     * @param portalType     The type of the portal.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation,\n                                                    PortalType portalType);\n\n    /**\n     * Handle an entity going through a portal on an island.\n     *\n     * @param entity              The entity that entered the portal.\n     * @param island              The island the portal is inside.\n     * @param portalLocation      The location of the portal.\n     * @param portalType          The type of the portal.\n     * @param destinationLocation The location that the player should be teleported to.\n     * @return The result of going through the portal.\n     */\n    EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation,\n                                                    PortalType portalType, Location destinationLocation);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/InteractionResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.region;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\n\npublic enum InteractionResult {\n\n    /**\n     * The interaction was made outside an island.\n     */\n    OUTSIDE_ISLAND,\n\n    /**\n     * The player is missing an {@link IslandPrivilege} for doing the interaction.\n     */\n    MISSING_PRIVILEGE,\n\n    /**\n     * The interaction that was made cannot be done while the island is being recalculated.\n     */\n    ISLAND_RECALCULATE,\n\n    /**\n     * The interaction can be done.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/MoveResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.region;\n\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent;\n\npublic enum MoveResult {\n\n    /**\n     * The player cannot do the movement as he is banned from the island.\n     */\n    BANNED_FROM_ISLAND,\n\n    /**\n     * The player cannot do the movement as the island is locked to the public.\n     */\n    ISLAND_LOCKED,\n\n    /**\n     * The {@link IslandEnterEvent} event was cancelled.\n     */\n    ENTER_EVENT_CANCELLED,\n\n    /**\n     * The player cannot move out of an island into the wilderness.\n     */\n    LEAVE_ISLAND_TO_OUTSIDE,\n\n    /**\n     * The player was moved too far away while being in island-preview mode.\n     */\n    ISLAND_PREVIEW_MOVED_TOO_FAR,\n\n    /**\n     * The player was teleported due to void-teleport.\n     */\n    VOID_TELEPORT,\n\n    /**\n     * The player can do the movement.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.region;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface RegionManagerService {\n\n    /**\n     * Handle a block being placed.\n     *\n     * @param superiorPlayer The player that placed the block.\n     * @param block          The block that was placed.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block block);\n\n    /**\n     * Handle a block being broken.\n     *\n     * @param superiorPlayer The player that broke the block.\n     * @param block          The block that was broken.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block block);\n\n    /**\n     * Handle a player interacting with a block.\n     *\n     * @param superiorPlayer The player that made the interaction.\n     * @param block          The block that the player interacted with.\n     * @param action         The action that the player did.\n     * @param usedItem       The item that was used to interact.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Block block, Action action,\n                                          @Nullable ItemStack usedItem);\n\n    /**\n     * Handle a player fertilizing a block.\n     *\n     * @param superiorPlayer The player that fertilized the block.\n     * @param block          The block that was fertilized by the player.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Block block);\n\n    /**\n     * Handle a player interacting with an entity.\n     *\n     * @param superiorPlayer The player that made the interaction.\n     * @param entity         The entity that the player interacted with.\n     * @param usedItem       The item that was used to interact.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Entity entity, @Nullable ItemStack usedItem);\n\n    /**\n     * Handle a player shearing an entity.\n     *\n     * @param superiorPlayer The player that sheared the entity.\n     * @param entity         The entity that was sheared.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity entity);\n\n    /**\n     * Handle a player leashing an entity.\n     *\n     * @param superiorPlayer The player that leashed the entity.\n     * @param entity         The entity that was leashed.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity entity);\n\n    /**\n     * Handle a player picking up an item.\n     *\n     * @param superiorPlayer The player that picked up the item.\n     * @param item           The item that was picked up.\n     * @return The result of the interaction.\n     */\n    InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, Item item);\n\n    /**\n     * Handle a player dropping an item.\n     *\n     * @param superiorPlayer The player that dropped the item.\n     * @param item           The item that was dropped.\n     * @return The result of the interaction.\n     */\n    InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Item item);\n\n    /**\n     * Handle a player using an ender pearl.\n     *\n     * @param superiorPlayer The player that used the ender pearl.\n     * @param destination    The location of the teleportation of the ender pearl.\n     * @return The result of the interaction.\n     */\n    InteractionResult handlePlayerEnderPearl(SuperiorPlayer superiorPlayer, Location destination);\n\n    /**\n     * Handle a player consuming a Chorus Fruit.\n     *\n     * @param superiorPlayer The player that consumed the Chorus Fruit.\n     * @param location       The location of the player.\n     * @return The result of the interaction.\n     */\n    InteractionResult handlePlayerConsumeChorusFruit(SuperiorPlayer superiorPlayer, Location location);\n\n    /**\n     * Handle a player using a wind charge.\n     *\n     * @param superiorPlayer The player that used the wind charge.\n     * @param location       The location of the player.\n     * @return The result of the interaction.\n     */\n    InteractionResult handlePlayerUseWindCharge(SuperiorPlayer superiorPlayer, Location location);\n\n    /**\n     * Handle an entity damaging another entity.\n     *\n     * @param damager The entity that dealt the damage.\n     * @param entity  The entity that was damaged.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleEntityDamage(Entity damager, Entity entity);\n\n    /**\n     * Handle a player riding an entity.\n     *\n     * @param superiorPlayer The player that rides the entity.\n     * @param vehicle        The entity that is ridden.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle);\n\n    /**\n     * Handle a custom interaction of a player.\n     *\n     * @param superiorPlayer  The player that made the interaction.\n     * @param location        The location of the interaction.\n     * @param islandPrivilege The privilege required for doing the interaction.\n     * @return The result of the interaction.\n     */\n    InteractionResult handleCustomInteraction(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege);\n\n    /**\n     * Handle a player movement.\n     *\n     * @param superiorPlayer The player that made the movement.\n     * @param from           The location of the player.\n     * @param to             The new location of the player after the movement.\n     * @return The result of the movement.\n     */\n    MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to);\n\n    /**\n     * Handle a player teleportation.\n     *\n     * @param superiorPlayer The player that made the teleportation.\n     * @param from           The location of the player.\n     * @param to             The new location of the player after the teleportation.\n     * @return The result of the teleportation.\n     */\n    MoveResult handlePlayerTeleport(SuperiorPlayer superiorPlayer, Location from, Location to);\n\n    /**\n     * Handle a player teleportation by a portal.\n     *\n     * @param superiorPlayer   The player that made the teleportation.\n     * @param portalLocation   The location of the portal.\n     * @param teleportLocation The new location of the player after the teleportation.\n     * @return The result of the teleportation.\n     */\n    MoveResult handlePlayerTeleportByPortal(SuperiorPlayer superiorPlayer, Location portalLocation, Location teleportLocation);\n\n    /**\n     * Handle a player joining the server.\n     *\n     * @param superiorPlayer The player that joined the server.\n     * @param location       The location of the player.\n     * @return The result of joining the server.\n     */\n    MoveResult handlePlayerJoin(SuperiorPlayer superiorPlayer, Location location);\n\n    /**\n     * Handle a player leaving the server.\n     *\n     * @param superiorPlayer The player that left the server.\n     * @param location       The location of the player.\n     * @return The result of leaving the server.\n     */\n    MoveResult handlePlayerQuit(SuperiorPlayer superiorPlayer, Location location);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/stackedblocks/InteractionResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.api.events.BlockStackEvent;\nimport com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent;\n\npublic enum InteractionResult {\n\n    /**\n     * The stacked-blocks system is disabled.\n     */\n    STACKED_BLOCKS_DISABLED,\n\n    /**\n     * The world that the player tries to stack blocks in is disabled for stacking blocks.\n     */\n    DISABLED_WORLD,\n\n    /**\n     * The player has toggled off his ability to stack blocks.\n     */\n    PLAYER_STACKED_BLOCKS_DISABLED,\n\n    /**\n     * The used item to stack the block has a name or a lore, and cannot be used to stack blocks.\n     */\n    CUSTOMIZED_ITEM,\n\n    /**\n     * The item used by the player to stack blocks is different from the block.\n     */\n    PLAYER_HOLDING_DIFFERENT_ITEM,\n\n    /**\n     * The player does not have the permission to stack this type of block.\n     */\n    PLAYER_MISSING_PERMISSION,\n\n    /**\n     * The block cannot be stacked as it is not whitelisted.\n     */\n    STACKED_BLOCK_NOT_WHITELISTED,\n\n    /**\n     * The player does not have enough items in his inventory in order to stack the blocks.\n     */\n    NOT_ENOUGH_BLOCKS,\n\n    /**\n     * The event that had been fired ({@link BlockStackEvent}, {@link BlockUnstackEvent}) was cancelled.\n     */\n    EVENT_CANCELLED,\n\n    /**\n     * An unexpected behavior occurred and the plugin prevented the block from being stacked.\n     */\n    GLITCHED_STACKED_BLOCK,\n\n    /**\n     * The block that was being unstacked is not an actual stacked block.\n     */\n    NOT_STACKED_BLOCK,\n\n    /**\n     * The block is protected by another island.\n     */\n    STACKED_BLOCK_PROTECTED,\n\n    /**\n     * The block was successfully stacked or unstacked.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/stackedblocks/StackedBlocksInteractionService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.stackedblocks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.block.Block;\nimport org.bukkit.inventory.EquipmentSlot;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface StackedBlocksInteractionService {\n\n    /**\n     * Handle a stacked block being placed.\n     *\n     * @param superiorPlayer The player that stacked the block.\n     * @param block          The block to stack into.\n     * @param usedHand       The hand that was used when placing the block.\n     * @return The result of stacking the block.\n     */\n    InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, EquipmentSlot usedHand);\n\n    /**\n     * Handle a stacked block being placed.\n     *\n     * @param superiorPlayer      The player that stacked the block.\n     * @param block               The block to stack into.\n     * @param amountToDeposit     The amount of blocks that were stacked.\n     * @param itemRemovalCallback Callback to remove items from the inventory of the player.\n     * @return The result of stacking the block.\n     */\n    InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, int amountToDeposit,\n                                              OnItemRemovalCallback itemRemovalCallback);\n\n    /**\n     * Check if a block can be stacked.\n     *\n     * @param superiorPlayer The player that stacked the block.\n     * @param block          The block to stack into.\n     * @param itemStack      The item that is used to stack into the block.\n     * @return The result of stacking the block.\n     */\n    InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPlayer, Block block, ItemStack itemStack);\n\n    /**\n     * Handle a stacked block being broken.\n     *\n     * @param block          The block to unstack from.\n     * @param superiorPlayer The player that unstacked the block, if exists.\n     * @return The result of unstacking the block.\n     */\n    InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer);\n\n    /**\n     * Callback for removing items from the inventory when stacking blocks.\n     * Used in {@link #handleStackedBlockPlace(SuperiorPlayer, Block, int, OnItemRemovalCallback)}\n     */\n    interface OnItemRemovalCallback {\n\n        void accept(int amount);\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/RecordResult.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.world;\n\npublic enum RecordResult {\n\n    /**\n     * The action was not done inside an island.\n     */\n    NOT_IN_ISLAND,\n\n    /**\n     * The entity cannot be tracked.\n     */\n    ENTITY_CANNOT_BE_TRACKED,\n\n    /**\n     * The action was successfully recorded.\n     */\n    SUCCESS\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/WorldRecordFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.world;\n\nimport com.bgsoftware.common.annotations.IntType;\n\n/**\n * The integer value element annotated with {@link WorldRecordFlags} represents flags related to what to do\n * when block change is recorded. It is mainly used within the {@link WorldRecordService} interface and its methods.\n */\n@IntType({WorldRecordFlags.SAVE_BLOCK_COUNT, WorldRecordFlags.DIRTY_CHUNKS, WorldRecordFlags.HANDLE_NEARBY_BLOCKS})\npublic @interface WorldRecordFlags {\n\n    /**\n     * Save the new block count after the block change.\n     */\n    int SAVE_BLOCK_COUNT = 1 << 0;\n\n    /**\n     * Mark dirty chunks status for changes in chunks.\n     */\n    int DIRTY_CHUNKS = 1 << 1;\n\n    /**\n     * Check for nearby block changes.\n     * Only handled when breaking blocks to check for nearby block changes that\n     * were affected by the breaking of the block.\n     */\n    int HANDLE_NEARBY_BLOCKS = 1 << 2;\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/WorldRecordService.java",
    "content": "package com.bgsoftware.superiorskyblock.api.service.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\n\npublic interface WorldRecordService {\n\n    /**\n     * Record a block place.\n     *\n     * @param block         The block that was placed.\n     * @param blockCount    The amount of blocks that were placed.\n     * @param oldBlockState The state of the block before placing the new one.\n     * @param flags         See {@link WorldRecordFlags}\n     * @return The result of recording the block placement.\n     */\n    RecordResult recordBlockPlace(Block block, int blockCount, @Nullable BlockState oldBlockState,\n                                  @WorldRecordFlags int flags);\n\n    /**\n     * Record a block place.\n     *\n     * @param blockKey      The key of the block that was placed.\n     * @param blockLocation The location of the block.\n     * @param blockCount    The amount of blocks that were placed.\n     * @param oldBlockState The state of the block before placing the new one.\n     * @param flags         See {@link WorldRecordFlags}\n     * @return The result of recording the block placement.\n     */\n    RecordResult recordBlockPlace(Key blockKey, Location blockLocation, int blockCount,\n                                  @Nullable BlockState oldBlockState, @WorldRecordFlags int flags);\n\n    /**\n     * Record multiple block placements.\n     *\n     * @param blockCounts KeyMap containing the counts of the blocks that were placed.\n     * @param location    The location of where the blocks were placed at.\n     * @param flags       See {@link WorldRecordFlags}\n     * @return The result of recording the block placements.\n     */\n    RecordResult recordMultiBlocksPlace(KeyMap<Integer> blockCounts, Location location, @WorldRecordFlags int flags);\n\n    /**\n     * Record a block break.\n     *\n     * @param block The block that was broken\n     * @param flags See {@link WorldRecordFlags}\n     * @return The result of recording the block break.\n     */\n    RecordResult recordBlockBreak(Block block, @WorldRecordFlags int flags);\n\n    /**\n     * Record a block break.\n     *\n     * @param block      The block that was broken.\n     * @param blockCount The amount of blocks that were broken.\n     * @param flags      See {@link WorldRecordFlags}\n     * @return The result of recording the block break.\n     */\n    RecordResult recordBlockBreak(Block block, int blockCount, @WorldRecordFlags int flags);\n\n    /**\n     * Record a block break.\n     *\n     * @param blockKey      The key of the block that was broken.\n     * @param blockLocation The location of the block.\n     * @param blockCount    The amount of blocks that were broken.\n     * @param flags         See {@link WorldRecordFlags}\n     * @return The result of recording the block break.\n     */\n    RecordResult recordBlockBreak(Key blockKey, Location blockLocation, int blockCount, @WorldRecordFlags int flags);\n\n    /**\n     * Record multiple block breaks.\n     *\n     * @param blockCounts KeyMap containing the counts of the blocks that were broken.\n     * @param location    The location of where the blocks were broken at.\n     * @param flags       See {@link WorldRecordFlags}\n     * @return The result of recording the block breaks.\n     */\n    RecordResult recordMultiBlocksBreak(KeyMap<Integer> blockCounts, Location location, @WorldRecordFlags int flags);\n\n    /**\n     * Record an entity spawning into the world.\n     *\n     * @param entity The entity that spawned.\n     * @return The result of recording the entity spawn.\n     */\n    RecordResult recordEntitySpawn(Entity entity);\n\n    /**\n     * Record an entity spawning into the world.\n     *\n     * @param entityType The type of the entity that spawned.\n     * @param location   The location of where the entity was spawned.\n     * @return The result of recording the entity spawn.\n     */\n    RecordResult recordEntitySpawn(EntityType entityType, Location location);\n\n    /**\n     * Record an entity despawning from the world.\n     *\n     * @param entity The entity that despawned.\n     * @return The result of recording the entity despawn.\n     */\n    RecordResult recordEntityDespawn(Entity entity);\n\n    /**\n     * Record an entity despawning from the world.\n     *\n     * @param entityType The type of the entity that despawned.\n     * @param location   The location of where the entity was despawned.\n     * @return The result of recording the entity despawn.\n     */\n    RecordResult recordEntityDespawn(EntityType entityType, Location location);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/Upgrade.java",
    "content": "package com.bgsoftware.superiorskyblock.api.upgrades;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.List;\n\npublic interface Upgrade {\n\n    /**\n     * Get the name of the upgrade.\n     */\n    String getName();\n\n    /**\n     * Get the upgrade-level object from a level.\n     * If it doesn't exist, an update level with level 0 will be returned.\n     *\n     * @param level The level to get the object from.\n     */\n    UpgradeLevel getUpgradeLevel(int level);\n\n    /**\n     * Get the maximum level that exists for the upgrade.\n     */\n    int getMaxUpgradeLevel();\n\n    /**\n     * Get the slot the upgrade is in the upgrades menu.\n     */\n    @Deprecated\n    int getSlot();\n\n    /**\n     * Get the slots the upgrade is in the upgrades menu.\n     */\n    List<Integer> getSlots();\n\n    /**\n     * Check whether the upgrade is in the given slot in the upgrades menu.\n     *\n     * @param slot The slot to check.\n     */\n    boolean isSlot(int slot);\n\n    /**\n     * Set the slot the upgrade is in the upgrades menu.\n     *\n     * @param slot The slot to set the upgrade item in.\n     */\n    @Deprecated\n    void setSlot(int slot);\n\n    /**\n     * Set the slots the upgrade is in the upgrades menu.\n     *\n     * @param slots The slots to set the upgrade item in.\n     */\n    void setSlots(@Nullable List<Integer> slots);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java",
    "content": "package com.bgsoftware.superiorskyblock.api.upgrades;\n\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.World;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.util.List;\nimport java.util.Map;\n\npublic interface UpgradeLevel {\n\n    /**\n     * Get the level of the current upgrade-level.\n     */\n    int getLevel();\n\n    /**\n     * Get the price required to upgrade to the next level.\n     *\n     * @deprecated See getCost()\n     */\n    @Deprecated\n    double getPrice();\n\n    /**\n     * Get the price required to upgrade to the next level.\n     */\n    UpgradeCost getCost();\n\n    /**\n     * Get all commands that will be executed when upgrading to the next level.\n     */\n    List<String> getCommands();\n\n    /**\n     * Get the permission required to upgrade to this level.\n     */\n    String getPermission();\n\n    /**\n     * Check all the custom requirements of the upgrade.\n     *\n     * @param superiorPlayer The player to check the requirements on.\n     * @return The error message for the failed requirements.\n     * If all the requirements were passed, an empty string will be returned.\n     */\n    String checkRequirements(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Checks if this level has a custom crop growth multiplier.\n     */\n    boolean hasCropGrowth();\n\n    /**\n     * Get the crop growth multiplier of this level.\n     */\n    double getCropGrowth();\n\n    /**\n     * Checks if this level has a custom spawner rates multiplier.\n     */\n    boolean hasSpawnerRates();\n\n    /**\n     * Get the spawner rates multiplier of this level.\n     */\n    double getSpawnerRates();\n\n    /**\n     * Checks if this level has a custom mob drops multiplier.\n     */\n    boolean hasMobDrops();\n\n    /**\n     * Get the mob drops multiplier of this level.\n     */\n    double getMobDrops();\n\n    /**\n     * Get the limit of a block for this level.\n     *\n     * @param key The block to check.\n     */\n    int getBlockLimit(Key key);\n\n    /**\n     * Get the exact limit of a block for this level.\n     *\n     * @param key The block to check.\n     */\n    int getExactBlockLimit(Key key);\n\n    /**\n     * Get all the block limits for this level.\n     */\n    Map<Key, Integer> getBlockLimits();\n\n    /**\n     * Get the limit of an entity for this level.\n     *\n     * @param entityType The entity's type to check.\n     */\n    int getEntityLimit(EntityType entityType);\n\n    /**\n     * Get the limit of an entity for this level.\n     *\n     * @param key The key of the entity to check.\n     */\n    int getEntityLimit(Key key);\n\n    /**\n     * Get all the entity limits for this level.\n     */\n    Map<Key, Integer> getEntityLimitsAsKeys();\n\n    /**\n     * Checks if this level has a custom team limit.\n     */\n    boolean hasTeamLimit();\n\n    /**\n     * Get the team limit of this level.\n     */\n    int getTeamLimit();\n\n    /**\n     * Checks if this level has a custom warps limit.\n     */\n    boolean hasWarpsLimit();\n\n    /**\n     * Get the warps limit of this level.\n     */\n    int getWarpsLimit();\n\n    /**\n     * Checks if this level has a custom coop limit.\n     */\n    boolean hasCoopLimit();\n\n    /**\n     * Get the coop players limit of this level.\n     */\n    int getCoopLimit();\n\n    /**\n     * Checks if this level has a custom border size.\n     */\n    boolean hasBorderSize();\n\n    /**\n     * Get the border size of this level.\n     */\n    int getBorderSize();\n\n    /**\n     * Get the generator rate of a block for this level in a specific world.\n     *\n     * @param key       The block to check.\n     * @param dimension The world dimension.\n     */\n    int getGeneratorAmount(Key key, Dimension dimension);\n\n    /**\n     * Get all the generator rates for this level in a specific world.\n     *\n     * @param dimension The world dimension\n     */\n    Map<String, Integer> getGeneratorAmounts(Dimension dimension);\n\n    /**\n     * Get the potion effect for this level.\n     *\n     * @param potionEffectType The potion effect to check.\n     */\n    int getPotionEffect(PotionEffectType potionEffectType);\n\n    /**\n     * Get all the potion effects for this level.\n     */\n    Map<PotionEffectType, Integer> getPotionEffects();\n\n    /**\n     * Checks if this level has a custom bank limit.\n     */\n    boolean hasBankLimit();\n\n    /**\n     * Get the bank limit of this level.\n     */\n    BigDecimal getBankLimit();\n\n    /**\n     * Get a limit of a role for this level.\n     *\n     * @param playerRole The role to check.\n     */\n    int getRoleLimit(PlayerRole playerRole);\n\n    /**\n     * Get the role limits of this level.\n     */\n    Map<PlayerRole, Integer> getRoleLimits();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCost.java",
    "content": "package com.bgsoftware.superiorskyblock.api.upgrades.cost;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\npublic interface UpgradeCost {\n\n    /**\n     * Get the id of this upgrade cost.\n     */\n    String getId();\n\n    /**\n     * Get the cost value.\n     */\n    BigDecimal getCost();\n\n    /**\n     * Check whether or not the player has enough money in his bank.\n     *\n     * @param superiorPlayer The player to check.\n     */\n    boolean hasEnoughBalance(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Withdraw the cost value from the player.\n     *\n     * @param superiorPlayer The player to withdraw from.\n     */\n    void withdrawCost(SuperiorPlayer superiorPlayer);\n\n    /**\n     * Clone this cost with a new cost value.\n     *\n     * @param cost The new cost value\n     */\n    UpgradeCost clone(BigDecimal cost);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCostLoadException.java",
    "content": "package com.bgsoftware.superiorskyblock.api.upgrades.cost;\n\nimport org.bukkit.configuration.ConfigurationSection;\n\n/**\n * This exception is used inside {@link UpgradeCostLoader#loadCost(ConfigurationSection)}\n * when a faulty configuration is given for the loader.\n */\npublic class UpgradeCostLoadException extends Exception {\n\n    public UpgradeCostLoadException(String message) {\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCostLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.api.upgrades.cost;\n\nimport org.bukkit.configuration.ConfigurationSection;\n\npublic interface UpgradeCostLoader {\n\n    /**\n     * Load a cost from a configuration section.\n     *\n     * @param upgradeSection The section to load the cost from.\n     * @throws UpgradeCostLoadException when an issue occurred when loading the cost.\n     */\n    UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException;\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java",
    "content": "package com.bgsoftware.superiorskyblock.api.world;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.World;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class Dimension implements Enumerable {\n\n    private static final Map<String, Dimension> dimensions = new HashMap<>();\n    private static int ordinalCounter = 0;\n\n    private final String name;\n    private final World.Environment environment;\n    private final int ordinal;\n\n    private Dimension(String name, World.Environment environment) {\n        this.name = name.toUpperCase(Locale.ENGLISH);\n        this.environment = environment;\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    /**\n     * Get the environment of the world.\n     */\n    public World.Environment getEnvironment() {\n        return environment;\n    }\n\n    /**\n     * Get all the dimensions..\n     */\n    public static Collection<Dimension> values() {\n        return dimensions.values();\n    }\n\n    /**\n     * Get a dimension by its name.\n     *\n     * @param name The name to check.\n     */\n    public static Dimension getByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        Dimension dimension = dimensions.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkNotNull(dimension, \"Couldn't find a Dimension with the name \" + name + \".\");\n\n        return dimension;\n    }\n\n    /**\n     * Register a new dimension.\n     *\n     * @param name        The name for the dimension.\n     * @param environment The environment of the world this dimension refers to.\n     */\n    public static void register(String name, World.Environment environment) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        name = name.toUpperCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!dimensions.containsKey(name), \"Dimension with the name \" + name + \" already exists.\");\n\n        dimensions.put(name, new Dimension(name, environment));\n    }\n\n    /**\n     * Get the name of the dimension.\n     */\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public String toString() {\n        return \"Dimension{name=\" + name + \",environment=\" + environment + \"}\";\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/world/GameSound.java",
    "content": "package com.bgsoftware.superiorskyblock.api.world;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Sound;\n\npublic interface GameSound {\n\n    Sound getSound();\n\n    float getVolume();\n\n    float getPitch();\n\n    static GameSound of(Sound sound, float volume, float pitch) {\n        Preconditions.checkNotNull(sound, \"sound parameter cannot be null\");\n        return SuperiorSkyblockAPI.getFactory().createGameSound(sound, volume, pitch);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java",
    "content": "package com.bgsoftware.superiorskyblock.api.world;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.World;\n\npublic interface WorldInfo {\n\n    /**\n     * Get the name of this world.\n     */\n    String getName();\n\n    /**\n     * Get the environment of this world.\n     */\n    @Deprecated\n    World.Environment getEnvironment();\n\n    /**\n     * Get the environment of this world.\n     */\n    Dimension getDimension();\n\n    /**\n     * Create a new world info.\n     *\n     * @param world The world.\n     */\n    static WorldInfo of(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null\");\n        Dimension dimension = SuperiorSkyblockAPI.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n        if (dimension == null)\n            dimension = Dimension.getByName(world.getEnvironment().name());\n\n        return of(world.getName(), dimension);\n    }\n\n    /**\n     * Create a new world info.\n     *\n     * @param worldName The name of the world.\n     * @param dimension The dimension of the world.\n     */\n    static WorldInfo of(String worldName, Dimension dimension) {\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n        return SuperiorSkyblockAPI.getFactory().createWorldInfo(worldName, dimension);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.world.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\n\npublic class DelegateIslandCreationAlgorithm implements IslandCreationAlgorithm {\n\n    protected final IslandCreationAlgorithm handle;\n\n    protected DelegateIslandCreationAlgorithm(IslandCreationAlgorithm handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    @Deprecated\n    public CompletableFuture<IslandCreationResult> createIsland(UUID islandUUID, SuperiorPlayer owner,\n                                                                BlockPosition lastIsland, String islandName,\n                                                                Schematic schematic) {\n        return this.handle.createIsland(islandUUID, owner, lastIsland, islandName, schematic);\n    }\n\n    @Override\n    public CompletableFuture<IslandCreationResult> createIsland(Island.Builder builder, BlockPosition lastIsland) {\n        return this.handle.createIsland(builder, lastIsland);\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/IslandCreationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.api.world.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\n\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface IslandCreationAlgorithm {\n\n    /**\n     * Create a new island on the server.\n     * This method should not only create the Island object itself, but also paste a schematic.\n     * Teleportation and island initialization will be handled by the plugin.\n     *\n     * @param islandUUID The uuid of the island.\n     * @param owner      The owner of the island.\n     * @param lastIsland The location of the last generated island.\n     * @param islandName The name of the island.\n     * @param schematic  The schematic used to create the island.\n     */\n    CompletableFuture<IslandCreationResult> createIsland(UUID islandUUID, SuperiorPlayer owner, BlockPosition lastIsland,\n                                                         String islandName, Schematic schematic);\n\n    /**\n     * Create a new island on the server.\n     * This method should not only create the Island object itself, but also paste a schematic.\n     * Teleportation and island initialization will be handled by the plugin.\n     *\n     * @param builder    The builder of the island.\n     * @param lastIsland The location of the last generated island.\n     */\n    CompletableFuture<IslandCreationResult> createIsland(Island.Builder builder, BlockPosition lastIsland);\n\n    /**\n     * Class representing result of a creation process.\n     */\n    class IslandCreationResult {\n\n        private final Status status;\n        private final Island island;\n        private final Location islandLocation;\n        private final boolean shouldTeleportPlayer;\n\n        /**\n         * Constructor of the result.\n         *\n         * @param island               The created island.\n         * @param islandLocation       The location of the island.\n         * @param shouldTeleportPlayer Whether to teleport the player to his island or not.\n         * @deprecated See {@link #IslandCreationResult(Status, Island, Location, boolean)}\n         */\n        @Deprecated\n        public IslandCreationResult(Island island, Location islandLocation, boolean shouldTeleportPlayer) {\n            this(Status.SUCCESS, island, islandLocation, shouldTeleportPlayer);\n        }\n\n        /**\n         * Constructor of the result.\n         *\n         * @param status               The status of the creation result.\n         *                             In case of failure, the rest of the parameters are undefined.\n         * @param island               The created island.\n         * @param islandLocation       The location of the island.\n         * @param shouldTeleportPlayer Whether to teleport the player to his island or not.\n         */\n        public IslandCreationResult(Status status, Island island, Location islandLocation, boolean shouldTeleportPlayer) {\n            this.status = status;\n            this.island = island;\n            this.islandLocation = islandLocation;\n            this.shouldTeleportPlayer = shouldTeleportPlayer;\n        }\n\n        /**\n         * Get the status of the creation task.\n         */\n        public Status getStatus() {\n            return status;\n        }\n\n        /**\n         * Get the created island object.\n         */\n        public Island getIsland() {\n            Preconditions.checkState(this.getStatus() == Status.SUCCESS, \"Result is not successful.\");\n            return island;\n        }\n\n        /**\n         * Get the location of the new island.\n         */\n        public Location getIslandLocation() {\n            Preconditions.checkState(this.getStatus() == Status.SUCCESS, \"Result is not successful.\");\n            return islandLocation;\n        }\n\n        /**\n         * Get whether the player that created the island should be teleported to it.\n         */\n        public boolean shouldTeleportPlayer() {\n            Preconditions.checkState(this.getStatus() == Status.SUCCESS, \"Result is not successful.\");\n            return shouldTeleportPlayer;\n        }\n\n        public enum Status {\n\n            NAME_OCCUPIED,\n            EVENT_CANCELLED,\n            SUCCESS\n\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockOffset.java",
    "content": "package com.bgsoftware.superiorskyblock.api.wrappers;\n\nimport org.bukkit.Location;\n\n/**\n * This object represents an offset from a block.\n * You can create a new instance of this class by using {@link com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager}\n */\npublic interface BlockOffset {\n\n    /**\n     * Get the x-coords offset.\n     */\n    int getOffsetX();\n\n    /**\n     * Get the y-coords offset.\n     */\n    int getOffsetY();\n\n    /**\n     * Get the z-coords offset.\n     */\n    int getOffsetZ();\n\n    /**\n     * Get a copy of this offset with negated offsets, which this.equals(this.negate().negate()) is true.\n     */\n    BlockOffset negate();\n\n    /**\n     * Apply this block-offset to a location.\n     *\n     * @param location The location to apply the offset to.\n     * @return A new copy of the location with the offset applied to it.\n     */\n    Location applyToLocation(Location location);\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.api.wrappers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\n/**\n * This object represents a position of a block in the world.\n * You can create a new instance of this class by using {@link FactoriesManager}\n */\npublic interface BlockPosition {\n\n    /**\n     * Get the x value of the position.\n     */\n    int getX();\n\n    /**\n     * Get the y value of the position.\n     */\n    int getY();\n\n    /**\n     * Get the z value of the position.\n     */\n    int getZ();\n\n    /**\n     * Get a new position by an offset from this position.\n     *\n     * @param x The x-axis offset.\n     * @param y The y-axis offset.\n     * @param z The z-axis offset.\n     */\n    BlockPosition offset(int x, int y, int z);\n\n    /**\n     * Get the bukkit representation of this block position in the provided world.\n     *\n     * @param world The world for this block position.\n     */\n    Location toLocation(@Nullable World world);\n\n    /**\n     * Get the bukkit representation of this block position in the provided world.\n     *\n     * @param world    The world for this block position.\n     * @param location The location to write the output to. If null, null will be returned as well.\n     */\n    @Nullable\n    Location toLocation(@Nullable World world, @Nullable Location location);\n\n    /**\n     * Get the bukkit representation of this block position in the provided world.\n     * If the world is unloaded, the location's getWorld will return null.\n     *\n     * @param worldInfo The world information for this world position.\n     */\n    Location toLocation(WorldInfo worldInfo);\n\n    /**\n     * Get the bukkit representation of this block position in the provided world.\n     * If the world is unloaded, the location's getWorld will return null.\n     *\n     * @param worldInfo The world information for this world position.\n     * @param location  The location to write the output to. If null, null will be returned as well.\n     */\n    @Nullable\n    Location toLocation(WorldInfo worldInfo, @Nullable Location location);\n\n    /**\n     * Get the world position representation of this block position.\n     */\n    WorldPosition toWorldPosition();\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java",
    "content": "package com.bgsoftware.superiorskyblock.api.wrappers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.HitActionResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\npublic interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, IDatabaseBridgeHolder {\n\n    /*\n     *   General Methods\n     */\n\n    /**\n     * Get the UUID of the player.\n     */\n    UUID getUniqueId();\n\n    /**\n     * Get the last known name of the player.\n     */\n    String getName();\n\n    /**\n     * Get the player cache.\n     */\n    PlayerCache getCache();\n\n    /**\n     * Get the last known skin-texture value of the player.\n     */\n    String getTextureValue();\n\n    /**\n     * Set the skin-texture value for the player.\n     *\n     * @param textureValue The skin texture.\n     */\n    void setTextureValue(String textureValue);\n\n    /**\n     * Update the last time player joined or left the server.\n     */\n    void updateLastTimeStatus();\n\n    /**\n     * Set the last time player joined or left the server.\n     *\n     * @param lastTimeStatus The time to set.\n     */\n    void setLastTimeStatus(long lastTimeStatus);\n\n    /**\n     * Get the last time player joined or left the server.\n     */\n    long getLastTimeStatus();\n\n    /**\n     * Update the cached name with the current player's name.\n     * When the player is offline, nothing will happen.\n     */\n    void updateName();\n\n    /**\n     * Set the cached name with the given name.\n     * When the player will join the server, it will be synced again with his correct name.\n     */\n    void setName(String name);\n\n    /**\n     * Get the player object.\n     */\n    @Nullable\n    Player asPlayer();\n\n    /**\n     * Get the offline-player object.\n     * This can return null if the player is invalid, for example - npcs.\n     */\n    @Nullable\n    OfflinePlayer asOfflinePlayer();\n\n    /**\n     * Check whether or not the player is online.\n     */\n    boolean isOnline();\n\n    /**\n     * Execute code only if the player is online.\n     */\n    void runIfOnline(Consumer<Player> toRun);\n\n    /**\n     * Check whether or not this player is in a gamemode with fly mode enabled.\n     * When the player is offline, false will be returned.\n     */\n    boolean hasFlyGamemode();\n\n    /**\n     * Get the opened view for the player.\n     * When the player is offline or no view is opened, null will be returned.\n     */\n    @Nullable\n    MenuView<?, ?> getOpenedView();\n\n    /**\n     * Check whether or not the player is AFK.\n     * When the player is offline, false will be returned.\n     */\n    boolean isAFK();\n\n    /**\n     * Check whether or not the player is vanished.\n     * When the player is offline, false will be returned.\n     */\n    boolean isVanished();\n\n    /**\n     * Checks whether the player is shown as online.\n     *\n     * @return false if vanished, in spectator mode or offline.\n     */\n    boolean isShownAsOnline();\n\n    /**\n     * Check whether the player has a permission.\n     *\n     * @param permission The permission to check.\n     * @return When the player is offline, false will be returned.\n     */\n    boolean hasPermission(String permission);\n\n    /**\n     * Check whether the player has a permission without having op.\n     *\n     * @param permission The permission to check.\n     * @return When the player is offline, false may be returned.\n     */\n    boolean hasPermissionWithoutOP(String permission);\n\n    /**\n     * Check whether the player has a permission on his island.\n     *\n     * @param permission The {@link IslandPrivilege} to check.\n     * @return Whether the player has the permission on his island.\n     * When the player doesn't have an island, false will be returned.\n     */\n    boolean hasPermission(IslandPrivilege permission);\n\n    /**\n     * Check whether the player has the bypass permission for the provided {@link IslandPrivilege}.\n     *\n     * @param permission The {@link IslandPrivilege} to check.\n     * @return Whether the player has the bypass permission. If the player is offline, false may be returned.\n     */\n    boolean hasBypassPermission(IslandPrivilege permission);\n\n    /**\n     * Check whether or not this player can hit another player.\n     * <p>\n     * Players cannot hit each other if one of the followings is true:\n     * 1) They are inside an island that has pvp disabled.\n     * 2) One of them has pvp warm-up.\n     * 3) They are both in the same island, and they hit each other outside of a pvp world.\n     * 4) One of the players isn't online (duh?)\n     * 5) The target player is inside an island as a visitor and can't take damage.\n     * 6) The target player is inside an island as a coop and can't take damage.\n     *\n     * @param otherPlayer The other player to check.\n     */\n    HitActionResult canHit(SuperiorPlayer otherPlayer);\n\n    /*\n     *   Location Methods\n     */\n\n    /**\n     * Get the world that the player is inside.\n     * When the player is offline, null will be returned.\n     */\n    @Nullable\n    World getWorld();\n\n    /**\n     * Get the location of the player.\n     * When the player is offline, null will be returned.\n     */\n    @Nullable\n    Location getLocation();\n\n    /**\n     * Get the location of the player.\n     * When the player is offline, {@param location} will be returned.\n     *\n     * @param location Location object to re-use.\n     */\n    @Nullable\n    Location getLocation(@Nullable Location location);\n\n    /**\n     * Teleport the player to a location.\n     *\n     * @param location The location to teleport the player to.\n     */\n    void teleport(Location location);\n\n    /**\n     * Teleport the player to a location.\n     *\n     * @param location       The location to teleport the player to.\n     * @param teleportResult The result of the teleportation process.\n     */\n    void teleport(Location location, @Nullable Consumer<Boolean> teleportResult);\n\n    /**\n     * Teleport the player to an island.\n     *\n     * @param island The island to teleport the player to.\n     */\n    void teleport(Island island);\n\n    /**\n     * Teleport the player to an island.\n     *\n     * @param island    The island to teleport the player to.\n     * @param dimension The dimension to teleport the player to.\n     */\n    void teleport(Island island, Dimension dimension);\n\n    /**\n     * Teleport the player to an island.\n     *\n     * @param island         The island to teleport the player to.\n     * @param teleportResult Consumer that will be ran when task is finished.\n     */\n    void teleport(Island island, @Nullable Consumer<Boolean> teleportResult);\n\n    /**\n     * Teleport the player to an island.\n     *\n     * @param island         The island to teleport the player to.\n     * @param dimension      The dimension to teleport the player to.\n     * @param teleportResult Consumer that will be ran when task is finished.\n     */\n    void teleport(Island island, Dimension dimension, @Nullable Consumer<Boolean> teleportResult);\n\n    /**\n     * Check whether or not the player is inside their island.\n     * When the player is offline or he doesn't have an island, false will be returned.\n     */\n    boolean isInsideIsland();\n\n    /*\n     *   Island Methods\n     */\n\n    /**\n     * Get the island owner of the player's island.\n     */\n    SuperiorPlayer getIslandLeader();\n\n    /**\n     * Set the island owner of the player's island.\n     * !Can cause issues if not used properly!\n     *\n     * @param islandLeader The island owner's player.\n     * @deprecated see {@link #setIsland(Island)}\n     */\n    @Deprecated\n    void setIslandLeader(SuperiorPlayer islandLeader);\n\n    /**\n     * Get the island of the player.\n     */\n    @Nullable\n    Island getIsland();\n\n    /**\n     * Set the island of the player.\n     * !Can cause issues if not used properly!\n     *\n     * @param island The island to set the player to.\n     * @throws IllegalArgumentException if island doesn't contain player as a member.\n     */\n    void setIsland(Island island);\n\n    /**\n     * Check if this player is a member of an island.\n     */\n    boolean hasIsland();\n\n    /**\n     * Add an invitation to an island for the player.\n     * Do not call use this method directly unless you know what you're doing.\n     * Instead, use {@link Island#inviteMember(SuperiorPlayer)}\n     *\n     * @param island The island that invited the player.\n     */\n    void addInvite(Island island);\n\n    /**\n     * Remove an invitation from an island for the player.\n     * Do not call use this method directly unless you know what you're doing.\n     * Instead, use {@link Island#revokeInvite(SuperiorPlayer)} (SuperiorPlayer)}\n     *\n     * @param island The island to remove the invitation from.\n     */\n    void removeInvite(Island island);\n\n    /**\n     * Get all pending invites of the player.\n     *\n     * @return Pending invites, in the same order they were sent.\n     */\n    List<Island> getInvites();\n\n    /**\n     * Mark player as a coop of an island.\n     * !Can cause issues if not used properly!\n     *\n     * @param island The island to mark the player as coop.\n     * @throws IllegalArgumentException if island doesn't contain player as a coop.\n     */\n    void addCoop(Island island);\n\n    /**\n     * Remove mark of the player as a coop of an island.\n     * !Can cause issues if not used properly!\n     *\n     * @param island The island to remove the mark of the player as coop.\n     */\n    void removeCoop(Island island);\n\n    /**\n     * Get all islands that the player is coop of.\n     */\n    List<Island> getCoopIslands();\n\n    /**\n     * Get the role of the player.\n     */\n    PlayerRole getPlayerRole();\n\n    /**\n     * Set the role of the player.\n     *\n     * @param playerRole The role to give the player.\n     */\n    void setPlayerRole(PlayerRole playerRole);\n\n    /**\n     * Get the amount of left disbands.\n     */\n    int getDisbands();\n\n    /**\n     * Check whether or not the player has a permission.\n     */\n    void setDisbands(int disbands);\n\n    /**\n     * Check whether or not the player has more disbands.\n     */\n    boolean hasDisbands();\n\n    /*\n     *   Preferences Methods\n     */\n\n    /**\n     * Get the locale of the player.\n     */\n    Locale getUserLocale();\n\n    /**\n     * Set the locale of the player.\n     *\n     * @param locale The locale to set.\n     */\n    void setUserLocale(Locale locale);\n\n    /**\n     * Check whether the world border is enabled for the player.\n     */\n    boolean hasWorldBorderEnabled();\n\n    /**\n     * Toggle the world border for the player.\n     */\n    void toggleWorldBorder();\n\n    /**\n     * Set whether the world border is enabled for the player.\n     *\n     * @param enabled true to enable borders.\n     */\n    void setWorldBorderEnabled(boolean enabled);\n\n    /**\n     * Update world border for this player.\n     *\n     * @param island The island the player should see the border of.\n     */\n    void updateWorldBorder(@Nullable Island island);\n\n    /**\n     * Check whether the blocks-stacker mode is enabled for the player.\n     */\n    boolean hasBlocksStackerEnabled();\n\n    /**\n     * Toggle the blocks-stacker for the player.\n     */\n    void toggleBlocksStacker();\n\n    /**\n     * Set whether the blocks-stacker mode is enabled for the player.\n     *\n     * @param enabled true to enable blocks-stacker mode.\n     */\n    void setBlocksStacker(boolean enabled);\n\n    /**\n     * Check whether the schematic mode is enabled for the player.\n     */\n    boolean hasSchematicModeEnabled();\n\n    /**\n     * Toggle the schematic mode for the player.\n     */\n    void toggleSchematicMode();\n\n    /**\n     * Set whether the schematic mode is enabled for the player.\n     *\n     * @param enabled true to enable schematic mode.\n     */\n    void setSchematicMode(boolean enabled);\n\n    /**\n     * Check whether the team chat is enabled for the player.\n     */\n    boolean hasTeamChatEnabled();\n\n    /**\n     * Toggle the team chat for the player.\n     */\n    void toggleTeamChat();\n\n    /**\n     * Set whether the schematic mode is enabled for the player.\n     *\n     * @param enabled true to enable schematic mode.\n     */\n    void setTeamChat(boolean enabled);\n\n    /**\n     * Check whether the bypass mode is enabled for the player.\n     */\n    boolean hasBypassModeEnabled();\n\n    /**\n     * Toggle the bypass mode for the player.\n     */\n    void toggleBypassMode();\n\n    /**\n     * Set whether the bypass mode is enabled for the player.\n     *\n     * @param enabled true to enable bypass mode.\n     */\n    void setBypassMode(boolean enabled);\n\n    /**\n     * Check whether or not the player has their panel toggled.\n     */\n    boolean hasToggledPanel();\n\n    /**\n     * Set whether or not the player has their panel toggled.\n     */\n    void setToggledPanel(boolean toggledPanel);\n\n    /**\n     * Set whether the player has flying enabled.\n     */\n    boolean hasIslandFlyEnabled();\n\n    /**\n     * Toggle flying mode.\n     */\n    void toggleIslandFly();\n\n    /**\n     * Set whether the player has flying enabled.\n     *\n     * @param enabled true to enable flying.\n     */\n    void setIslandFly(boolean enabled);\n\n    /**\n     * Check whether the player has admin spy mode enabled.\n     */\n    boolean hasAdminSpyEnabled();\n\n    /**\n     * Toggle admin spy mode.\n     */\n    void toggleAdminSpy();\n\n    /**\n     * Set whether the player has admin spy mode enabled.\n     *\n     * @param enabled true to enable admin spy mode.\n     */\n    void setAdminSpy(boolean enabled);\n\n    /**\n     * Get the border color of the player.\n     */\n    BorderColor getBorderColor();\n\n    /**\n     * Set the border color for the player.\n     *\n     * @param borderColor The color to set.\n     */\n    void setBorderColor(BorderColor borderColor);\n\n    /*\n     *   Schematics Methods\n     */\n\n    /**\n     * Get the first schematic position of the player. May be null.\n     */\n    BlockPosition getSchematicPos1();\n\n    /**\n     * Set the first schematic position of the player.\n     *\n     * @param block The block to change the position to.\n     */\n    void setSchematicPos1(@Nullable Block block);\n\n    /**\n     * Get the second schematic position of the player. May be null.\n     */\n    BlockPosition getSchematicPos2();\n\n    /**\n     * Set the second schematic position of the player.\n     *\n     * @param block The block to change the position to.\n     */\n    void setSchematicPos2(@Nullable Block block);\n\n    /*\n     *   Data Methods\n     */\n\n    /**\n     * Whether the player is immuned to PvP or not.\n     */\n    @Deprecated\n    boolean isImmunedToPvP();\n\n    /**\n     * Set immunity to PvP for this player.\n     *\n     * @param immunedToPvP Whether or not the player should be immuned to PvP.\n     */\n    @Deprecated\n    void setImmunedToPvP(boolean immunedToPvP);\n\n    /**\n     * Whether the player has just left an island's area or not.\n     */\n    @Deprecated\n    boolean isLeavingFlag();\n\n    /**\n     * Set whether or not the player has just left an island's area.\n     * If set to true, the player will not be able to escape islands.\n     *\n     * @param leavingFlag Whether or not the island has left an island's area.\n     */\n    @Deprecated\n    void setLeavingFlag(boolean leavingFlag);\n\n    /**\n     * Whether the player is immuned to portals or not.\n     */\n    @Deprecated\n    boolean isImmunedToPortals();\n\n    /**\n     * Set whether or not the player is immuned to portals.\n     * If set to true, players will not be able to get teleported through portals.\n     *\n     * @param immuneToPortals Whether the player should be immuned or not.\n     */\n    @Deprecated\n    void setImmunedToPortals(boolean immuneToPortals);\n\n    /**\n     * Get the current active teleport task of the player.\n     */\n    @Nullable\n    BukkitTask getTeleportTask();\n\n    /**\n     * Set a teleportation task for the player.\n     * This is used for warmpups, etc.\n     *\n     * @param teleportTask The teleport task to set.\n     */\n    void setTeleportTask(@Nullable BukkitTask teleportTask);\n\n    /**\n     * Get the status of the player.\n     *\n     * @deprecated See {@link #hasPlayerStatus(PlayerStatus)}\n     */\n    @Deprecated\n    PlayerStatus getPlayerStatus();\n\n    /**\n     * Set the status of the player.\n     *\n     * @param playerStatus The new status of the player.\n     */\n    void setPlayerStatus(PlayerStatus playerStatus);\n\n    /**\n     * Remove a status of the player.\n     *\n     * @param playerStatus The status to remove.\n     */\n    void removePlayerStatus(PlayerStatus playerStatus);\n\n    /**\n     * Check if player is in status.\n     *\n     * @param playerStatus The status to check.\n     */\n    boolean hasPlayerStatus(PlayerStatus playerStatus);\n\n    /**\n     * Merge another player into this object.\n     */\n    void merge(SuperiorPlayer otherPlayer);\n\n    /**\n     * Create a new builder for a {@link SuperiorPlayer} object.\n     */\n    static Builder newBuilder() {\n        return SuperiorSkyblockAPI.getFactory().createPlayerBuilder();\n    }\n\n    /**\n     * The {@link Builder} interface is used to create {@link SuperiorPlayer} objects with predefined values.\n     * All of its methods are setters for all the values possible to create a player with.\n     * Use {@link Builder#build()} to create the new {@link SuperiorPlayer} object. You must set\n     * {@link Builder#setUniqueId(UUID)} before creating a new {@link SuperiorPlayer}\n     */\n    interface Builder {\n\n        Builder setUniqueId(UUID uuid);\n\n        UUID getUniqueId();\n\n        Builder setName(String name);\n\n        String getName();\n\n        Builder setPlayerRole(PlayerRole playerRole);\n\n        PlayerRole getPlayerRole();\n\n        Builder setDisbands(int disbands);\n\n        int getDisbands();\n\n        Builder setLocale(Locale locale);\n\n        Locale getLocale();\n\n        Builder setTextureValue(String textureValue);\n\n        String getTextureValue();\n\n        Builder setLastTimeUpdated(long lastTimeUpdated);\n\n        long getLastTimeUpdated();\n\n        Builder setToggledPanel(boolean toggledPanel);\n\n        boolean hasToggledPanel();\n\n        Builder setIslandFly(boolean islandFly);\n\n        boolean hasIslandFly();\n\n        Builder setBorderColor(BorderColor borderColor);\n\n        BorderColor getBorderColor();\n\n        Builder setWorldBorderEnabled(boolean worldBorderEnabled);\n\n        boolean hasWorldBorderEnabled();\n\n        Builder setCompletedMission(Mission<?> mission, int finishCount);\n\n        Map<Mission<?>, Integer> getCompletedMissions();\n\n        Builder setPersistentData(byte[] persistentData);\n\n        byte[] getPersistentData();\n\n        SuperiorPlayer build();\n\n    }\n\n}\n"
  },
  {
    "path": "API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.api.wrappers;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\n/**\n * This object represents a position of an entity in the world.\n * You can create a new instance of this class by using {@link FactoriesManager}\n */\npublic interface WorldPosition {\n\n    /**\n     * Get the x value of the position.\n     */\n    double getX();\n\n    /**\n     * Get the y value of the position.\n     */\n    double getY();\n\n    /**\n     * Get the z value of the position.\n     */\n    double getZ();\n\n    /**\n     * Get the yaw value of the position.\n     */\n    float getYaw();\n\n    /**\n     * Get the pitch value of the position.\n     */\n    float getPitch();\n\n    /**\n     * Get a new position by an offset from this position.\n     *\n     * @param x The x-axis offset.\n     * @param y The y-axis offset.\n     * @param z The z-axis offset.\n     */\n    WorldPosition offset(double x, double y, double z);\n\n    /**\n     * Get a new position by rotating this position.\n     *\n     * @param yaw   The y-axis rotation.\n     * @param pitch The z-axis rotation.\n     */\n    WorldPosition rotate(float yaw, float pitch);\n\n    /**\n     * Get a new position by an offset from this position.\n     *\n     * @param x     The x-axis offset.\n     * @param y     The y-axis offset.\n     * @param z     The z-axis offset.\n     * @param yaw   The y-axis rotation.\n     * @param pitch The z-axis rotation.\n     */\n    WorldPosition offset(double x, double y, double z, float yaw, float pitch);\n\n    /**\n     * Get the bukkit representation of this world position in the provided world.\n     *\n     * @param world The world for this world position.\n     */\n    Location toLocation(@Nullable World world);\n\n    /**\n     * Get the bukkit representation of this world position in the provided world.\n     *\n     * @param world    The world for this world position.\n     * @param location The location to write the output to. If null, null will be returned as well.\n     */\n    @Nullable\n    Location toLocation(@Nullable World world, @Nullable Location location);\n\n    /**\n     * Get the bukkit representation of this world position in the provided world info.\n     * If the world is unloaded, the location's getWorld will return null.\n     *\n     * @param worldInfo The world information for this world position.\n     */\n    Location toLocation(WorldInfo worldInfo);\n\n    /**\n     * Get the bukkit representation of this world position in the provided world info.\n     * If the world is unloaded, the location's getWorld will return null.\n     *\n     * @param worldInfo The world information for this world position.\n     * @param location  The location to write the output to. If null, null will be returned as well.\n     */\n    @Nullable\n    Location toLocation(WorldInfo worldInfo, @Nullable Location location);\n\n    /**\n     * Get the block position representation of this world position.\n     */\n    BlockPosition toBlockPosition();\n\n}\n"
  },
  {
    "path": "Hooks/AdvancedSlimePaper/build.gradle",
    "content": "group 'AdvancedSlimePaper'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ndependencies {\n    compileOnly 'com.infernalsuite:AdvancedSlimePaper:1.19.4-R0.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_slimeworldmanager') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_slimeworldmanager\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.infernalsuite.aswm.api.SlimePlugin;\nimport com.infernalsuite.aswm.api.loaders.SlimeLoader;\nimport org.bukkit.Bukkit;\nimport org.bukkit.plugin.Plugin;\n\n@SuppressWarnings(\"unused\")\npublic class AdvancedSlimePaperHook {\n\n    private static final String[] LOADERS = new String[]{\"api\", \"mysql\", \"mongodb\", \"file\"};\n\n    private static Plugin slimeWorldPlugin = null;\n\n    public static boolean isCompatible() {\n        try {\n            Class.forName(\"com.infernalsuite.aswm.api.loaders.SlimeLoader\");\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n\n        // We don't support API v3\n\n        try {\n            Class.forName(\"com.infernalsuite.aswm.api.AdvancedSlimePaperAPI\");\n            return false;\n        } catch (ClassNotFoundException error) {\n            return true;\n        }\n    }\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        slimeWorldPlugin = Bukkit.getPluginManager().getPlugin(\"SlimeWorldManager\");\n        plugin.getProviders().registerWorldsListener(AdvancedSlimePaperHook::loadWorld);\n    }\n\n    private static void loadWorld(String worldName) {\n        SlimePlugin slimePlugin = (SlimePlugin) slimeWorldPlugin;\n\n        for (String loaderName : LOADERS) {\n            try {\n                SlimeLoader slimeLoader = slimePlugin.getLoader(loaderName);\n                if (slimeLoader != null && slimeLoader.worldExists(worldName)) {\n                    slimeLoader.loadWorld(worldName);\n                    break;\n                }\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/AdvancedSpawners/build.gradle",
    "content": "group 'Hooks:AdvancedSpawners'\n\ndependencies {\n    compileOnly 'gcspawners:AdvancedSpawners:2.2.14'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_advancedspawners') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_advancedspawners\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport gcspawners.ASAPI;\nimport gcspawners.AdvancedSpawnerPlaceEvent;\nimport gcspawners.AdvancedSpawnersBreakEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class SpawnersProvider_AdvancedSpawners implements SpawnersProvider_AutoDetect {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_AdvancedSpawners(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new SpawnersProvider_AdvancedSpawners.StackerListener(), plugin);\n        Log.info(\"Using AdvancedSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return !Bukkit.isPrimaryThread() ? new Pair<>(-1, null) :\n                new Pair<>(ASAPI.getSpawnerAmount(location), ASAPI.getSpawnerType(location).toUpperCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return ASAPI.getSpawnerType(itemStack).toUpperCase(Locale.ENGLISH);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerStack(AdvancedSpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null) {\n                island.handleBlockPlace(Keys.ofSpawner(e.getEntityType()), e.getCountPlaced());\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(AdvancedSpawnersBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null)\n                island.handleBlockBreak(Keys.ofSpawner(e.getEntityType()), e.getCountBroken());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/CMI/build.gradle",
    "content": "group 'Hooks:CMI'\n\ndependencies {\n    compileOnly 'com.Zrips:CMI:8.5.1.4'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_cmi') && !Boolean.valueOf(project.findProperty(\"hook.compile_cmi\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/afk/AFKProvider_CMI.java",
    "content": "package com.bgsoftware.superiorskyblock.external.afk;\n\nimport com.Zrips.CMI.CMI;\nimport com.bgsoftware.superiorskyblock.api.hooks.AFKProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.entity.Player;\n\npublic class AFKProvider_CMI implements AFKProvider {\n\n    public AFKProvider_CMI() {\n        Log.info(\"Hooked into CMI for support of afk status of players.\");\n    }\n\n    @Override\n    public boolean isAFK(Player player) {\n        Preconditions.checkNotNull(player, \"player parameter cannot be null.\");\n        return CMI.getInstance().getPlayerManager().getUser(player).isAfk();\n    }\n\n}\n"
  },
  {
    "path": "Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java",
    "content": "package com.bgsoftware.superiorskyblock.external.vanish;\n\nimport com.Zrips.CMI.CMI;\nimport com.Zrips.CMI.events.CMIPlayerUnVanishEvent;\nimport com.Zrips.CMI.events.CMIPlayerVanishEvent;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class VanishProvider_CMI implements VanishProvider, Listener {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public VanishProvider_CMI(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(this, plugin);\n        Log.info(\"Hooked into CMI for support of vanish status of players.\");\n    }\n\n    @Override\n    public boolean isVanished(Player player) {\n        return CMI.getInstance().getVanishManager().getAllVanished().contains(player.getUniqueId());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerVanish(CMIPlayerVanishEvent e) {\n        IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getPlayer()));\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerUnvanish(CMIPlayerUnVanishEvent e) {\n        IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getPlayer()));\n    }\n\n}\n"
  },
  {
    "path": "Hooks/CandcSilkSpawners/build.gradle",
    "content": "group 'Hooks:CandcSilkSpawners'\n\ndependencies {\n    compileOnly 'de.candc:SilkSpawners:1.6'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_candcsilkspawners') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_candcsilkspawners\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport de.candc.events.SpawnerBreakEvent;\nimport de.candc.events.SpawnerPlaceEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\npublic class SpawnersProvider_CandcSilkSpawners implements SpawnersProvider_AutoDetect {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_CandcSilkSpawners(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using SilkSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return new Pair<>(1, null);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return itemStack.getItemMeta().getLore().get(0).replaceAll(\"§e\", \"\");\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerPlace(SpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null)\n                island.handleBlockPlace(Keys.ofSpawner(e.getSpawnedEntity()), 1);\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null)\n                island.handleBlockBreak(Keys.ofSpawner(e.getSpawnedEntity()), 1);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/ChangeSkin/build.gradle",
    "content": "group 'Hooks:ChangeSkin'\n\ndependencies {\n    compileOnly 'com.github.games647:ChangeSkin:3.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_changeskin') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_changeskin\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/ChangeSkin/src/main/java/com/bgsoftware/superiorskyblock/external/ChangeSkinHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.Listener;\n\npublic class ChangeSkinHook implements Listener {\n\n    public static boolean isCompatible() {\n        try {\n            Class.forName(\"com.github.games647.changeskin.bukkit.events.PlayerChangeSkinEvent\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }\n\n    private ChangeSkinHook() {\n    }\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        Bukkit.getPluginManager().registerEvents(new PlayerChangeSkinListener(plugin), plugin);\n    }\n\n    private static class PlayerChangeSkinListener implements Listener {\n\n        private final SuperiorSkyblockPlugin plugin;\n\n        PlayerChangeSkinListener(SuperiorSkyblockPlugin plugin) {\n            this.plugin = plugin;\n        }\n\n        @EventHandler\n        public void onPlayerChangeSkin(com.github.games647.changeskin.bukkit.events.PlayerChangeSkinEvent e) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n            superiorPlayer.setTextureValue(e.getSkinModel().getEncodedValue());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/CoreProtect/build.gradle",
    "content": "group 'Hooks:CoreProtect'\n\ndependencies {\n    compileOnly 'net.coreprotect:CoreProtect:19.0'\n    compileOnly \"org.spigotmc:v1_16_R3:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_coreprotect') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_coreprotect\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport net.coreprotect.CoreProtect;\nimport net.coreprotect.CoreProtectAPI;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.block.Block;\nimport org.bukkit.plugin.Plugin;\n\n@SuppressWarnings({\"deprecation\", \"unused\"})\npublic class CoreProtectHook {\n\n    private static SuperiorSkyblockPlugin plugin;\n    private static Plugin coreProtect;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        CoreProtectHook.plugin = plugin;\n        coreProtect = Bukkit.getPluginManager().getPlugin(\"CoreProtect\");\n        plugin.getProviders().registerStackedBlocksListener(CoreProtectHook::recordBlockAction);\n    }\n\n    private static void recordBlockAction(OfflinePlayer offlinePlayer, Block block,\n                                          IStackedBlocksListener.Action action) {\n        if (!Bukkit.isPrimaryThread()) {\n            BukkitExecutor.sync(() -> recordBlockAction(offlinePlayer, block, action));\n            return;\n        }\n\n        CoreProtectAPI coreProtectAPI = ((CoreProtect) coreProtect).getAPI();\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = block.getLocation(wrapper.getHandle());\n\n            if (coreProtectAPI.APIVersion() == 5) {\n                switch (action) {\n                    case BLOCK_BREAK:\n                        coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(), block.getData());\n                        break;\n                    case BLOCK_PLACE:\n                        coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(), block.getData());\n                        break;\n                }\n            } else if (coreProtectAPI.APIVersion() <= 9) {\n                switch (action) {\n                    case BLOCK_BREAK:\n                        coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(),\n                                (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block));\n                        break;\n                    case BLOCK_PLACE:\n                        coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(),\n                                (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block));\n                        break;\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/CraftEngine/build.gradle",
    "content": "group 'Hooks:CraftEngine'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\nrepositories {\n    maven { url \"https://repo.momirealms.net/releases/\" }\n}\n\ndependencies {\n    compileOnly \"net.momirealms:craft-engine-core:0.0.56\"\n    compileOnly \"net.momirealms:craft-engine-bukkit:0.0.56\"\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_craftengine') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_craftengine\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;\nimport net.momirealms.craftengine.bukkit.api.CraftEngineItems;\nimport net.momirealms.craftengine.core.block.CustomBlock;\nimport net.momirealms.craftengine.core.block.ImmutableBlockState;\nimport net.momirealms.craftengine.core.item.CustomItem;\nimport net.momirealms.craftengine.core.plugin.CraftEngine;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.data.BlockData;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class CraftEngineHook {\n\n    private static final String CRAFTENGINE_PREFIX = \"CRAFTENGINE\";\n    private static final KeySet CUSTOM_ITEM_KEYS = collectCustomItemKeys();\n    private static final KeySet CUSTOM_BLOCK_KEYS = collectCustomBlockKeys();\n    private static final KeyMap<ItemStack> CUSTOM_ITEM_CACHE = collectCustomItemsCache();\n    private static final KeyMap<CustomBlock> CUSTOM_ITEM_TO_BLOCK_CACHE = collectCustomItemToBlocksCache();\n\n    private static boolean registered = false;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin);\n        if (!registered) {\n            registered = true;\n            plugin.getBlockValues().registerKeyParser(new CraftEngineKeyParser(), collectCustomKeys());\n        }\n    }\n\n    private static KeySet collectCustomItemKeys() {\n        KeySet customItemKeys = KeySets.createHashSet(KeyIndicator.MATERIAL);\n        for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) {\n            CustomItem<ItemStack> customItem = CraftEngineItems.byId(itemKey);\n            if (customItem != null) {\n                ItemStack itemStack = customItem.buildItemStack();\n                customItemKeys.add(Keys.of(itemStack.getType()));\n            }\n        }\n        return customItemKeys;\n    }\n\n    private static KeySet collectCustomBlockKeys() {\n        KeySet customBlockKeys = KeySets.createHashSet(KeyIndicator.MATERIAL);\n        for (CustomBlock customBlock : CraftEngine.instance().blockManager().blocks().values()) {\n            BlockData blockData = CraftEngineBlocks.getBukkitBlockData(customBlock.defaultState());\n            customBlockKeys.add(Keys.of(blockData.getMaterial()));\n        }\n        return customBlockKeys;\n    }\n\n    private static KeyMap<ItemStack> collectCustomItemsCache() {\n        KeyMap<ItemStack> customItemsCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM);\n\n        for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) {\n            CustomItem<ItemStack> customItem = CraftEngineItems.byId(itemKey);\n            if (customItem != null) {\n                ItemStack itemStack = customItem.buildItemStack();\n                Key ssbItemKey = Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n                customItemsCache.put(ssbItemKey, itemStack);\n            }\n        }\n\n        return customItemsCache;\n    }\n\n    private static KeyMap<CustomBlock> collectCustomItemToBlocksCache() {\n        KeyMap<CustomBlock> customItemToBlocksCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM);\n\n        CraftEngine.instance().blockManager().blocks().forEach((blockKey, customBlock) -> {\n            Key ssbBlockKey = Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n            customItemToBlocksCache.put(ssbBlockKey, customBlock);\n        });\n\n        return customItemToBlocksCache;\n    }\n\n    private static Key[] collectCustomKeys() {\n        KeySet customKeys = KeySets.createHashSet(KeyIndicator.MATERIAL);\n        customKeys.addAll(CUSTOM_ITEM_KEYS);\n        customKeys.addAll(CUSTOM_BLOCK_KEYS);\n        return customKeys.toArray(new Key[0]);\n    }\n\n    private static class ListenerImpl implements Listener {\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onIslandGenerateBlock(IslandGenerateBlockEvent event) {\n            if (!event.getBlock().getGlobalKey().equals(CRAFTENGINE_PREFIX))\n                return;\n\n            CustomBlock customBlock = CUSTOM_ITEM_TO_BLOCK_CACHE.get(event.getBlock());\n            if (customBlock == null) {\n                event.setCancelled(true);\n                return;\n            }\n\n            event.setPlaceBlock(false);\n            CraftEngineBlocks.place(event.getLocation(), customBlock.defaultState(), false);\n        }\n\n    }\n\n    private static class CraftEngineKeyParser implements CustomKeyParser {\n\n        @Override\n        public Key getCustomKey(Location location) {\n            Block block = location.getBlock();\n            ImmutableBlockState customBlockState = CraftEngineBlocks.getCustomBlockState(block);\n            if (customBlockState == null || customBlockState.isEmpty())\n                return null;\n\n            net.momirealms.craftengine.core.util.Key blockKey = customBlockState.owner().value().id();\n\n            return Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public Key getCustomKey(ItemStack itemStack, Key def) {\n            CustomItem<ItemStack> customItem = CraftEngineItems.byItemStack(itemStack);\n            if (customItem == null)\n                return def;\n\n            net.momirealms.craftengine.core.util.Key itemKey = customItem.id();\n\n            return Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public boolean isCustomKey(Key key) {\n            return key.getGlobalKey().equals(CRAFTENGINE_PREFIX);\n        }\n\n        @Override\n        @Nullable\n        public ItemStack getCustomKeyItem(Key key) {\n            return key.getGlobalKey().equals(CRAFTENGINE_PREFIX) ? CUSTOM_ITEM_CACHE.get(key) : null;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/EpicSpawners6/build.gradle",
    "content": "group 'Hooks:EpicSpawners6'\n\ndependencies {\n    compileOnly 'com.songoda:EpicSpawners:6.0.6'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_epicspawners6') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_epicspawners6\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport com.songoda.epicspawners.EpicSpawners;\nimport com.songoda.epicspawners.api.events.SpawnerBreakEvent;\nimport com.songoda.epicspawners.api.events.SpawnerChangeEvent;\nimport com.songoda.epicspawners.api.events.SpawnerPlaceEvent;\nimport com.songoda.epicspawners.spawners.spawner.Spawner;\nimport com.songoda.epicspawners.spawners.spawner.SpawnerData;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\npublic class SpawnersProvider_EpicSpawners6 implements SpawnersProvider_AutoDetect {\n\n    private final EpicSpawners instance = EpicSpawners.getInstance();\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_EpicSpawners6(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using EpicSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        String entityType = null;\n\n        if (Bukkit.isPrimaryThread()) {\n            Spawner spawner = instance.getSpawnerManager().getSpawnerFromWorld(location);\n            blockCount = spawner.getFirstStack().getStackSize();\n            entityType = spawner.getIdentifyingName();\n        }\n\n        return new Pair<>(blockCount, entityType);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return instance.getSpawnerManager().getSpawnerData(itemStack).getIdentifyingName();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData();\n\n            Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n            int increaseAmount = e.getSpawner().getFirstStack().getStackSize();\n\n            if (spawnerData.isCustom()) {\n                // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and\n                // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered\n                // before removing it.\n                BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L);\n            } else {\n                // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already\n                // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly.\n                increaseAmount--;\n            }\n\n            if (increaseAmount <= 0)\n                return;\n\n            if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString()));\n            } else {\n                island.handleBlockPlace(spawnerKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerChangeEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            int increaseAmount = e.getStackSize() - e.getOldStackSize();\n\n            if (increaseAmount < 0) {\n                island.handleBlockBreak(blockKey, -increaseAmount);\n            } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/EpicSpawners7/build.gradle",
    "content": "group 'Hooks:EpicSpawners7'\n\ndependencies {\n    compileOnly 'com.songoda:EpicSpawners:7.0.2'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_epicspawners7') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_epicspawners7\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport com.songoda.epicspawners.EpicSpawners;\nimport com.songoda.epicspawners.api.events.SpawnerBreakEvent;\nimport com.songoda.epicspawners.api.events.SpawnerChangeEvent;\nimport com.songoda.epicspawners.api.events.SpawnerPlaceEvent;\nimport com.songoda.epicspawners.spawners.spawner.SpawnerData;\nimport com.songoda.epicspawners.spawners.spawner.SpawnerStack;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\n@SuppressWarnings(\"unused\")\npublic class SpawnersProvider_EpicSpawners7 implements SpawnersProvider {\n\n    private final EpicSpawners instance = EpicSpawners.getInstance();\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_EpicSpawners7(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new SpawnersProvider_EpicSpawners7.StackerListener(), plugin);\n        Log.info(\"Using EpicSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        String entityType = null;\n\n        if (Bukkit.isPrimaryThread()) {\n            SpawnerStack spawnerStack = instance.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack();\n            if (spawnerStack != null) {\n                blockCount = spawnerStack.getStackSize();\n                entityType = spawnerStack.getCurrentTier().getIdentifyingName();\n            }\n        }\n\n        return new Pair<>(blockCount, entityType);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return instance.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName();\n    }\n\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData();\n\n            Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n            int increaseAmount = e.getSpawner().getFirstStack().getStackSize();\n\n            if (spawnerData.isCustom()) {\n                // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and\n                // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered\n                // before removing it.\n                BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L);\n            } else {\n                // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already\n                // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly.\n                increaseAmount--;\n            }\n\n            if (increaseAmount <= 0)\n                return;\n\n            if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString()));\n            } else {\n                island.handleBlockPlace(spawnerKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerChangeEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            int increaseAmount = e.getStackSize() - e.getOldStackSize();\n\n            if (increaseAmount < 0) {\n                island.handleBlockBreak(blockKey, -increaseAmount);\n            } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/EpicSpawners8/build.gradle",
    "content": "group 'Hooks:EpicSpawners8'\n\ndependencies {\n    compileOnly \"com.songoda:EpicSpawners:8.1.0\"\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_epicspawners8') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_epicspawners8\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.craftaro.epicspawners.api.EpicSpawnersApi;\nimport com.craftaro.epicspawners.api.events.SpawnerBreakEvent;\nimport com.craftaro.epicspawners.api.events.SpawnerChangeEvent;\nimport com.craftaro.epicspawners.api.events.SpawnerPlaceEvent;\nimport com.craftaro.epicspawners.api.spawners.spawner.SpawnerData;\nimport com.craftaro.epicspawners.api.spawners.spawner.SpawnerStack;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\n@SuppressWarnings(\"unused\")\npublic class SpawnersProvider_EpicSpawners8 implements SpawnersProvider {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_EpicSpawners8(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using EpicSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        String entityType = null;\n\n        if (Bukkit.isPrimaryThread()) {\n            SpawnerStack spawnerStack = EpicSpawnersApi.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack();\n            if (spawnerStack != null) {\n                blockCount = spawnerStack.getStackSize();\n                entityType = spawnerStack.getCurrentTier().getIdentifyingName();\n            }\n        }\n\n        return new Pair<>(blockCount, entityType);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return EpicSpawnersApi.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName();\n    }\n\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData();\n\n            Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n            int increaseAmount = e.getSpawner().getFirstStack().getStackSize();\n\n            if (spawnerData.isCustom()) {\n                // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and\n                // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered\n                // before removing it.\n                BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L);\n            } else {\n                // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already\n                // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly.\n                increaseAmount--;\n            }\n\n            if (increaseAmount <= 0)\n                return;\n\n            if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString()));\n            } else {\n                island.handleBlockPlace(spawnerKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerChangeEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            int increaseAmount = e.getStackSize() - e.getOldStackSize();\n\n            if (increaseAmount < 0) {\n                island.handleBlockBreak(blockKey, -increaseAmount);\n            } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/EpicSpawners9/build.gradle",
    "content": "group 'Hooks:EpicSpawners8'\n\ndependencies {\n    compileOnly \"com.songoda:EpicSpawners:9.1.1\"\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_epicspawners9') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_epicspawners9\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport com.songoda.epicspawners.api.EpicSpawnersApi;\nimport com.songoda.epicspawners.api.events.SpawnerBreakEvent;\nimport com.songoda.epicspawners.api.events.SpawnerChangeEvent;\nimport com.songoda.epicspawners.api.events.SpawnerPlaceEvent;\nimport com.songoda.epicspawners.api.spawners.spawner.SpawnerData;\nimport com.songoda.epicspawners.api.spawners.spawner.SpawnerStack;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\n@SuppressWarnings(\"unused\")\npublic class SpawnersProvider_EpicSpawners9 implements SpawnersProvider {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_EpicSpawners9(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using EpicSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        String entityType = null;\n\n        if (Bukkit.isPrimaryThread()) {\n            SpawnerStack spawnerStack = EpicSpawnersApi.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack();\n            if (spawnerStack != null) {\n                blockCount = spawnerStack.getStackSize();\n                entityType = spawnerStack.getCurrentTier().getIdentifyingName();\n            }\n        }\n\n        return new Pair<>(blockCount, entityType);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return EpicSpawnersApi.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName();\n    }\n\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData();\n\n            Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n            int increaseAmount = e.getSpawner().getFirstStack().getStackSize();\n\n            if (spawnerData.isCustom()) {\n                // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and\n                // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered\n                // before removing it.\n                BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L);\n            } else {\n                // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already\n                // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly.\n                increaseAmount--;\n            }\n\n            if (increaseAmount <= 0)\n                return;\n\n            if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString()));\n            } else {\n                island.handleBlockPlace(spawnerKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerChangeEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            int increaseAmount = e.getStackSize() - e.getOldStackSize();\n\n            if (increaseAmount < 0) {\n                island.handleBlockBreak(blockKey, -increaseAmount);\n            } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName());\n\n            island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Essentials/build.gradle",
    "content": "group 'Hooks:Essentials'\n\ndependencies {\n    compileOnly 'com.earth2me:Essentials:2.16.0.3'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_essentials') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_essentials\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/afk/AFKProvider_Essentials.java",
    "content": "package com.bgsoftware.superiorskyblock.external.afk;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.AFKProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.earth2me.essentials.Essentials;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.entity.Player;\nimport org.bukkit.plugin.java.JavaPlugin;\n\npublic class AFKProvider_Essentials implements AFKProvider {\n\n    private final Essentials instance;\n\n    public AFKProvider_Essentials() {\n        instance = JavaPlugin.getPlugin(Essentials.class);\n        Log.info(\"Hooked into Essentials for support of afk status of players.\");\n    }\n\n    @Override\n    public boolean isAFK(Player player) {\n        Preconditions.checkNotNull(player, \"player parameter cannot be null.\");\n        return instance.getUser(player).isAfk();\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java",
    "content": "package com.bgsoftware.superiorskyblock.external.vanish;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications;\nimport com.earth2me.essentials.Essentials;\nimport net.ess3.api.events.VanishStatusChangeEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.java.JavaPlugin;\n\npublic class VanishProvider_Essentials implements VanishProvider, Listener {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final Essentials instance;\n\n    public VanishProvider_Essentials(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        this.instance = JavaPlugin.getPlugin(Essentials.class);\n        Bukkit.getPluginManager().registerEvents(this, plugin);\n        Log.info(\"Hooked into Essentials for support of vanish status of players.\");\n    }\n\n    @Override\n    public boolean isVanished(Player player) {\n        return instance.getUser(player).isVanished();\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerVanish(VanishStatusChangeEvent e) {\n        Player affectedPlayer = e.getAffected() == null ? e.getController().getBase() : e.getAffected().getBase();\n        if (e.getValue()) {\n            IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(affectedPlayer));\n        } else {\n            IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(affectedPlayer));\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/FastAsyncWorldEdit/build.gradle",
    "content": "group 'Hooks:FastAsyncWorldEdit'\n\ndependencies {\n    compileOnly 'com.boydti:FastAsyncWorldEdit:1.13.135'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_fastasyncworldedit') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_fastasyncworldedit\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.impl;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic;\nimport com.boydti.fawe.object.clipboard.FaweClipboard;\nimport com.sk89q.worldedit.EditSession;\nimport com.sk89q.worldedit.blocks.BaseBlock;\nimport com.sk89q.worldedit.bukkit.BukkitWorld;\nimport com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;\nimport com.sk89q.worldedit.math.transform.Transform;\nimport com.sk89q.worldedit.world.World;\nimport com.sk89q.worldedit.world.block.BlockState;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class WorldEditSchematic extends BaseSchematic implements Schematic {\n\n    private static ReflectMethod<Object> AT;\n    private static ReflectMethod<EditSession> PASTE;\n\n    private static final ReflectMethod<Object> GET_BLOCK_TYPE = new ReflectMethod<>(BaseBlock.class, \"getBlockType\");\n    private static final ReflectMethod<Integer> GET_INTERNAL_ID = new ReflectMethod<>(BaseBlock.class, \"getInternalId\");\n    private static final ReflectMethod<Material> ADAPT = new ReflectMethod<>(\n            new ClassInfo(\"com.sk89q.worldedit.bukkit.BukkitAdapter\", ClassInfo.PackageType.UNKNOWN),\n            \"adapt\",\n            new ClassInfo(\"com.sk89q.worldedit.world.block.BlockTypes\", ClassInfo.PackageType.UNKNOWN));\n\n    private static final ReflectMethod<Integer> GET_ID = new ReflectMethod<>(BaseBlock.class, \"getId\");\n    private static final ReflectMethod<Integer> GET_DATA = new ReflectMethod<>(BaseBlock.class, \"getData\");\n\n    private final com.boydti.fawe.object.schematic.Schematic schematic;\n\n    static {\n        try {\n            Class<?> blockVectorClass = Class.forName(\"com.sk89q.worldedit.math.BlockVector3\");\n            AT = new ReflectMethod<>(blockVectorClass, \"at\", int.class, int.class, int.class);\n            PASTE = new ReflectMethod<>(com.boydti.fawe.object.schematic.Schematic.class,\n                    \"paste\", World.class, blockVectorClass, boolean.class, boolean.class, Transform.class);\n        } catch (ClassNotFoundException ignored) {\n\n        }\n    }\n\n    public WorldEditSchematic(String name, com.boydti.fawe.object.schematic.Schematic schematic) {\n        super(name);\n        this.schematic = schematic;\n        readBlocks();\n    }\n\n    @Override\n    public void pasteSchematic(Island island, Location location, Runnable callback) {\n        pasteSchematic(island, location, callback, null);\n    }\n\n    @Override\n    public void pasteSchematic(Island island, Location location, Runnable callback, Consumer<Throwable> onFailure) {\n        try {\n            Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location);\n\n            Object _point = AT.invoke(null, location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            EditSession editSession = PASTE.invoke(schematic, new BukkitWorld(location.getWorld()), _point, false, true, null);\n\n            if (editSession == null) {\n                com.sk89q.worldedit.Vector point = new com.sk89q.worldedit.Vector(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n                editSession = schematic.paste(new BukkitWorld(location.getWorld()), point, true, true, null);\n            }\n\n            editSession.addNotifyTask(() -> {\n                Log.debugResult(Debug.PASTE_SCHEMATIC, \"Task Finished\", \"\");\n\n                try {\n                    island.handleBlocksPlace(cachedCounts);\n\n                    PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location);\n\n                    callback.run();\n                } catch (Throwable ex) {\n                    if (onFailure != null)\n                        onFailure.accept(ex);\n                }\n            });\n        } catch (Throwable ex) {\n            if (onFailure != null)\n                onFailure.accept(ex);\n        }\n    }\n\n    @Override\n    public Location adjustRotation(Location location) {\n        return location;\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Runnable onTeleportCallback() {\n        return null;\n    }\n\n    private void readBlocks() {\n        BlockArrayClipboard clipboard = (BlockArrayClipboard) schematic.getClipboard();\n\n        assert clipboard != null;\n\n        try {\n            clipboard.IMP.forEach(new BlockReader() {\n                @Override\n                public void run(int x, int y, int z, BaseBlock block) {\n                    readBlock(block);\n                }\n            }, false);\n        } catch (Throwable ex) {\n            clipboard.IMP.forEach(new FaweClipboard.BlockReader() {\n                @Override\n                public void run(int x, int y, int z, BlockState block) {\n                    readBlock(block);\n                }\n            }, false);\n        }\n    }\n\n    private void readBlock(Object baseBlock) {\n        Key key;\n\n        if (ADAPT.isValid() && GET_BLOCK_TYPE.isValid() && GET_INTERNAL_ID.isValid()) {\n            Material material = ADAPT.invoke(null, GET_BLOCK_TYPE.invoke(baseBlock));\n            int data = GET_INTERNAL_ID.invokeWithDef(baseBlock, 0);\n            key = Keys.of(material, (byte) data);\n        } else {\n            int id = GET_ID.invoke(baseBlock);\n            int data = GET_DATA.invoke(baseBlock);\n            //noinspection deprecation\n            key = Keys.of(Material.getMaterial(id), (byte) data);\n        }\n\n        cachedCounts.put(key, cachedCounts.getRaw(key, 0) + 1);\n    }\n\n    private static abstract class BlockReader extends FaweClipboard.BlockReader {\n\n        public abstract void run(int x, int y, int z, BaseBlock block);\n\n        public void run(int x, int y, int z, BlockState block) {\n            // Do nothing.\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/FAWESchematicParser.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.parser;\n\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\nimport com.bgsoftware.superiorskyblock.world.schematic.impl.WorldEditSchematic;\nimport com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;\n\nimport java.io.DataInputStream;\nimport java.io.IOException;\n\npublic class FAWESchematicParser implements SchematicParser {\n\n    public FAWESchematicParser() {\n\n    }\n\n    @Override\n    public Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException {\n        try {\n            //noinspection deprecation\n            return new WorldEditSchematic(schematicName, ClipboardFormat.SCHEMATIC.load(inputStream));\n        } catch (IOException error) {\n            throw new SchematicParseException(schematicName + \" is not a FastAsyncWorldEdit schematic.\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/ItemsAdder/build.gradle",
    "content": "group 'Hooks:ItemsAdder'\n\ndependencies {\n    compileOnly 'dev.lone:ItemsAdder:3.5.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_itemsadder') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_itemsadder\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport dev.lone.itemsadder.api.CustomBlock;\nimport dev.lone.itemsadder.api.CustomStack;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class ItemsAdderHook {\n\n    private static final String ITEMS_ADDER_PREFIX = \"ITEMS_ADDER\";\n    private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER);\n    private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK);\n\n    private static final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    private static boolean registered = false;\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        ItemsAdderHook.plugin = plugin;\n        plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin);\n        if (!registered) {\n            registered = true;\n            plugin.getBlockValues().registerKeyParser(new ItemsAdderKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY);\n        }\n    }\n\n    private static class ListenerImpl implements Listener {\n\n        @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)\n        public void onItemAdderBlockInteract(PlayerInteractEvent e) {\n            switch (e.getAction()) {\n                case RIGHT_CLICK_BLOCK:\n                    onBlockPlace(e);\n                    break;\n                case LEFT_CLICK_BLOCK:\n                    onBlockBreak(e);\n                    break;\n            }\n        }\n\n        private void onBlockPlace(PlayerInteractEvent e) {\n            if (e.getItem() == null)\n                return;\n\n            CustomBlock customBlock = CustomBlock.byItemStack(e.getItem());\n            if (customBlock == null)\n                return;\n\n            CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock());\n            if (clickedBlock != null)\n                return;\n\n            Block placeBlock = e.getClickedBlock().getRelative(e.getBlockFace());\n\n            BukkitExecutor.sync(() -> {\n                if (placeBlock.getType() == Material.NOTE_BLOCK) {\n                    try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                        Key itemKey = Keys.of(ITEMS_ADDER_PREFIX, customBlock.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n                        worldRecordService.get().recordBlockPlace(itemKey,\n                                placeBlock.getLocation(wrapper.getHandle()), 1,\n                                null, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS);\n                    }\n                }\n            }, 1L);\n        }\n\n        private void onBlockBreak(PlayerInteractEvent e) {\n            CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock());\n            if (clickedBlock != null) {\n                Key blockKey = Key.of(e.getClickedBlock());\n                BukkitExecutor.sync(() -> {\n                    if (e.getClickedBlock().getType() == Material.AIR) {\n                        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                            worldRecordService.get().recordBlockBreak(blockKey,\n                                    e.getClickedBlock().getLocation(wrapper.getHandle()),\n                                    1,\n                                    WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS);\n                        }\n                    }\n                }, 1L);\n\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onIslandGenerateBlock(IslandGenerateBlockEvent event) {\n            if (!event.getBlock().getGlobalKey().equals(ITEMS_ADDER_PREFIX))\n                return;\n\n            String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH);\n\n            CustomBlock customBlock = CustomBlock.getInstance(itemId);\n\n            if (customBlock == null) {\n                event.setCancelled(true);\n                return;\n            }\n\n            event.setPlaceBlock(false);\n            customBlock.place(event.getLocation());\n        }\n\n    }\n\n    private static class ItemsAdderKeyParser implements CustomKeyParser {\n\n        @Override\n        public Key getCustomKey(Location location) {\n            Block block = location.getBlock();\n            CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);\n            if (customBlock == null)\n                return BLOCK_KEY;\n            return Keys.of(ITEMS_ADDER_PREFIX, customBlock.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public Key getCustomKey(ItemStack itemStack, Key def) {\n            CustomStack customStack = CustomStack.byItemStack(itemStack);\n            if (customStack == null)\n                return def;\n            return Keys.of(ITEMS_ADDER_PREFIX, customStack.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public boolean isCustomKey(Key key) {\n            return key.getGlobalKey().equals(ITEMS_ADDER_PREFIX);\n        }\n\n        @Override\n        @Nullable\n        public ItemStack getCustomKeyItem(Key key) {\n            CustomStack customStack = CustomStack.getInstance(key.getSubKey().toLowerCase(Locale.ENGLISH));\n            if (customStack == null)\n                return null;\n            return customStack.getItemStack();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/JetsMinions/build.gradle",
    "content": "group 'Hooks:JetsMinions'\n\ndependencies {\n    compileOnly 'me.jet315:JetsMinions:6.9.2'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_jetsminions') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_jetsminions\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/JetsMinions/src/main/java/com/bgsoftware/superiorskyblock/external/JetsMinionsHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper;\nimport me.jet315.minions.events.MinerBlockBreakEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class JetsMinionsHook implements Listener {\n\n    @WorldRecordFlags\n    private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n\n    private final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n    private final LazyReference<StackedBlocksInteractionService> stackedBlocksInteractionService = new LazyReference<StackedBlocksInteractionService>() {\n        @Override\n        protected StackedBlocksInteractionService create() {\n            return plugin.getServices().getService(StackedBlocksInteractionService.class);\n        }\n    };\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    private JetsMinionsHook(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        Bukkit.getPluginManager().registerEvents(new JetsMinionsHook(plugin), plugin);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onMinionBreak(MinerBlockBreakEvent e) {\n        Log.debug(Debug.BLOCK_BREAK, e.getBlock().getType());\n\n        InteractionResult interactionResult = this.stackedBlocksInteractionService.get()\n                .handleStackedBlockBreak(e.getBlock(), null);\n        if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) {\n            e.setCancelled(true);\n        } else {\n            this.worldRecordService.get().recordBlockBreak(e.getBlock(), REGULAR_RECORD_FLAGS);\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/LuckPerms/build.gradle",
    "content": "group 'Hooks:LuckPerms'\n\ndependencies {\n    compileOnly 'net.luckperms:LuckPerms:5.1.15'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_luckperms') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_luckperms\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java",
    "content": "package com.bgsoftware.superiorskyblock.external.permissions;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore;\nimport net.luckperms.api.LuckPerms;\nimport net.luckperms.api.cacheddata.CachedDataManager;\nimport net.luckperms.api.event.node.NodeAddEvent;\nimport net.luckperms.api.event.node.NodeRemoveEvent;\nimport net.luckperms.api.model.user.User;\nimport net.luckperms.api.node.Node;\nimport net.luckperms.api.node.types.InheritanceNode;\nimport net.luckperms.api.node.types.PermissionNode;\nimport net.luckperms.api.node.types.RegexPermissionNode;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\nimport java.util.UUID;\n\n@SuppressWarnings(\"unused\")\npublic class PermissionsProvider_LuckPerms implements PermissionsProvider {\n\n    private final LuckPerms luckPerms;\n\n    public static boolean isCompatible() {\n        try {\n            CachedDataManager.class.getMethod(\"getPermissionData\");\n            return true;\n        } catch (Throwable ex) {\n            Log.warn(\"You are using an outdated version of LuckPerms. It's recommended to update for a more optimized experience (v5.1+).\");\n            return false;\n        }\n    }\n\n    public PermissionsProvider_LuckPerms(SuperiorSkyblockPlugin plugin) {\n        this.luckPerms = Bukkit.getServicesManager().getRegistration(LuckPerms.class).getProvider();\n        this.luckPerms.getEventBus().subscribe(plugin, NodeAddEvent.class, this::onPermissionsAdd);\n        this.luckPerms.getEventBus().subscribe(plugin, NodeRemoveEvent.class, this::onPermissionsRemove);\n        Log.info(\"Using LuckPerms as a permissions provider.\");\n    }\n\n    @Override\n    public boolean hasPermission(Player player, String permission) {\n        User user = this.luckPerms.getUserManager().getUser(player.getUniqueId());\n        return user != null && user.getCachedData().getPermissionData().getPermissionMap()\n                .getOrDefault(permission.toLowerCase(Locale.ENGLISH), false);\n    }\n\n    private void onPermissionsAdd(NodeAddEvent e) {\n        if (e.getTarget() instanceof User && isTrackableNode(e.getNode()))\n            notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId());\n    }\n\n    private void onPermissionsRemove(NodeRemoveEvent e) {\n        if (e.getTarget() instanceof User && isTrackableNode(e.getNode()))\n            notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId());\n    }\n\n    private void notifyPermissionsUpdate(UUID playerUUID) {\n        PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(playerUUID);\n        if (permissionsStore != null)\n            permissionsStore.markDirty();\n    }\n\n    private static boolean isTrackableNode(Node node) {\n        if (node instanceof PermissionNode) {\n            return ((PermissionNode) node).getPermission().contains(\"superior\");\n        }\n\n        // In the case of RegexPermissionNode - we are not going to try and parse the regex.\n        // In the case of InheritanceNode - we are not going to go through the inherited group and check for permissions.\n        // We will always mark cache as dirty for both of these events.\n        return node instanceof RegexPermissionNode || node instanceof InheritanceNode;\n    }\n\n}\n"
  },
  {
    "path": "Hooks/MVdWPlaceholderAPI/build.gradle",
    "content": "group 'Hooks:MVdWPlaceholderAPI'\n\ndependencies {\n    compileOnly 'be.maximvdw:MVdWPlaceholderAPI:3.0.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_mvdwplaceholderapi') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_mvdwplaceholderapi\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/MVdWPlaceholderAPI/src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider_MVdWPlaceholderAPI.java",
    "content": "package com.bgsoftware.superiorskyblock.external.placeholders;\n\nimport be.maximvdw.placeholderapi.PlaceholderAPI;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl;\nimport org.bukkit.OfflinePlayer;\n\nimport java.util.regex.Pattern;\n\n@SuppressWarnings(\"unused\")\npublic class PlaceholdersProvider_MVdWPlaceholderAPI implements PlaceholdersProvider {\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private static final Pattern BUILT_IN_NUMERIC_PLACEHOLDER = Pattern.compile(\"\\\\{(\\\\d)}\");\n\n    public PlaceholdersProvider_MVdWPlaceholderAPI(SuperiorSkyblockPlugin plugin) {\n        Log.info(\"Using MVdWPlaceholderAPI for placeholders support.\");\n        PlaceholderAPI.registerPlaceholder(plugin, \"superior_*\", e ->\n                ((PlaceholdersServiceImpl) placeholdersService.get()).handlePluginPlaceholder(e.getOfflinePlayer(),\n                        e.getPlaceholder().replace(\"superior_\", \"\")));\n    }\n\n    @Override\n    public String parsePlaceholders(OfflinePlayer offlinePlayer, String value) {\n        return PlaceholderAPI.replacePlaceholders(offlinePlayer, BUILT_IN_NUMERIC_PLACEHOLDER.matcher(value)\n                .replaceAll(\"{%$1}\")).replace(\"{%\", \"{\");\n    }\n\n}\n"
  },
  {
    "path": "Hooks/MergedSpawner/build.gradle",
    "content": "group 'Hooks:MergedSpawner'\n\ndependencies {\n    compileOnly 'com.vk2gpz:MergedSpawner:13.0.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_mergedspawner') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_mergedspawner\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport com.vk2gpz.mergedspawner.api.MergedSpawnerAPI;\nimport com.vk2gpz.mergedspawner.event.MergedSpawnerBreakEvent;\nimport com.vk2gpz.mergedspawner.event.MergedSpawnerPlaceEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\npublic class SpawnersProvider_MergedSpawner implements SpawnersProvider_AutoDetect {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_MergedSpawner(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new SpawnersProvider_MergedSpawner.StackerListener(), plugin);\n        Log.info(\"Using MergedSpawner as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        int blockCount = -1;\n\n        if (Bukkit.isPrimaryThread()) {\n            MergedSpawnerAPI spawnerAPI = MergedSpawnerAPI.getInstance();\n            blockCount = spawnerAPI.getCountFor(location.getBlock());\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        return MergedSpawnerAPI.getInstance().getEntityType(itemStack).name();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerStack(MergedSpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            int increaseAmount = e.getNewCount() - e.getOldCount();\n            if (island != null)\n                island.handleBlockPlace(e.getBlock(), increaseAmount);\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(MergedSpawnerBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            int decreaseAmount = e.getOldCount() - e.getNewCount();\n            if (island != null)\n                island.handleBlockBreak(Keys.ofSpawner(e.getSpawnerType()), decreaseAmount);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/MiniMessage/build.gradle",
    "content": "group 'Hooks:MiniMessage'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    compileOnly(\"net.kyori:adventure-text-minimessage:4.17.0\")\n    compileOnly(\"net.kyori:adventure-text-serializer-plain:4.19.0\")\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_minimessage') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_minimessage\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}\n"
  },
  {
    "path": "Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.service.message.MessagesService;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl;\nimport net.kyori.adventure.text.Component;\nimport net.kyori.adventure.text.TextComponent;\nimport net.kyori.adventure.text.TextReplacementConfig;\nimport net.kyori.adventure.text.event.ClickEvent;\nimport net.kyori.adventure.text.minimessage.MiniMessage;\nimport net.kyori.adventure.text.minimessage.ParsingException;\nimport net.kyori.adventure.text.minimessage.tag.standard.StandardTags;\nimport net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.regex.MatchResult;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MiniMessageHook {\n\n    private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().tags(StandardTags.defaults()).build();\n\n    private static boolean registered = false;\n\n    private static final MessagesServiceImpl.CustomComponentParser PARSER = new MessagesServiceImpl.CustomComponentParser() {\n        @Override\n        public Optional<IMessageComponent> parse(YamlConfiguration config, String path) {\n            if (!config.isString(path))\n                return Optional.empty();\n\n            String content = config.getString(path);\n            if (Text.isBlank(content))\n                return Optional.empty();\n\n            return parse(content);\n        }\n\n        @Override\n        public Optional<IMessageComponent> parse(String content) {\n            try {\n                Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content));\n                return Optional.of(new MiniMessageComponent(component));\n            } catch (ParsingException error) {\n                return Optional.empty();\n            }\n        }\n    };\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        if (!registered) {\n            MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class);\n            messagesService.registerCustomComponentParser(PARSER);\n            registered = true;\n        }\n    }\n\n    private static class MiniMessageComponent implements IMessageComponent {\n\n        private final Component component;\n        private final MessageContent content;\n\n        MiniMessageComponent(Component component) {\n            this.component = component;\n            this.content = findTextComponentContent(component);\n        }\n\n        @Override\n        public Type getType() {\n            return Type.COMPLEX_MESSAGE;\n        }\n\n        @Override\n        public String getMessage() {\n            return this.content.getContent(null).orElse(\"\");\n        }\n\n        @Override\n        public String getMessage(Object... args) {\n            return this.content.getContent(null, args).orElse(\"\");\n        }\n\n        @Override\n        public void sendMessage(CommandSender sender, Object... args) {\n            sender.sendMessage(Translator.translate(this.component, args));\n        }\n\n        private static MessageContent findTextComponentContent(Component component) {\n            if (component instanceof TextComponent textComponent)\n                return MessageContent.parse(textComponent.content());\n\n            for (Component children : component.children()) {\n                MessageContent childrenContent = findTextComponentContent(children);\n                if (childrenContent != MessageContent.EMPTY)\n                    return childrenContent;\n            }\n\n\n            return MessageContent.EMPTY;\n        }\n\n    }\n\n    private static class Translator {\n        private static final Pattern ARG_PATTERN = Pattern.compile(\"\\\\{[0-9]+}\");\n\n        static Component translate(Component input, Object... args) {\n            Component output = input;\n            if (args.length != 0) {\n                output = output.replaceText(TextReplacementConfig.builder()\n                        .match(ARG_PATTERN)\n                        .replacement((result, builder) -> doReplacement(result, args))\n                        .build());\n                output = translateClickEvent(output, args);\n            }\n            return translateChildren(output, args);\n        }\n\n        private static Component translateChildren(Component input, Object... args) {\n            List<Component> children = new LinkedList<>();\n            for (Component component : input.children()) {\n                Component output = translate(component, args);\n                children.add(translateChildren(output, args));\n            }\n            return input.children(children);\n        }\n\n        private static Component translateClickEvent(Component input, Object... args) {\n            ClickEvent event = input.clickEvent();\n            if (event == null) return input;\n\n            String value = event.value();\n            Matcher matcher = ARG_PATTERN.matcher(value);\n\n            String result = matcher.replaceAll(match -> doTextReplacement(match, args));\n            return input.clickEvent(ClickEvent.clickEvent(event.action(), result));\n        }\n\n        private static Component doReplacement(MatchResult match, Object... args) {\n            String group = match.group();\n            int index = Integer.parseInt(group.substring(1, group.length() - 1));\n            return Component.text(index < args.length ? MessageContent.getArgumentString(args[index]) : group);\n        }\n\n        private static String doTextReplacement(MatchResult match, Object... args) {\n            return PlainTextComponentSerializer.plainText().serialize(doReplacement(match, args));\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Nexo/build.gradle",
    "content": "group 'Hooks:Nexo'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\nrepositories {\n    mavenCentral()\n    maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }\n}\n\ndependencies {\n    compileOnly \"com.nexomc:Nexo:0.9\"\n    compileOnly \"org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_nexo') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_nexo\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider;\nimport com.nexomc.nexo.api.NexoBlocks;\nimport com.nexomc.nexo.api.NexoFurniture;\nimport com.nexomc.nexo.api.NexoItems;\nimport com.nexomc.nexo.api.events.furniture.NexoFurnitureBreakEvent;\nimport com.nexomc.nexo.api.events.furniture.NexoFurniturePlaceEvent;\nimport com.nexomc.nexo.items.ItemBuilder;\nimport com.nexomc.nexo.mechanics.Mechanic;\nimport com.nexomc.nexo.mechanics.MechanicFactory;\nimport com.nexomc.nexo.mechanics.MechanicsManager;\nimport com.nexomc.nexo.mechanics.custom_block.noteblock.NoteBlockMechanicFactory;\nimport com.nexomc.nexo.mechanics.custom_block.stringblock.StringBlockMechanicFactory;\nimport com.nexomc.nexo.mechanics.furniture.FurnitureMechanic;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class NexoHook {\n\n    private static final String NEXO_PREFIX = \"NEXO\";\n    private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER);\n    private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK);\n\n    private static final List<MechanicData> AVAILABLE_MECHANICS = new LinkedList<>();\n\n    private static final LazyReference<WorldRecordService> worldRecordService = new LazyReference<>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    private static boolean registered = false;\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        NexoHook.plugin = plugin;\n        plugin.getServer().getPluginManager().registerEvents(new NexoListener(), plugin);\n        if (!registered) {\n            registered = true;\n            plugin.getProviders().registerCustomBlocksProvider(new NexuCustomBlocksProvider());\n            BukkitExecutor.sync(NexoHook::initializeMechanics, 1L);\n            plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY);\n        }\n    }\n\n    private static void initializeMechanics() {\n        MechanicsManager mechanicsManager = MechanicsManager.INSTANCE;\n        AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory(\"noteblock\"), NoteBlockMechanicFactory.Companion::setBlockModel));\n        AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory(\"stringblock\"), StringBlockMechanicFactory.Companion::setBlockModel));\n    }\n\n    private static class NexuCustomBlocksProvider implements ICustomBlocksProvider {\n\n        @Nullable\n        @Override\n        public KeyMap<Integer> getBlockCountsForChunk(ChunkPosition chunkPosition) {\n            if (!Bukkit.isPrimaryThread())\n                return null;\n\n            World world = chunkPosition.getWorld();\n            if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ()))\n                return KeyMaps.createEmptyMap();\n\n            KeyMap<Integer> blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM);\n\n            Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ());\n\n            for (Entity entity : chunk.getEntities()) {\n                FurnitureMechanic mechanic = NexoFurniture.furnitureMechanic(entity);\n                if (mechanic != null) {\n                    Key blockKey = Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n                    blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1);\n                }\n            }\n\n            return blockCounts;\n        }\n    }\n\n    private static class NexoListener implements Listener {\n\n        @WorldRecordFlags\n        private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n        @WorldRecordFlags\n        private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS;\n\n        @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)\n        public void onNexoBlockBreak(BlockBreakEvent e) {\n            Key blockKey = Keys.of(e.getBlock());\n            if (blockKey.getGlobalKey().equals(NEXO_PREFIX)) {\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    worldRecordService.get().recordBlockBreak(blockKey,\n                            e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS);\n                }\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onFurniturePlace(NexoFurniturePlaceEvent e) {\n            Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()),\n                        1, null, REGULAR_RECORD_FLAGS);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onFurnitureBreak(NexoFurnitureBreakEvent e) {\n            Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                worldRecordService.get().recordBlockBreak(blockKey,\n                        e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onIslandGenerateBlock(IslandGenerateBlockEvent event) {\n            if (!event.getBlock().getGlobalKey().equals(NEXO_PREFIX))\n                return;\n\n            String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH);\n\n            if (!NexoItems.exists(itemId)) {\n                event.setCancelled(true);\n                return;\n            }\n\n            for (MechanicData mechanic : AVAILABLE_MECHANICS) {\n                if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) {\n                    event.setPlaceBlock(false);\n                    mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId);\n                    return;\n                }\n            }\n\n            // No mechanic was found\n            event.setCancelled(true);\n        }\n\n    }\n\n    private static class NexoKeyParser implements CustomKeyParser {\n\n        @Override\n        public Key getCustomKey(Location location) {\n            Mechanic mechanic = NexoBlocks.customBlockMechanic(location);\n            if (mechanic == null)\n                return BLOCK_KEY;\n            return Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public Key getCustomKey(ItemStack itemStack, Key def) {\n            String itemId = NexoItems.idFromItem(itemStack);\n            if (itemId == null)\n                return def;\n            return Keys.of(NEXO_PREFIX, itemId.toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public boolean isCustomKey(Key key) {\n            return key.getGlobalKey().equals(NEXO_PREFIX);\n        }\n\n        @Override\n        @Nullable\n        public ItemStack getCustomKeyItem(Key key) {\n            ItemBuilder itemBuilder = NexoItems.itemFromId(key.getSubKey().toLowerCase(Locale.ENGLISH));\n            if (itemBuilder == null)\n                return null;\n            return itemBuilder.build();\n        }\n\n    }\n\n    private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) {\n\n    }\n\n    private interface SetBlockModelFunction {\n\n        void setBlockModel(Block block, String itemId);\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/OpenJdkNashornEngine/build.gradle",
    "content": "group 'Hooks:OpenJdkNashornEngine'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    compileOnly 'org.openjdk.nashorn:nashorn-core:15.4'\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n"
  },
  {
    "path": "Hooks/OpenJdkNashornEngine/src/main/java/com/bgsoftware/superiorskyblock/core/engine/OpenJdkNashornEngine.java",
    "content": "package com.bgsoftware.superiorskyblock.core.engine;\n\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\nimport org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;\n\nimport javax.script.Bindings;\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineFactory;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class OpenJdkNashornEngine implements IScriptEngine {\n\n    private static final List<String> JAVASCRIPT_ENGINE_NAMES = Arrays.asList(\n            \"js\", \"JS\", \"javascript\", \"JavaScript\", \"ecmascript\", \"ECMAScript\", \"nashorn\", \"Nashorn\"\n    );\n\n    private static final OpenJdkNashornEngine INSTANCE = new OpenJdkNashornEngine();\n\n    public static OpenJdkNashornEngine getInstance() {\n        return INSTANCE;\n    }\n\n    private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();\n    private final ScriptEngine engine;\n\n    private OpenJdkNashornEngine() {\n        ScriptEngineFactory factory = new NashornScriptEngineFactory();\n        JAVASCRIPT_ENGINE_NAMES.forEach(n -> scriptEngineManager.registerEngineName(n, factory));\n        engine = scriptEngineManager.getEngineByName(\"nashorn\");\n    }\n\n    @Override\n    public Object eval(String stringToEvaluate) throws ScriptException {\n        return engine.eval(stringToEvaluate);\n    }\n\n    @Override\n    public Object eval(String stringToEvaluate, Bindings bindings) throws ScriptException {\n        return engine.eval(stringToEvaluate, bindings);\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Oraxen/build.gradle",
    "content": "group 'Hooks:Oraxen'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ndependencies {\n    compileOnly 'io.th0rgal:Oraxen:1.187.0'\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_oraxen') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_oraxen\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider;\nimport io.th0rgal.oraxen.api.OraxenBlocks;\nimport io.th0rgal.oraxen.api.OraxenFurniture;\nimport io.th0rgal.oraxen.api.OraxenItems;\nimport io.th0rgal.oraxen.api.events.furniture.OraxenFurnitureBreakEvent;\nimport io.th0rgal.oraxen.api.events.furniture.OraxenFurniturePlaceEvent;\nimport io.th0rgal.oraxen.items.ItemBuilder;\nimport io.th0rgal.oraxen.mechanics.Mechanic;\nimport io.th0rgal.oraxen.mechanics.MechanicFactory;\nimport io.th0rgal.oraxen.mechanics.MechanicsManager;\nimport io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory;\nimport io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic;\nimport io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;\nimport io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class OraxenHook {\n\n    private static final String ORAXEN_PREFIX = \"ORAXEN\";\n    private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER);\n    private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK);\n\n    private static final List<MechanicData> AVAILABLE_MECHANICS = initializeMechanics();\n\n    private static List<MechanicData> initializeMechanics() {\n        List<MechanicData> mechanics = new LinkedList<>();\n\n        try {\n            Class.forName(\"io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory\");\n            mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory(\"block\"), BlockMechanicFactory::setBlockModel));\n            mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory(\"noteblock\"), NoteBlockMechanicFactory::setBlockModel));\n            mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory(\"stringblock\"), StringBlockMechanicFactory::setBlockModel));\n        } catch (Throwable error) {\n            {\n                ReflectMethod<Void> setBlockModel = new ReflectMethod<>(\n                        new ClassInfo(\"io.th0rgal.oraxen.mechanics.provided.block.BlockMechanicFactory\", ClassInfo.PackageType.UNKNOWN),\n                        \"setBlockModel\", Block.class, String.class);\n\n                mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory(\"block\"), (block, itemId) -> {\n                    if (setBlockModel.isValid())\n                        setBlockModel.invoke(null, block, itemId);\n                }));\n            }\n\n            {\n                ReflectMethod<Void> setBlockModel = new ReflectMethod<>(\n                        new ClassInfo(\"io.th0rgal.oraxen.mechanics.provided.noteblock.NoteBlockMechanicFactory\", ClassInfo.PackageType.UNKNOWN),\n                        \"setBlockModel\", Block.class, String.class);\n\n                mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory(\"noteblock\"), (block, itemId) -> {\n                    if (setBlockModel.isValid())\n                        setBlockModel.invoke(null, block, itemId);\n                }));\n            }\n        }\n\n        return Collections.unmodifiableList(mechanics);\n    }\n\n    private static final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    private static boolean registered = false;\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        OraxenHook.plugin = plugin;\n        plugin.getServer().getPluginManager().registerEvents(new OraxenListener(), plugin);\n        if (!registered) {\n            registered = true;\n            plugin.getProviders().registerCustomBlocksProvider(new OraxenCustomBlocksProvider());\n            plugin.getBlockValues().registerKeyParser(new OraxenKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY);\n        }\n    }\n\n    private static class OraxenCustomBlocksProvider implements ICustomBlocksProvider {\n\n        @Nullable\n        @Override\n        public KeyMap<Integer> getBlockCountsForChunk(ChunkPosition chunkPosition) {\n            if (!Bukkit.isPrimaryThread())\n                return null;\n\n            World world = chunkPosition.getWorld();\n            if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ()))\n                return KeyMaps.createEmptyMap();\n\n            KeyMap<Integer> blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM);\n\n            Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ());\n\n            for (Entity entity : chunk.getEntities()) {\n                FurnitureMechanic mechanic = OraxenFurniture.getFurnitureMechanic(entity);\n                if (mechanic != null) {\n                    Key blockKey = Keys.of(ORAXEN_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n                    blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1);\n                }\n            }\n\n            return blockCounts;\n        }\n    }\n\n    private static class OraxenListener implements Listener {\n\n        @WorldRecordFlags\n        private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n        @WorldRecordFlags\n        private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS;\n\n        @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)\n        public void onOraxenBlockBreak(BlockBreakEvent e) {\n            Key blockKey = Keys.of(e.getBlock());\n            if (blockKey.getGlobalKey().equals(ORAXEN_PREFIX)) {\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    worldRecordService.get().recordBlockBreak(blockKey,\n                            e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS);\n                }\n\n\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onFurniturePlace(OraxenFurniturePlaceEvent e) {\n            Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()),\n                        1, null, REGULAR_RECORD_FLAGS);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onFurnitureBreak(OraxenFurnitureBreakEvent e) {\n            Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                worldRecordService.get().recordBlockBreak(blockKey,\n                        e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onIslandGenerateBlock(IslandGenerateBlockEvent event) {\n            if (!event.getBlock().getGlobalKey().equals(ORAXEN_PREFIX))\n                return;\n\n            String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH);\n\n            if (!OraxenItems.exists(itemId)) {\n                event.setCancelled(true);\n                return;\n            }\n\n            for (MechanicData mechanic : AVAILABLE_MECHANICS) {\n                if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) {\n                    event.setPlaceBlock(false);\n                    mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId);\n                    return;\n                }\n            }\n\n            // No mechanic was found\n            event.setCancelled(true);\n        }\n\n    }\n\n    private static class OraxenKeyParser implements CustomKeyParser {\n\n        @Override\n        public Key getCustomKey(Location location) {\n            Mechanic mechanic = OraxenBlocks.getOraxenBlock(location);\n            if (mechanic == null)\n                return BLOCK_KEY;\n            return Keys.of(ORAXEN_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public Key getCustomKey(ItemStack itemStack, Key def) {\n            String itemId = OraxenItems.getIdByItem(itemStack);\n            if (itemId == null)\n                return def;\n            return Keys.of(ORAXEN_PREFIX, itemId.toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM);\n        }\n\n        @Override\n        public boolean isCustomKey(Key key) {\n            return key.getGlobalKey().equals(ORAXEN_PREFIX);\n        }\n\n        @Override\n        @Nullable\n        public ItemStack getCustomKeyItem(Key key) {\n            ItemBuilder itemBuilder = OraxenItems.getItemById(key.getSubKey().toLowerCase(Locale.ENGLISH));\n            if (itemBuilder == null)\n                return null;\n            return itemBuilder.build();\n        }\n\n    }\n\n    private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) {\n\n    }\n\n    private interface SetBlockModelFunction {\n\n        void setBlockModel(Block block, String itemId);\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/PaperMC/build.gradle",
    "content": "group 'Hooks:PaperMC'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_papermc') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_papermc\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}\n"
  },
  {
    "path": "Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider_Paper.java",
    "content": "package com.bgsoftware.superiorskyblock.external.async;\n\nimport com.bgsoftware.superiorskyblock.external.async.AsyncProvider;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\nimport java.util.function.Consumer;\n\npublic class AsyncProvider_Paper implements AsyncProvider {\n\n    @Override\n    public void teleport(Entity entity, Location location, Consumer<Boolean> teleportResult) {\n        entity.teleportAsync(location).whenComplete((result, ex) -> {\n            if (teleportResult != null)\n                teleportResult.accept(result);\n        });\n    }\n\n}\n"
  },
  {
    "path": "Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/chunks/ChunksProvider_Paper.java",
    "content": "package com.bgsoftware.superiorskyblock.external.chunks;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider;\nimport org.bukkit.Chunk;\nimport org.bukkit.World;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class ChunksProvider_Paper implements ChunksProvider {\n\n    @Override\n    public CompletableFuture<Chunk> loadChunk(World world, int chunkX, int chunkZ) {\n        return world.getChunkAtAsync(chunkX, chunkZ);\n    }\n\n}\n"
  },
  {
    "path": "Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/remapper/PluginRemapperFilesLookupProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.external.remapper;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupProvider;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class PluginRemapperFilesLookupProvider implements FilesLookupProvider {\n\n    private static final ReflectMethod<Object> CREATE_PLUGIN_REMAPPER;\n    private static final ReflectMethod<Void> PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY;\n    private static final ReflectMethod<Path> PLUGIN_REMAPPER_REWRITE_PLUGIN;\n    private static final ReflectMethod<Void> PLUGIN_REMAPPER_LOADING_PLUGINS;\n    private static final ReflectMethod<Void> PLUGIN_REMAPPER_PLUGINS_ENABLED;\n    private static final ReflectMethod<Void> PLUGIN_REMAPPER_SHUTDOWN;\n\n    static {\n        ClassInfo pluginRemapperClassInfo = new ClassInfo(\"io.papermc.paper.pluginremap.PluginRemapper\",\n                ClassInfo.PackageType.UNKNOWN);\n        CREATE_PLUGIN_REMAPPER = new ReflectMethod<>(pluginRemapperClassInfo, \"create\", Path.class);\n        PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY = new ReflectMethod<>(pluginRemapperClassInfo, \"rewritePluginDirectory\", List.class);\n        PLUGIN_REMAPPER_REWRITE_PLUGIN = new ReflectMethod<>(pluginRemapperClassInfo, \"rewritePlugin\", Path.class);\n        PLUGIN_REMAPPER_LOADING_PLUGINS = new ReflectMethod<>(pluginRemapperClassInfo, \"loadingPlugins\", new Class[0]);\n        PLUGIN_REMAPPER_PLUGINS_ENABLED = new ReflectMethod<>(pluginRemapperClassInfo, \"pluginsEnabled\", new Class[0]);\n        PLUGIN_REMAPPER_SHUTDOWN = new ReflectMethod<>(pluginRemapperClassInfo, \"shutdown\", new Class[0]);\n    }\n\n    @Override\n    public FilesLookup createFilesLookup(File folder) {\n        Object pluginRemapper = CREATE_PLUGIN_REMAPPER.invoke(null, folder.toPath());\n        if (pluginRemapper == null)\n            throw new IllegalStateException(\"Cannot create PluginRemapper\");\n\n        PLUGIN_REMAPPER_LOADING_PLUGINS.invoke(pluginRemapper);\n\n        List<Path> folderFiles = new LinkedList<>();\n        for (File file : Files.listFolderFiles(folder, false, file -> file.getName().endsWith(\".jar\"))) {\n            folderFiles.add(file.toPath());\n        }\n\n        PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY.invoke(pluginRemapper, folderFiles);\n\n        File remappedFolder = new File(folder, \".paper-remapped\");\n        if (!remappedFolder.isDirectory())\n            throw new IllegalStateException(\"Cannot find remapped folder: \" + remappedFolder.getAbsolutePath());\n\n        return new PluginRemapperFilesLookup(remappedFolder, pluginRemapper);\n    }\n\n    private static class PluginRemapperFilesLookup implements FilesLookup {\n\n        private final File remappedFolder;\n        private Object pluginRemapper;\n\n        public PluginRemapperFilesLookup(File remappedFolder, Object pluginRemapper) {\n            this.remappedFolder = remappedFolder;\n            this.pluginRemapper = pluginRemapper;\n        }\n\n        @Override\n        public File getFile(String name) {\n            File file = new File(this.remappedFolder, name);\n            return PLUGIN_REMAPPER_REWRITE_PLUGIN.invoke(this.pluginRemapper, file.toPath()).toFile();\n        }\n\n        @Override\n        public void close() {\n            PLUGIN_REMAPPER_PLUGINS_ENABLED.invoke(this.pluginRemapper);\n            PLUGIN_REMAPPER_SHUTDOWN.invoke(this.pluginRemapper);\n            this.pluginRemapper = null;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/PlaceholderAPI/build.gradle",
    "content": "group 'Hooks:PlaceholderAPI'\n\ndependencies {\n    compileOnly 'me.clip:PlaceholderAPI:2.10.3'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_placeholderapi') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_placeholderapi\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/PlaceholderAPI/src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider_PlaceholderAPI.java",
    "content": "package com.bgsoftware.superiorskyblock.external.placeholders;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl;\nimport me.clip.placeholderapi.PlaceholderAPI;\nimport me.clip.placeholderapi.expansion.PlaceholderExpansion;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.entity.Player;\n\n@SuppressWarnings(\"unused\")\npublic class PlaceholdersProvider_PlaceholderAPI implements PlaceholdersProvider {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public PlaceholdersProvider_PlaceholderAPI(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        new EZPlaceholder((PlaceholdersServiceImpl) plugin.getServices().getService(PlaceholdersService.class)).register();\n\n        Log.info(\"Using PlaceholderAPI for placeholders support.\");\n    }\n\n    @Override\n    public String parsePlaceholders(OfflinePlayer offlinePlayer, String value) {\n        return PlaceholderAPI.setPlaceholders(offlinePlayer, value);\n    }\n\n    private class EZPlaceholder extends PlaceholderExpansion {\n\n        private final PlaceholdersServiceImpl placeholdersService;\n\n        public EZPlaceholder(PlaceholdersServiceImpl placeholdersService) {\n            this.placeholdersService = placeholdersService;\n        }\n\n        @Override\n        public String getIdentifier() {\n            return \"superior\";\n        }\n\n        @Override\n        public String getAuthor() {\n            return \"Ome_R\";\n        }\n\n        @Override\n        public String getVersion() {\n            return plugin.getDescription().getVersion();\n        }\n\n        @Override\n        public boolean persist() {\n            return true;\n        }\n\n        @Override\n        public String onRequest(OfflinePlayer player, String placeholder) {\n            return placeholdersService.handlePluginPlaceholder(player, placeholder);\n        }\n\n        @Override\n        public String onPlaceholderRequest(Player player, String placeholder) {\n            return onRequest(player, placeholder);\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Plan/build.gradle",
    "content": "group 'Hooks:Plan'\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(8)\n    }\n}\n\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n\ndependencies {\n    compileOnly project(\":API\")\n    compileOnly rootProject\n    compileOnly 'org.spigotmc:v1_8_R3-Taco:latest'\n    compileOnly 'com.github.plan-player-analytics:Plan:5.7.3232'\n}\n\nif (project.hasProperty('hook.compile_plan') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_plan\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.djrapitops.plan.capability.CapabilityService;\nimport com.djrapitops.plan.extension.DataExtension;\nimport com.djrapitops.plan.extension.ExtensionService;\nimport com.djrapitops.plan.extension.annotation.NumberProvider;\nimport com.djrapitops.plan.extension.annotation.PluginInfo;\nimport com.djrapitops.plan.extension.annotation.TableProvider;\nimport com.djrapitops.plan.extension.icon.Color;\nimport com.djrapitops.plan.extension.icon.Icon;\nimport com.djrapitops.plan.extension.table.Table;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class PlanHook {\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        try {\n            Log.info(\"Plan detected - attempting to register SuperiorSkyblock DataExtension.\");\n\n            if (CapabilityService.getInstance().hasCapability(\"DATA_EXTENSION_VALUES\")) {\n                ExtensionService.getInstance().register(new PlanDataExtension(plugin));\n                Log.info(\"Registered SuperiorSkyblock Plan DataExtension.\");\n            } else {\n                Log.warn(\"Plan installed but DataExtension capability not available - skipping registration.\");\n            }\n        } catch (Throwable t) {\n            Log.error(t, \"Failed to initialize Plan integration:\");\n        }\n    }\n\n    private PlanHook() {\n    }\n\n    @PluginInfo(name = \"SuperiorSkyblock\")\n    private static class PlanDataExtension implements DataExtension {\n\n        private final SuperiorSkyblockPlugin plugin;\n\n        PlanDataExtension(SuperiorSkyblockPlugin plugin) {\n            this.plugin = plugin;\n        }\n\n        @NumberProvider(\n                text = \"Total Islands\",\n                description = \"Total number of islands on the server\",\n                priority = 100\n        )\n        public long islandCount() {\n            return plugin.getGrid().getIslandsContainer().getIslandsAmount();\n        }\n\n        @NumberProvider(\n                text = \"Total Island Level\",\n                description = \"Sum of all island levels\",\n                priority = 90\n        )\n        public long totalLevel() {\n            return plugin.getGrid().getTotalLevel().toBigInteger().longValue();\n        }\n\n        @NumberProvider(\n                text = \"Total Island Worth\",\n                description = \"Sum of all island worths\",\n                priority = 80\n        )\n        public long totalWorth() {\n            return plugin.getGrid().getTotalWorth().toBigInteger().longValue();\n        }\n\n        @NumberProvider(\n                text = \"Active Islands\",\n                description = \"Islands that currently have visitors\",\n                priority = 70\n        )\n        public long activeIslands() {\n            return plugin.getGrid().getIslands().stream()\n                    .filter(island -> !island.getIslandVisitors().isEmpty())\n                    .count();\n        }\n\n        @NumberProvider(\n                text = \"Islands With Bank Balance\",\n                description = \"Islands that have money in their bank\",\n                priority = 60\n        )\n        public long islandsWithBankBalance() {\n            return plugin.getGrid().getIslands().stream()\n                    .filter(island -> island.getIslandBank() != null\n                            && island.getIslandBank().getBalance().compareTo(BigDecimal.ZERO) > 0)\n                    .count();\n        }\n\n        @NumberProvider(\n                text = \"Average Island Level\",\n                description = \"Average level across all islands\",\n                priority = 50\n        )\n        public long averageIslandLevel() {\n            List<Island> islands = plugin.getGrid().getIslands();\n            if (islands.isEmpty())\n                return 0L;\n\n            BigDecimal sum = BigDecimal.ZERO;\n            int count = 0;\n            for (Island island : islands) {\n                BigDecimal lvl = island.getIslandLevel();\n                if (lvl != null) {\n                    sum = sum.add(lvl);\n                    count++;\n                }\n            }\n\n            if (count == 0)\n                return 0L;\n\n            return sum.divide(BigDecimal.valueOf(count), 0, plugin.getSettings().getIslandLevelRoundingMode())\n                    .toBigInteger().longValue();\n        }\n\n        @TableProvider(\n                tableColor = Color.GREEN\n        )\n        public Table topIslandsTable() {\n            List<Island> islands = plugin.getGrid().getIslands(SortingTypes.BY_WORTH);\n\n            Table.Factory table = Table.builder()\n                    .columnOne(\"Pos\", Icon.called(\"list-ol\").build())\n                    .columnTwo(\"Owner\", Icon.called(\"user\").build())\n                    .columnThree(\"Island\", Icon.called(\"home\").build())\n                    .columnFour(\"Level\", Icon.called(\"star\").build())\n                    .columnFive(\"Worth\", Icon.called(\"coins\").build());\n\n            int pos = 1;\n            for (Island island : islands) {\n                if (pos > 25)\n                    break;\n\n                BigDecimal worth = island.getWorth();\n                BigDecimal level = island.getIslandLevel();\n                String ownerName = island.getOwner() == null ? \"\" : island.getOwner().getName();\n                String islandName = island.getName() == null || island.getName().isEmpty() ? ownerName : island.getName();\n\n                table.addRow(pos, ownerName, islandName,\n                        level == null ? 0L : level.toBigInteger().longValue(),\n                        worth == null ? 0L : worth.toBigInteger().longValue()\n                );\n\n                pos++;\n            }\n\n            return table.build();\n        }\n    }\n}"
  },
  {
    "path": "Hooks/ProtocolLib/build.gradle",
    "content": "group 'Hooks:ProtocolLib'\n\ndependencies {\n    compileOnly \"com.comphenix.protocol:ProtocolLib:4.8.0\"\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_protocollib') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_protocollib\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.comphenix.protocol.PacketType;\nimport com.comphenix.protocol.ProtocolLibrary;\nimport com.comphenix.protocol.ProtocolManager;\nimport com.comphenix.protocol.events.PacketAdapter;\nimport com.comphenix.protocol.events.PacketContainer;\nimport com.comphenix.protocol.events.PacketEvent;\n\nimport java.util.Locale;\n\npublic class ProtocolLibHook {\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        ProtocolLibHook.plugin = plugin;\n        ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();\n        protocolManager.addPacketListener(new ChangePlayerLanguageListener(plugin));\n    }\n\n    private static class ChangePlayerLanguageListener extends PacketAdapter {\n\n        private ChangePlayerLanguageListener(SuperiorSkyblockPlugin plugin) {\n            super(plugin, PacketType.Play.Client.SETTINGS);\n        }\n\n        @Override\n        public void onPacketReceiving(PacketEvent event) {\n            if (!ProtocolLibHook.plugin.getSettings().isAutoLanguageDetection() || event.getPlayer() == null ||\n                    event.isPlayerTemporary())\n                return;\n\n            PacketContainer packetContainer = event.getPacket();\n            Locale newPlayerLocale;\n\n            try {\n                newPlayerLocale = PlayerLocales.getLocale(packetContainer.getStrings().read(0));\n            } catch (Throwable error) {\n                return;\n            }\n\n            SuperiorPlayer superiorPlayer = ProtocolLibHook.plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(event.getPlayer().getUniqueId());\n            if (superiorPlayer != null && PlayerLocales.isValidLocale(newPlayerLocale) &&\n                    !superiorPlayer.getUserLocale().equals(newPlayerLocale)) {\n                if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, newPlayerLocale))\n                    superiorPlayer.setUserLocale(newPlayerLocale);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/PvpingSpawners/build.gradle",
    "content": "group 'Hooks:PvpingSpawners'\n\ndependencies {\n    compileOnly 'skyblock.hassan:PvpingSpawners:1.3'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_pvpingspawners') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_pvpingspawners\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.block.CreatureSpawner;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport skyblock.hassan.plugin.Main;\nimport skyblock.hassan.plugin.api.SpawnerStackEvent;\nimport skyblock.hassan.plugin.api.SpawnerUnstackEvent;\nimport skyblock.hassan.plugin.spawners.StackedSpawner;\n\npublic class SpawnersProvider_PvpingSpawners implements SpawnersProviderItemMetaSpawnerType {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final Main main;\n\n    public SpawnersProvider_PvpingSpawners(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        main = (Main) Bukkit.getPluginManager().getPlugin(\"PvpingSpawners\");\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using PvpingSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        if (Bukkit.isPrimaryThread()) {\n            StackedSpawner stackedSpawner = main.getProps().getStackedSpawner(main, (CreatureSpawner) location.getBlock().getState());\n            blockCount = stackedSpawner.getSize();\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerStackEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle());\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(spawnerLocation));\n                if (island != null)\n                    island.handleBlockPlace(spawnerLocation.getBlock(), e.getSpawnerAmount());\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerUnstackEvent e) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle());\n                Island island = plugin.getGrid().getIslandAt(spawnerLocation);\n                if (island != null)\n                    island.handleBlockBreak(spawnerLocation.getBlock(), e.getSpawnerAmount());\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/RoseStacker/build.gradle",
    "content": "group 'Hooks:RoseStacker'\n\ndependencies {\n    compileOnly 'dev.rosewood:RoseStacker:1.4.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_rosestacker') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_rosestacker\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.entities;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport dev.rosewood.rosestacker.api.RoseStackerAPI;\nimport dev.rosewood.rosestacker.stack.StackedEntity;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.entity.EntityDeathEvent;\n\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\npublic class EntitiesProvider_RoseStacker implements EntitiesProvider {\n\n    private final AutoRemovalCollection<UUID> stackedEntityDeaths = AutoRemovalCollection.newHashSet(5, TimeUnit.SECONDS);\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public EntitiesProvider_RoseStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n\n        plugin.getServer().getPluginManager().registerEvents(new DeathListener(), plugin);\n    }\n\n    @Override\n    public boolean shouldTrackEntity(Entity entity) {\n        return !stackedEntityDeaths.contains(entity.getUniqueId());\n    }\n\n    private class DeathListener implements Listener {\n\n        @EventHandler\n        public void onEntityDeath(EntityDeathEvent e) {\n            if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) ||\n                    !BukkitEntities.canHaveLimit(e.getEntityType()) ||\n                    BukkitEntities.canBypassEntityLimit(e.getEntity(), false))\n                return;\n\n            StackedEntity stackedEntity = RoseStackerAPI.getInstance().getStackedEntity(e.getEntity());\n            if (stackedEntity == null || stackedEntity.getStackSize() <= 1)\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            stackedEntityDeaths.add(e.getEntity().getUniqueId());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport dev.rosewood.rosestacker.api.RoseStackerAPI;\nimport dev.rosewood.rosestacker.event.SpawnerStackEvent;\nimport dev.rosewood.rosestacker.event.SpawnerUnstackEvent;\nimport dev.rosewood.rosestacker.stack.StackedSpawner;\nimport dev.rosewood.rosestacker.utils.ItemUtils;\nimport dev.rosewood.rosestacker.utils.StackerUtils;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.inventory.ItemStack;\n\npublic class SpawnersProvider_RoseStacker implements SpawnersProvider_AutoDetect {\n\n    private static final ReflectMethod<EntityType> GET_STACKED_ITEM_ENTITY_TYPE =\n            new ReflectMethod<>(StackerUtils.class, \"getStackedItemEntityType\", ItemStack.class);\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_RoseStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using RoseStacker as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n\n        if (Bukkit.isPrimaryThread()) {\n            StackedSpawner stackedSpawner = RoseStackerAPI.getInstance().getStackedSpawner(location.getBlock());\n            blockCount = stackedSpawner == null ? 1 : stackedSpawner.getStackSize();\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        EntityType entityType = GET_STACKED_ITEM_ENTITY_TYPE.isValid() ?\n                GET_STACKED_ITEM_ENTITY_TYPE.invoke(null, itemStack) : ItemUtils.getStackedItemEntityType(itemStack);\n        return entityType == null ? null : entityType.name();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerStackEvent e) {\n            Location location = e.getStack().getLocation();\n            Island island = plugin.getGrid().getIslandAt(location);\n            if (island != null) {\n                Key blockKey = Keys.of(e.getStack().getBlock());\n\n                int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ?\n                        e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount();\n                int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount;\n\n                if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) {\n                    e.setCancelled(true);\n                } else {\n                    island.handleBlockPlace(blockKey, newBlocksCount);\n                }\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerUnstackEvent e) {\n            Location location = e.getStack().getLocation();\n            Island island = plugin.getGrid().getIslandAt(location);\n            if (island != null) {\n                island.handleBlockBreak(Keys.of(e.getStack().getBlock()), e.getDecreaseAmount());\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.google.common.base.Preconditions;\nimport dev.rosewood.rosestacker.api.RoseStackerAPI;\nimport dev.rosewood.rosestacker.event.BlockStackEvent;\nimport dev.rosewood.rosestacker.event.BlockUnstackEvent;\nimport dev.rosewood.rosestacker.stack.StackedBlock;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerInteractEvent;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class StackedBlocksProvider_RoseStacker implements StackedBlocksProvider_AutoDetect {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final LazyReference<RegionManagerService> protectionManager = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public StackedBlocksProvider_RoseStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using RoseStacker as a stacked-blocks provider.\");\n    }\n\n    @Override\n    public Collection<Pair<Key, Integer>> getBlocks(World world, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n\n        if (!Bukkit.isPrimaryThread())\n            return null;\n\n        Map<Key, Integer> blockKeys = new HashMap<>();\n\n        try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ);\n             ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            RoseStackerAPI.getInstance().getStackedBlocks().entrySet().stream()\n                    .filter(entry ->\n                            chunkPosition.isInsideChunk(entry.getKey().getLocation(wrapper.getHandle())))\n                    .forEach(entry -> {\n                        Key blockKey = Key.of(entry.getKey());\n                        blockKeys.put(blockKey, blockKeys.getOrDefault(blockKey, 0) + entry.getValue().getStackSize());\n                    });\n        }\n\n        return blockKeys.entrySet().stream()\n                .map(entry -> new Pair<>(entry.getKey(), entry.getValue()))\n                .collect(Collectors.toSet());\n    }\n\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBlockStack(BlockStackEvent e) {\n            Location location = e.getStack().getLocation();\n            Island island = plugin.getGrid().getIslandAt(location);\n\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.of(e.getStack().getBlock());\n\n            int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ?\n                    e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount();\n            int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount;\n\n            if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, newBlocksCount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBlockUnstack(BlockUnstackEvent e) {\n            Location location = e.getStack().getLocation();\n            Island island = plugin.getGrid().getIslandAt(location);\n            if (island != null) {\n                island.handleBlockBreak(e.getStack().getBlock(), e.getDecreaseAmount());\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onBlockStackProtection(BlockStackEvent e) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n            InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getStack().getBlock());\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n                e.setCancelled(true);\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onBlockUnstackProtection(BlockUnstackEvent e) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n            InteractionResult interactionResult = protectionManager.get().handleBlockBreak(superiorPlayer, e.getStack().getBlock());\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n                e.setCancelled(true);\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onBlockStackInteractionProtection(PlayerInteractEvent e) {\n            if (e.getClickedBlock() == null || e.getPlayer().isSneaking())\n                return;\n\n            StackedBlock stackedBlock = RoseStackerAPI.getInstance().getStackedBlock(e.getClickedBlock());\n            if (stackedBlock == null)\n                return;\n\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n            InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getClickedBlock());\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n                e.setCancelled(true);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SkinsRestorer/build.gradle",
    "content": "group 'Hooks:SkinsRestorer'\n\ndependencies {\n    compileOnly 'net.skinsrestorer:SkinsRestorer:13.7.5'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_skinsrestorer') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_skinsrestorer\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.mojang.authlib.properties.Property;\nimport skinsrestorer.bukkit.SkinsRestorer;\nimport skinsrestorer.shared.exception.SkinRequestException;\nimport skinsrestorer.shared.storage.SkinStorage;\n\n@SuppressWarnings(\"unused\")\npublic class SkinsRestorerHook {\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        SkinsRestorerHook.plugin = plugin;\n        plugin.getProviders().registerSkinsListener(SkinsRestorerHook::setSkinTexture);\n    }\n\n    private static void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer));\n    }\n\n    private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) {\n        Property property = getSkin(superiorPlayer);\n        if (property != null)\n            BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property));\n    }\n\n    public static Property getSkin(SuperiorPlayer superiorPlayer) {\n        try {\n            SkinStorage skinStorage = SkinsRestorer.getInstance().getSkinStorage();\n            return (Property) skinStorage.getOrCreateSkinForPlayer(superiorPlayer.getName(), true);\n        } catch (SkinRequestException | NullPointerException ignored) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SkinsRestorer14/build.gradle",
    "content": "group 'Hooks:SkinsRestorer14'\n\ndependencies {\n    compileOnly 'net.skinsrestorer:SkinsRestorer:14.1.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_skinsrestorer') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_skinsrestorer\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.mojang.authlib.properties.Property;\nimport net.skinsrestorer.api.SkinsRestorerAPI;\nimport net.skinsrestorer.api.bukkit.events.SkinApplyBukkitEvent;\nimport net.skinsrestorer.api.property.IProperty;\nimport net.skinsrestorer.shared.storage.Config;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.java.JavaPlugin;\n\nimport java.io.File;\nimport java.nio.file.Path;\n\npublic class SkinsRestorer14Hook {\n\n    private static final ReflectMethod<Object> SKINS_RESTORER_GET_SKIN = new ReflectMethod<>(SkinsRestorerAPI.class, \"getSkinData\", String.class);\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static boolean isCompatible() {\n        if (Config.MYSQL_ENABLED)\n            return true;\n\n        ReflectField<Object> skinsFolderMethod = new ReflectField<>(net.skinsrestorer.shared.storage.SkinStorage.class,\n                Object.class, \"skinsFolder\");\n\n        if (!skinsFolderMethod.isValid())\n            return false;\n\n        net.skinsrestorer.bukkit.SkinsRestorer skinsRestorer = JavaPlugin.getPlugin(net.skinsrestorer.bukkit.SkinsRestorer.class);\n        Object skinsFolder = skinsFolderMethod.get(skinsRestorer.getSkinStorage());\n\n        if (skinsFolder instanceof File) {\n            return ((File) skinsFolder).exists();\n        } else if (skinsFolder instanceof Path) {\n            return ((Path) skinsFolder).toFile().exists();\n        }\n\n        return false;\n    }\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        SkinsRestorer14Hook.plugin = plugin;\n\n        plugin.getProviders().registerSkinsListener(SkinsRestorer14Hook::setSkinTexture);\n        plugin.getServer().getPluginManager().registerEvents(new SkinsListener(), plugin);\n    }\n\n    private static void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer));\n    }\n\n    private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) {\n        Property property = getSkin(superiorPlayer);\n        if (property != null)\n            BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property));\n    }\n\n    private static Property getSkin(SuperiorPlayer superiorPlayer) {\n        IProperty property;\n        try {\n            property = SkinsRestorerAPI.getApi().getSkinData(superiorPlayer.getName());\n        } catch (Throwable ex) {\n            property = (IProperty) SKINS_RESTORER_GET_SKIN.invoke(SkinsRestorerAPI.getApi(), superiorPlayer.getName());\n        }\n\n        if (property == null)\n            return null;\n\n        if (property instanceof Property)\n            return ((Property) property);\n\n        Object propertyHandle = property.getHandle();\n\n        return propertyHandle instanceof Property ? ((Property) propertyHandle) : null;\n    }\n\n    private static class SkinsListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSkinApply(SkinApplyBukkitEvent event) {\n            if (event.getProperty() instanceof Property) {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getWho());\n                plugin.getNMSPlayers().setSkinTexture(superiorPlayer, (Property) event.getProperty());\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SkinsRestorer15/build.gradle",
    "content": "group 'Hooks:SkinsRestorer15'\n\ndependencies {\n    compileOnly 'net.skinsrestorer:SkinsRestorer:15.0.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_skinsrestorer') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_skinsrestorer\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.mojang.authlib.properties.Property;\nimport net.skinsrestorer.api.SkinsRestorer;\nimport net.skinsrestorer.api.SkinsRestorerProvider;\nimport net.skinsrestorer.api.event.SkinApplyEvent;\nimport net.skinsrestorer.api.exception.DataRequestException;\nimport net.skinsrestorer.api.property.SkinProperty;\nimport org.bukkit.entity.Player;\n\nimport java.util.function.Consumer;\n\npublic class SkinsRestorer15Hook {\n\n    private static SuperiorSkyblockPlugin plugin;\n    private static SkinsRestorer skinsRestorer;\n\n    public static boolean isCompatible() {\n        try {\n            SkinsRestorer skinsRestorer = SkinsRestorerProvider.get();\n            return skinsRestorer != null;\n        } catch (IllegalStateException error) {\n            return false;\n        }\n    }\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        SkinsRestorer15Hook.plugin = plugin;\n        skinsRestorer = SkinsRestorerProvider.get();\n\n        plugin.getProviders().registerSkinsListener(SkinsRestorer15Hook::setSkinTexture);\n        skinsRestorer.getEventBus().subscribe(plugin, SkinApplyEvent.class, new SkinsListener());\n    }\n\n    private static void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer));\n    }\n\n    private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) {\n        Property property = getSkin(superiorPlayer);\n        if (property != null)\n            BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property));\n    }\n\n    private static Property getSkin(SuperiorPlayer superiorPlayer) {\n        SkinProperty skinProperty;\n\n        try {\n            skinProperty = skinsRestorer.getPlayerStorage().getSkinForPlayer(superiorPlayer.getUniqueId(),\n                    superiorPlayer.getName()).orElse(null);\n        } catch (DataRequestException error) {\n            return null;\n        }\n\n        if (skinProperty == null)\n            return null;\n\n        return new Property(\"\", skinProperty.getValue(), skinProperty.getSignature());\n    }\n\n    private static class SkinsListener implements Consumer<SkinApplyEvent> {\n\n        @Override\n        public void accept(SkinApplyEvent event) {\n            Object playerObject = event.getPlayer(Object.class);\n\n            if (!(playerObject instanceof Player))\n                return;\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) playerObject);\n\n            Property property = new Property(\"\", event.getProperty().getValue(), event.getProperty().getSignature());\n\n            plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SlimeWorldManager/build.gradle",
    "content": "group 'Hooks:SlimeWorldManager'\n\ndependencies {\n    compileOnly 'com.grinderwolf:SlimeWorldManager:2.2.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_slimeworldmanager') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_slimeworldmanager\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SlimeWorldManager/src/main/java/com/bgsoftware/superiorskyblock/external/SlimeWorldManagerHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.grinderwolf.swm.api.SlimePlugin;\nimport com.grinderwolf.swm.plugin.config.ConfigManager;\nimport com.grinderwolf.swm.plugin.config.WorldData;\nimport org.bukkit.Bukkit;\nimport org.bukkit.plugin.Plugin;\n\n@SuppressWarnings(\"unused\")\npublic class SlimeWorldManagerHook {\n\n    private static Plugin slimeWorldPlugin = null;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        slimeWorldPlugin = Bukkit.getPluginManager().getPlugin(\"SlimeWorldManager\");\n        plugin.getProviders().registerWorldsListener(SlimeWorldManagerHook::loadWorld);\n    }\n\n    private static void loadWorld(String worldName) {\n        SlimePlugin slimePlugin = (SlimePlugin) slimeWorldPlugin;\n\n        WorldData worldData = ConfigManager.getWorldConfig().getWorlds().get(worldName);\n\n        if (worldData == null)\n            return;\n\n        try {\n            slimePlugin.getLoader(worldData.getDataSource()).loadWorld(worldName, false);\n        } catch (Exception ignored) {\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Slimefun/ProtectionModule_Dev999/build.gradle",
    "content": "group 'ProtectionModule_Dev999'\n\ndependencies {\n    compileOnly 'me.mrcookieslime:Slimefun:4.Dev999'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_slimefun') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_slimefun\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Slimefun/ProtectionModule_Dev999/src/main/java/com/bgsoftware/superiorskyblock/external/slimefun/ProtectionModule_Dev999.java",
    "content": "package com.bgsoftware.superiorskyblock.external.slimefun;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport io.github.thebusybiscuit.slimefun4.implementation.Slimefun;\nimport io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction;\nimport io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionManager;\nimport io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionModule;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.Server;\nimport org.bukkit.plugin.Plugin;\n\nimport java.util.function.Function;\n\npublic class ProtectionModule_Dev999 {\n\n    private static final ReflectMethod<Void> OLD_REGISTER_MODULE = new ReflectMethod<>(ProtectionManager.class,\n            \"registerModule\", Server.class, String.class, Function.class);\n\n    private ProtectionModule_Dev999() {\n    }\n\n    public static void register(Plugin plugin, PermissionCheck permissionCheck) {\n        new ProtectionModuleImpl(plugin, permissionCheck).register();\n    }\n\n    private static class ProtectionModuleImpl implements ProtectionModule {\n\n        private final Plugin plugin;\n        private final PermissionCheck permissionCheck;\n\n        ProtectionModuleImpl(Plugin plugin, PermissionCheck permissionCheck) {\n            this.plugin = plugin;\n            this.permissionCheck = permissionCheck;\n        }\n\n        @Override\n        public void load() {\n            // Do nothing.\n        }\n\n        @Override\n        public Plugin getPlugin() {\n            return plugin;\n        }\n\n        @Override\n        public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, Interaction interaction) {\n            return this.permissionCheck.checkPermission(offlinePlayer, location, interaction.name());\n        }\n\n        void register() {\n            BukkitExecutor.sync(() -> {\n                if (OLD_REGISTER_MODULE.isValid()) {\n                    OLD_REGISTER_MODULE.invoke(Slimefun.getProtectionManager(), Bukkit.getServer(), plugin.getName(),\n                            (Function<Plugin, ProtectionModule>) pl -> this);\n                } else {\n                    Slimefun.getProtectionManager().registerModule(Bukkit.getServer().getPluginManager(),\n                            plugin.getName(), pl -> this);\n                }\n            }, 2L);\n        }\n\n    }\n\n    public interface PermissionCheck {\n\n        boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String permission);\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Slimefun/ProtectionModule_RC13/build.gradle",
    "content": "group 'ProtectionModule_RC13'\n\ndependencies {\n    compileOnly 'me.mrcookieslime:Slimefun:4.RC13'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_slimefun') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_slimefun\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Slimefun/ProtectionModule_RC13/src/main/java/com/bgsoftware/superiorskyblock/external/slimefun/ProtectionModule_RC13.java",
    "content": "package com.bgsoftware.superiorskyblock.external.slimefun;\n\nimport me.mrCookieSlime.Slimefun.SlimefunPlugin;\nimport me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectableAction;\nimport me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectionModule;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.plugin.Plugin;\n\npublic class ProtectionModule_RC13 {\n\n    private ProtectionModule_RC13() {\n    }\n\n    public static void register(Plugin plugin, PermissionCheck permissionCheck) {\n        new ProtectionModuleImpl(plugin, permissionCheck).register();\n    }\n\n    private static class ProtectionModuleImpl implements ProtectionModule {\n\n        private final Plugin plugin;\n        private final PermissionCheck permissionCheck;\n\n        ProtectionModuleImpl(Plugin plugin, PermissionCheck permissionCheck) {\n            this.plugin = plugin;\n            this.permissionCheck = permissionCheck;\n        }\n\n        @Override\n        public void load() {\n\n        }\n\n        @Override\n        public Plugin getPlugin() {\n            return plugin;\n        }\n\n        @Override\n        public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, ProtectableAction protectableAction) {\n            return permissionCheck.checkPermission(offlinePlayer, location, protectableAction.name());\n        }\n\n        void register() {\n            SlimefunPlugin.getProtectionManager().registerModule(Bukkit.getServer(), plugin.getName(), pl -> this);\n        }\n    }\n\n    public interface PermissionCheck {\n\n        boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String permission);\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Slimefun/build.gradle",
    "content": "group 'Hooks:Slimefun'\n\ndependencies {\n    compileOnly 'me.mrcookieslime:Slimefun:4.Dev744'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":Hooks:Slimefun:ProtectionModule_RC13\")\n    compileOnly project(\":Hooks:Slimefun:ProtectionModule_Dev999\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_slimefun') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_slimefun\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_Dev999;\nimport com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_RC13;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper;\nimport io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;\nimport io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent;\nimport io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;\nimport me.mrCookieSlime.Slimefun.api.BlockStorage;\nimport me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectableAction;\nimport me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectionModule;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.Plugin;\n\npublic class SlimefunHook {\n\n    @WorldRecordFlags\n    private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n\n    private static final ReflectMethod<Void> BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD = new ReflectMethod<>(\n            BlockStorage.class, \"clearAllBlockInfoAtChunk\", World.class, int.class, int.class, boolean.class);\n\n    private static final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n    private static final LazyReference<StackedBlocksInteractionService> stackedBlocksInteractionService = new LazyReference<StackedBlocksInteractionService>() {\n        @Override\n        protected StackedBlocksInteractionService create() {\n            return plugin.getServices().getService(StackedBlocksInteractionService.class);\n        }\n    };\n    private static SuperiorSkyblockPlugin plugin;\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        SlimefunHook.plugin = plugin;\n\n        if (isClassLoaded(\"me.mrCookieSlime.Slimefun.SlimefunPlugin\")) {\n            ProtectionModule_RC13.register(plugin, SlimefunHook::checkPermission);\n        } else if (isClassLoaded(\"io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionModule\")) {\n            ProtectionModule_Dev999.register(plugin, SlimefunHook::checkPermission);\n        } else if (isClassLoaded(\"io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin\")) {\n            // Dev 744 version, which is the one we use here.\n            new ProtectionModuleImpl(plugin).register();\n        }\n\n        plugin.getServer().getPluginManager().registerEvents(new AndroidMineListener(), plugin);\n\n        if (isClassLoaded(\"io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent\"))\n            plugin.getServer().getPluginManager().registerEvents(new AutoPlacerPlaceListener(), plugin);\n\n        if (BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.isValid())\n            plugin.getServer().getPluginManager().registerEvents(new ChunkWipeListener(), plugin);\n    }\n\n    private static boolean isClassLoaded(String clazz) {\n        try {\n            Class.forName(clazz);\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }\n\n    private static boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String protectableAction) {\n        Island island = plugin.getGrid().getIslandAt(location);\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(offlinePlayer.getUniqueId());\n\n        if (!plugin.getGrid().isIslandsWorld(location.getWorld()))\n            return true;\n\n        if (protectableAction.equals(\"PVP\") || protectableAction.equals(\"ATTACK_PLAYER\"))\n            return island != null && island.hasSettingsEnabled(IslandFlags.PVP);\n\n        IslandPrivilege islandPrivilege;\n\n        switch (protectableAction) {\n            case \"BREAK_BLOCK\":\n                islandPrivilege = IslandPrivileges.BREAK;\n                break;\n            case \"PLACE_BLOCK\":\n                islandPrivilege = IslandPrivileges.BUILD;\n                break;\n            case \"ACCESS_INVENTORIES\":\n            case \"INTERACT_BLOCK\":\n                islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(ConstantKeys.CHEST);\n                break;\n            default:\n                islandPrivilege = IslandPrivileges.BREAK;\n                break;\n        }\n\n        return island != null && islandPrivilege != null && island.hasPermission(superiorPlayer, islandPrivilege);\n    }\n\n    private static class AndroidMineListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onAndroidMiner(AndroidMineEvent e) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Log.debug(Debug.BLOCK_BREAK, e.getBlock().getLocation(wrapper.getHandle()), e.getBlock().getType());\n            }\n\n            InteractionResult interactionResult = stackedBlocksInteractionService.get()\n                    .handleStackedBlockBreak(e.getBlock(), null);\n            if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) {\n                e.setCancelled(true);\n            } else {\n                worldRecordService.get().recordBlockBreak(e.getBlock(), REGULAR_RECORD_FLAGS);\n            }\n        }\n\n    }\n\n    private static class AutoPlacerPlaceListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onAutoPlacerPlaceBlock(BlockPlacerPlaceEvent e) {\n            worldRecordService.get().recordBlockPlace(e.getBlock(), 1, null, REGULAR_RECORD_FLAGS);\n        }\n\n    }\n\n    private static class ChunkWipeListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onChunkWipe(IslandChunkResetEvent e) {\n            BukkitExecutor.async(() -> {\n                // Might be unsafe to call async. Should fix:\n                // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2474\n                BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.invoke(null, e.getWorld(), e.getChunkX(), e.getChunkZ(), true);\n            });\n        }\n\n    }\n\n    private static class ProtectionModuleImpl implements ProtectionModule {\n\n        private final Plugin plugin;\n\n        ProtectionModuleImpl(Plugin plugin) {\n            this.plugin = plugin;\n        }\n\n        @Override\n        public void load() {\n\n        }\n\n        @Override\n        public Plugin getPlugin() {\n            return plugin;\n        }\n\n        @Override\n        public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, ProtectableAction protectableAction) {\n            return checkPermission(offlinePlayer, location, protectableAction.name());\n        }\n\n        void register() {\n            SlimefunPlugin.getProtectionManager().registerModule(Bukkit.getServer(), plugin.getName(), pl -> this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SmoothTimber/build.gradle",
    "content": "group 'Hooks:SmoothTimber'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(11))\n    }\n}\n\ndependencies {\n    compileOnly 'com.syntaxphoenix:SmoothTimber:1.27.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_smoothtimber') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_smoothtimber\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SmoothTimber/src/main/java/com/bgsoftware/superiorskyblock/external/SmoothTimberHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.syntaxphoenix.spigot.smoothtimber.event.AsyncPlayerChopTreeEvent;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class SmoothTimberHook {\n\n    private static SuperiorSkyblockPlugin plugin;\n    private static final LazyReference<RegionManagerService> protectionManager = new LazyReference<>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        SmoothTimberHook.plugin = plugin;\n        plugin.getServer().getPluginManager().registerEvents(new ChopListener(), plugin);\n    }\n\n    private static class ChopListener implements Listener {\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onChopEvent(AsyncPlayerChopTreeEvent e) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n            InteractionResult interactionResult = protectionManager.get().handleBlockBreak(superiorPlayer, e.getTreeLocation().getBlock());\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n                e.getBlockLocations().clear();\n                return;\n            }\n\n            Island island = plugin.getGrid().getIslandAt(e.getTreeLocation());\n            if (island != null)\n                e.getBlockLocations().removeIf(location -> !island.isInsideRange(location));\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onChopEventMonitor(AsyncPlayerChopTreeEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getTreeLocation());\n\n            if (island == null)\n                return;\n\n            e.getBlockLocations().forEach(location -> island.handleBlockBreak(Keys.of(location.getBlock())));\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/SuperVanish/build.gradle",
    "content": "group 'Hooks:SuperVanish'\n\ndependencies {\n    compileOnly 'de.myzelyam:SuperVanish:6.1.6'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_supervanish') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_supervanish\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java",
    "content": "package com.bgsoftware.superiorskyblock.external.vanish;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications;\nimport de.myzelyam.api.vanish.PlayerVanishStateChangeEvent;\nimport de.myzelyam.api.vanish.VanishAPI;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class VanishProvider_SuperVanish implements VanishProvider, Listener {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public VanishProvider_SuperVanish(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(this, plugin);\n        Log.info(\"Hooked into SuperVanish for support of vanish status of players.\");\n    }\n\n    @Override\n    public boolean isVanished(Player player) {\n        return VanishAPI.isInvisible(player);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerVanish(PlayerVanishStateChangeEvent e) {\n        if (e.isVanishing()) {\n            IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getUUID()));\n        } else {\n            IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getUUID()));\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/TimbruSilkSpawners/build.gradle",
    "content": "group 'Hooks:TimbruSilkSpawners'\n\ndependencies {\n    compileOnly 'de.dustplanet:SilkSpawners:6.0.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_timbrusilkspawners') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_timbrusilkspawners\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport de.dustplanet.silkspawners.events.SilkSpawnersSpawnerChangeEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\nimport java.util.Locale;\n\npublic class TimbruSilkSpawnersHook {\n\n    public static void register(SuperiorSkyblockPlugin plugin) {\n        Bukkit.getPluginManager().registerEvents(new SpawnersListener(plugin), plugin);\n    }\n\n    private TimbruSilkSpawnersHook() {\n\n    }\n\n    private static class SpawnersListener implements Listener {\n\n        private final SuperiorSkyblockPlugin plugin;\n\n        SpawnersListener(SuperiorSkyblockPlugin plugin) {\n            this.plugin = plugin;\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerChange(SilkSpawnersSpawnerChangeEvent e) {\n            EntityType oldEntity = EnumHelper.getEnum(EntityType.class, e.getOldEntityID().toUpperCase(Locale.ENGLISH));\n            EntityType newEntity = EnumHelper.getEnum(EntityType.class, e.getEntityID().toUpperCase(Locale.ENGLISH));\n\n            if (oldEntity == null || newEntity == null || oldEntity == newEntity)\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            island.handleBlockBreak(Keys.ofSpawner(oldEntity), 1);\n            island.handleBlockPlace(Keys.ofSpawner(newEntity), 1);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport de.dustplanet.util.SilkUtil;\nimport org.bukkit.Location;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class SpawnersProvider_TimbruSilkSpawners implements SpawnersProvider_AutoDetect {\n\n    private final SilkUtil silkUtil;\n\n    public SpawnersProvider_TimbruSilkSpawners() {\n        this.silkUtil = SilkUtil.hookIntoSilkSpanwers();\n        Log.info(\"Using SilkSpawners as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return new Pair<>(1, null);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n        String entityId = this.silkUtil.getStoredSpawnerItemEntityID(itemStack);\n\n        if (entityId != null) {\n            EntityType entityType = EnumHelper.getEnum(EntityType.class, entityId.toUpperCase(Locale.ENGLISH));\n            if (entityType != null)\n                return entityType.name();\n        }\n\n        return \"PIG\";\n    }\n\n}\n"
  },
  {
    "path": "Hooks/UltimateStacker/build.gradle",
    "content": "group 'Hooks:UltimateStacker'\n\ndependencies {\n    compileOnly 'com.songoda:UltimateStacker:2.1.7'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_ultimatestacker') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_ultimatestacker\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.google.common.base.Preconditions;\nimport com.songoda.ultimatestacker.UltimateStacker;\nimport com.songoda.ultimatestacker.events.SpawnerBreakEvent;\nimport com.songoda.ultimatestacker.events.SpawnerPlaceEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class SpawnersProvider_UltimateStacker implements SpawnersProviderItemMetaSpawnerType {\n\n    private final UltimateStacker instance = UltimateStacker.getInstance();\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_UltimateStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using UltimateStacker as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        if (Bukkit.isPrimaryThread()) {\n            blockCount = instance.getSpawnerStackManager().getSpawner(location).getAmount();\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawnerType());\n            int increaseAmount = e.getAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n            if (island != null)\n                island.handleBlockBreak(e.getBlock(), e.getAmount());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/UltimateStacker3/build.gradle",
    "content": "group 'Hooks:UltimateStacker3'\n\ndependencies {\n    compileOnly 'com.craftaro:UltimateStacker:3.0.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_ultimatestacker') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_ultimatestacker\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}\n"
  },
  {
    "path": "Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.craftaro.ultimatestacker.api.UltimateStackerApi;\nimport com.craftaro.ultimatestacker.api.events.spawner.SpawnerBreakEvent;\nimport com.craftaro.ultimatestacker.api.events.spawner.SpawnerPlaceEvent;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class SpawnersProvider_UltimateStacker3 implements SpawnersProviderItemMetaSpawnerType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_UltimateStacker3(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using UltimateStacker as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        if (Bukkit.isPrimaryThread()) {\n            blockCount = UltimateStackerApi.getSpawnerStackManager().getSpawner(location).getAmount();\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawnerType());\n            int increaseAmount = e.getAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n            if (island != null)\n                island.handleBlockBreak(e.getBlock(), e.getAmount());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/UltimateStacker4/build.gradle",
    "content": "group 'Hooks:UltimateStacker4'\n\ndependencies {\n    compileOnly 'com.songoda:UltimateStacker:4.3.0'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_ultimatestacker') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_ultimatestacker\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}\n"
  },
  {
    "path": "Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.google.common.base.Preconditions;\nimport com.songoda.ultimatestacker.api.UltimateStackerApi;\nimport com.songoda.ultimatestacker.api.events.spawner.SpawnerBreakEvent;\nimport com.songoda.ultimatestacker.api.events.spawner.SpawnerPlaceEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\npublic class SpawnersProvider_UltimateStacker4 implements SpawnersProviderItemMetaSpawnerType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SpawnersProvider_UltimateStacker4(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Log.info(\"Using UltimateStacker as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        int blockCount = -1;\n        if (Bukkit.isPrimaryThread()) {\n            blockCount = UltimateStackerApi.getSpawnerStackManager().getSpawner(location).getAmount();\n        }\n\n        return new Pair<>(blockCount, null);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.HIGHEST)\n        public void onSpawnerStack(SpawnerPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            Key blockKey = Key.ofSpawner(e.getSpawnerType());\n            int increaseAmount = e.getAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerBreakEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n            if (island != null)\n                island.handleBlockBreak(e.getBlock(), e.getAmount());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/VanishNoPacket/build.gradle",
    "content": "group 'Hooks:VanishNoPacket'\n\ndependencies {\n    compileOnly 'org.kitteh:VanishNoPacket:3.20.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_vanishnopacket') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_vanishnopacket\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java",
    "content": "package com.bgsoftware.superiorskyblock.external.vanish;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.java.JavaPlugin;\nimport org.kitteh.vanish.VanishPlugin;\nimport org.kitteh.vanish.event.VanishStatusChangeEvent;\n\npublic class VanishProvider_VanishNoPacket implements VanishProvider, Listener {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final VanishPlugin instance;\n\n    public VanishProvider_VanishNoPacket(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        this.instance = JavaPlugin.getPlugin(VanishPlugin.class);\n        Bukkit.getPluginManager().registerEvents(this, plugin);\n        Log.info(\"Hooked into VanishNoPacket for support of vanish status of players.\");\n    }\n\n    @Override\n    public boolean isVanished(Player player) {\n        return instance.getManager().isVanished(player);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerVanish(VanishStatusChangeEvent e) {\n        if (e.isVanishing()) {\n            IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getPlayer()));\n        } else {\n            IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getPlayer()));\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/Vault/build.gradle",
    "content": "group 'Hooks:Vault'\n\ndependencies {\n    compileOnly 'net.milkbowl:Vault:1.6.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_vault') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_vault\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/Vault/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Vault.java",
    "content": "package com.bgsoftware.superiorskyblock.external.economy;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Precision;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport net.milkbowl.vault.economy.Economy;\nimport net.milkbowl.vault.economy.EconomyResponse;\nimport org.bukkit.Bukkit;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.plugin.RegisteredServiceProvider;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\n\npublic class EconomyProvider_Vault implements EconomyProvider {\n\n    private static Economy econ;\n\n    public static boolean isCompatible() {\n        RegisteredServiceProvider<Economy> rsp = Bukkit.getServicesManager().getRegistration(Economy.class);\n        if (rsp != null)\n            econ = rsp.getProvider();\n\n        if (econ != null)\n            Log.info(\"Using Vault as an economy provider.\");\n\n        return econ != null;\n    }\n\n    @Override\n    public BigDecimal getBalance(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return BigDecimal.valueOf(getMoneyInBank(superiorPlayer.asOfflinePlayer()))\n                .setScale(3, RoundingMode.HALF_DOWN);\n    }\n\n    @Override\n    public EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n        double moneyBeforeDeposit = getMoneyInBank(offlinePlayer);\n        EconomyResponse economyResponse = econ.depositPlayer(offlinePlayer, amount);\n        double moneyInTransaction = Precision.round(getMoneyInBank(offlinePlayer) - moneyBeforeDeposit, 3);\n\n        String errorMessage = moneyInTransaction == amount ? getErrorMessageFromResponse(economyResponse) :\n                moneyInTransaction == 0 ? \"You have exceed the limit of your bank\" : \"\";\n\n        return new EconomyResult(errorMessage, moneyInTransaction);\n    }\n\n    @Override\n    public EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n        double moneyBeforeWithdraw = getMoneyInBank(offlinePlayer);\n        EconomyResponse economyResponse = econ.withdrawPlayer(offlinePlayer, amount);\n        double moneyInTransaction = Precision.round(moneyBeforeWithdraw - getMoneyInBank(offlinePlayer), 3);\n\n        String errorMessage = moneyInTransaction == amount ? getErrorMessageFromResponse(economyResponse) :\n                moneyInTransaction == 0 ? \"Couldn't process the transaction\" : \"\";\n\n        return new EconomyResult(errorMessage, moneyInTransaction);\n    }\n\n    private double getMoneyInBank(OfflinePlayer offlinePlayer) {\n        if (!econ.hasAccount(offlinePlayer))\n            econ.createPlayerAccount(offlinePlayer);\n\n        return Precision.round(econ.getBalance(offlinePlayer), 3);\n    }\n\n    @Nullable\n    private static String getErrorMessageFromResponse(EconomyResponse economyResponse) {\n        return economyResponse.transactionSuccess() ? null : economyResponse.errorMessage;\n    }\n\n}\n"
  },
  {
    "path": "Hooks/WildStacker/build.gradle",
    "content": "group 'Hooks:WildStacker'\n\ndependencies {\n    compileOnly 'com.bgsoftware:WildStackerAPI:3.6.1'\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('hook.compile_wildstacker') &&\n        !Boolean.valueOf(project.findProperty(\"hook.compile_wildstacker\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.wildstacker.api.WildStackerAPI;\nimport com.bgsoftware.wildstacker.api.objects.StackedSnapshot;\nimport org.bukkit.Chunk;\n\nimport java.util.function.Function;\n\npublic class WildStackerSnapshotsContainer {\n\n    private static final Synchronized<Chunk2ObjectMap<RefCount<StackedSnapshot>>> cachedSnapshots = Synchronized.of(new Chunk2ObjectMap<>());\n\n    private WildStackerSnapshotsContainer() {\n\n    }\n\n    public static void takeSnapshot(Chunk chunk) {\n        try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n            cachedSnapshots.write(cachedSnapshots ->\n                    takeSnapshotInternal(chunk, chunkPosition, cachedSnapshots));\n        }\n    }\n\n    private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition, Chunk2ObjectMap<RefCount<StackedSnapshot>> cachedSnapshots) {\n        RefCount<StackedSnapshot> refCountBase = cachedSnapshots.get(chunkPosition);\n        if (refCountBase != null) {\n            refCountBase.incRef();\n            return;\n        }\n\n        refCountBase = new RefCount<>();\n\n        try {\n            StackedSnapshot stackedSnapshot;\n\n            try {\n                stackedSnapshot = WildStackerAPI.getWildStacker().getSystemManager().getStackedSnapshot(chunk);\n            } catch (Throwable ex) {\n                //noinspection deprecation\n                stackedSnapshot = WildStackerAPI.getWildStacker().getSystemManager().getStackedSnapshot(chunk, false);\n            }\n\n            if (stackedSnapshot != null) {\n                refCountBase.set(stackedSnapshot);\n                cachedSnapshots.put(chunkPosition, refCountBase);\n            }\n        } catch (Throwable error) {\n            Log.error(error, \"Received an unexpected error while taking a snapshot for WildStacker:\");\n        }\n    }\n\n    public static void releaseSnapshot(ChunkPosition chunkPosition) {\n        cachedSnapshots.write(m -> {\n            RefCount<StackedSnapshot> refCountBase = m.get(chunkPosition);\n            if (refCountBase != null) {\n                if (refCountBase.defRef())\n                    m.remove(chunkPosition);\n            }\n        });\n    }\n\n    public static <R> R accessStackedSnapshot(ChunkPosition chunkPosition, Function<StackedSnapshot, R> function) {\n        return cachedSnapshots.readAndGet(cachedSnapshots -> {\n            RefCount<StackedSnapshot> refCountBase = cachedSnapshots.get(chunkPosition);\n            if (refCountBase == null)\n                return null;\n            return refCountBase.readAndGet(function);\n        });\n    }\n\n    private static class RefCount<T> {\n\n        private int refCount;\n        private Synchronized<T> handle;\n\n        synchronized void incRef() {\n            if (this.handle == null)\n                throw new IllegalStateException(\"Inc ref on null RefCount object \" + this);\n\n            int ref = this.handle.writeAndGet(unused -> {\n                return ++this.refCount;\n            });\n\n            if (ref <= 0)\n                throw new IllegalStateException(\"Inc ref on null RefCount object \" + this);\n        }\n\n        synchronized boolean defRef() {\n            if (this.handle == null)\n                throw new IllegalStateException(\"Dec ref on null RefCount object \" + this);\n\n            int ref = this.handle.writeAndGet(unused -> {\n                return --this.refCount;\n            });\n\n            if (ref == 0) {\n                this.handle = null;\n                return true;\n            } else if (ref < 0) {\n                throw new IllegalStateException(\"Dec ref on null RefCount object \" + this);\n            }\n\n            return false;\n        }\n\n        synchronized <R> R readAndGet(Function<T, R> function) {\n            if (this.handle == null)\n                throw new IllegalStateException(\"Access null RefCount object \" + this);\n\n            return this.handle.writeAndGet(handle -> {\n                if (this.refCount <= 0)\n                    throw new IllegalStateException(\"Access null RefCount object \" + this);\n\n                return function.apply(handle);\n            });\n        }\n\n        synchronized void set(T handle) {\n            this.handle = Synchronized.of(handle);\n            incRef();\n        }\n\n        @Override\n        public synchronized String toString() {\n            if (this.handle == null) {\n                return \"{ ref = \" + this.refCount + \", handle = \" + this.handle + \"}\";\n            } else {\n                return this.handle.readAndGet(handle -> {\n                    return \"{ ref = \" + this.refCount + \", handle = \" + handle + \"}\";\n                });\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersSnapshotProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer;\nimport com.bgsoftware.superiorskyblock.module.upgrades.listeners.WildStackerListener;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.bgsoftware.wildstacker.api.WildStackerAPI;\nimport com.bgsoftware.wildstacker.api.events.SpawnerPlaceEvent;\nimport com.bgsoftware.wildstacker.api.events.SpawnerPlaceInventoryEvent;\nimport com.bgsoftware.wildstacker.api.events.SpawnerStackEvent;\nimport com.bgsoftware.wildstacker.api.events.SpawnerUnstackEvent;\nimport com.bgsoftware.wildstacker.api.objects.StackedSpawner;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\n\nimport java.util.Map;\n\npublic class SpawnersProvider_WildStacker implements SpawnersProviderItemMetaSpawnerType, SpawnersSnapshotProvider {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final LazyReference<RegionManagerService> protectionManager = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public SpawnersProvider_WildStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n        Bukkit.getPluginManager().registerEvents(new WildStackerListener(), plugin);\n        Log.info(\"Using WildStacker as a spawners provider.\");\n    }\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        Map.Entry<Integer, EntityType> entry;\n        try (ChunkPosition chunkPosition = ChunkPosition.of(location)) {\n            entry = WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition,\n                    stackedSnapshot -> stackedSnapshot.getStackedSpawner(location));\n        }\n\n        if (entry == null) {\n            StackedSpawner stackedSpawner = WildStackerAPI.getWildStacker().getSystemManager().getStackedSpawner(location);\n            if (stackedSpawner == null) {\n                return new Pair<>(1, null);\n            } else {\n                return new Pair<>(stackedSpawner.getStackAmount(), stackedSpawner.getSpawnedType().name());\n            }\n        }\n\n        return new Pair<>(entry.getKey(), entry.getValue() + \"\");\n    }\n\n    @Override\n    public void takeSnapshot(Chunk chunk) {\n        WildStackerSnapshotsContainer.takeSnapshot(chunk);\n    }\n\n    @Override\n    public void releaseSnapshot(World world, int chunkX, int chunkZ) {\n        try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) {\n            WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition);\n        }\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerPlace(SpawnerPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType());\n            int increaseAmount = e.getSpawner().getStackAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else if (increaseAmount > 1) {\n                island.handleBlockPlace(blockKey, increaseAmount - 1);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerStack(SpawnerStackEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType());\n            int increaseAmount = e.getTarget().getStackAmount();\n\n            if (increaseAmount < 0) {\n                island.handleBlockBreak(blockKey, -increaseAmount);\n            } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerUnstack(SpawnerUnstackEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n            if (island != null)\n                island.handleBlockBreak(Keys.ofSpawner(e.getSpawner().getSpawnedType()), e.getAmount());\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerPlaceInventoryMonitor(SpawnerPlaceInventoryEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType());\n            int increaseAmount = e.getIncreaseAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        /* Protection Listener */\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onSpawnerPlaceInventoryNormal(SpawnerPlaceInventoryEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation());\n\n            if (island == null)\n                return;\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n            InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getSpawner().getLocation().getBlock());\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n                e.setCancelled(true);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java",
    "content": "package com.bgsoftware.superiorskyblock.external.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksSnapshotProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.bgsoftware.wildstacker.api.WildStackerAPI;\nimport com.bgsoftware.wildstacker.api.events.BarrelPlaceEvent;\nimport com.bgsoftware.wildstacker.api.events.BarrelPlaceInventoryEvent;\nimport com.bgsoftware.wildstacker.api.events.BarrelStackEvent;\nimport com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent;\nimport com.bgsoftware.wildstacker.api.handlers.SystemManager;\nimport com.bgsoftware.wildstacker.api.objects.StackedBarrel;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\n\npublic class StackedBlocksProvider_WildStacker implements StackedBlocksProvider_AutoDetect, StackedBlocksSnapshotProvider {\n\n    private static boolean registered = false;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public StackedBlocksProvider_WildStacker(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin);\n\n        if (!registered) {\n            registered = true;\n            SuperiorSkyblockAPI.getBlockValues().registerKeyParser(new CustomKeyParser() {\n\n                private final SystemManager systemManager = WildStackerAPI.getWildStacker().getSystemManager();\n\n                @Override\n                public Key getCustomKey(Location location) {\n                    return systemManager.isStackedBarrel(location) ?\n                            getBarrelKey(systemManager.getStackedBarrel(location)) :\n                            ConstantKeys.CAULDRON;\n                }\n\n                @Override\n                public boolean isCustomKey(Key key) {\n                    return false;\n                }\n\n            }, ConstantKeys.CAULDRON);\n\n        }\n\n        Log.info(\"Using WildStacker as a stacked-blocks provider.\");\n    }\n\n    @Override\n    public Collection<Pair<Key, Integer>> getBlocks(World world, int chunkX, int chunkZ) {\n        try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) {\n            return WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, stackedSnapshot -> {\n                try {\n                    return stackedSnapshot.getAllBarrelsItems().values().stream()\n                            .filter(entry -> entry.getValue() != null)\n                            .map(entry -> new Pair<>(Key.of(entry.getValue()), entry.getKey()))\n                            .collect(Collectors.toSet());\n                } catch (Throwable ex) {\n                    return stackedSnapshot.getAllBarrels().values().stream()\n                            .map(entry -> new Pair<>(Key.of(entry.getValue(), (short) 0), entry.getKey()))\n                            .collect(Collectors.toSet());\n                }\n            });\n        }\n    }\n\n    @Override\n    public void takeSnapshot(Chunk chunk) {\n        WildStackerSnapshotsContainer.takeSnapshot(chunk);\n    }\n\n    @Override\n    public void releaseSnapshot(World world, int chunkX, int chunkZ) {\n        try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) {\n            WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition);\n        }\n    }\n\n    @SuppressWarnings(\"unused\")\n    private class StackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBarrelPlace(BarrelPlaceEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = getBarrelKey(e.getBarrel());\n            int increaseAmount = e.getBarrel().getStackAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBarrelStack(BarrelStackEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = getBarrelKey(e.getTarget());\n            int increaseAmount = e.getTarget().getStackAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onBarrelUnstackOnOtherIsland(BarrelUnstackEvent e) {\n            Entity unstackSource = e.getUnstackSource();\n\n            if (!(unstackSource instanceof Player))\n                return;\n\n            Player player = (Player) unstackSource;\n\n            Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation());\n            if (island == null)\n                return;\n\n            Key blockKey = getBarrelKey(e.getBarrel());\n\n            IslandPrivilege islandPrivilege = plugin.getSettings().getValuableBlocks().contains(blockKey) ?\n                    IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK;\n\n            if (!island.hasPermission(player, islandPrivilege)) {\n                e.setCancelled(true);\n                ProtectionHelper.sendProtectionMessage(player);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBarrelUnstack(BarrelUnstackEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation());\n            if (island != null)\n                island.handleBlockBreak(getBarrelKey(e.getBarrel()), e.getAmount());\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBarrelPlace(BarrelPlaceInventoryEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation());\n\n            if (island == null)\n                return;\n\n            Key blockKey = getBarrelKey(e.getBarrel());\n            int increaseAmount = e.getIncreaseAmount();\n\n            if (island.hasReachedBlockLimit(blockKey, increaseAmount)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            } else {\n                island.handleBlockPlace(blockKey, increaseAmount);\n            }\n        }\n\n        @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n        public void onBarrelInteract(PlayerInteractEvent e) {\n            Block block = e.getClickedBlock();\n            if (block == null)\n                return;\n\n            StackedBarrel stackedBarrel;\n            Island island;\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location location = block.getLocation(wrapper.getHandle());\n\n                if(!WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(location))\n                    return;\n\n                stackedBarrel = WildStackerAPI.getWildStacker().getSystemManager().getStackedBarrel(location);\n                island = plugin.getGrid().getIslandAt(location);\n            }\n\n            if (island == null)\n                return;\n\n            Player player = e.getPlayer();\n            Key blockKey = getBarrelKey(stackedBarrel);\n\n            IslandPrivilege privilege = player.isSneaking() ? IslandPrivileges.BUILD :\n                    plugin.getSettings().getValuableBlocks().contains(blockKey) ?\n                            IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK;\n\n            if (!island.hasPermission(player, privilege)) {\n                e.setCancelled(true);\n                ProtectionHelper.sendProtectionMessage(player);\n            }\n        }\n\n    }\n\n    private static Key getBarrelKey(StackedBarrel barrel) {\n        ItemStack barrelItem = barrel.getBarrelItem(1);\n        return ServerVersion.isLegacy() ? Key.of(barrelItem) : Key.of(barrelItem.getType());\n    }\n\n}"
  },
  {
    "path": "Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/listeners/WildStackerListener.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.listeners;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates;\nimport com.bgsoftware.wildstacker.api.events.SpawnerPlaceEvent;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.Listener;\n\npublic class WildStackerListener implements Listener {\n\n    @Nullable\n    private final UpgradeTypeSpawnerRates spawnerRates = BuiltinModules.UPGRADES\n            .getEnabledUpgradeType(UpgradeTypeSpawnerRates.class);\n\n    @EventHandler\n    public void onWildStackerStackSpawn(SpawnerPlaceEvent e) {\n        if (spawnerRates != null)\n            spawnerRates.handleSpawnerPlace(e.getSpawner().getLocation().getBlock());\n    }\n\n}\n"
  },
  {
    "path": "Hooks/build.gradle",
    "content": "group 'Hooks'"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>."
  },
  {
    "path": "Missions/BlocksMissions/build.gradle",
    "content": "group 'Missions:BlocksMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n\n    compileOnly \"com.bgsoftware:WildStackerAPI:3.6.3\"\n    compileOnly \"com.bgsoftware:WildToolsAPI:2.11.4\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.blocks'\n}"
  },
  {
    "path": "Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.missions.blocks.BlocksTracker;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker;\nimport com.bgsoftware.wildstacker.api.WildStackerAPI;\nimport com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent;\nimport com.bgsoftware.wildtools.api.events.CuboidWandUseEvent;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.event.block.BlockPistonExtendEvent;\nimport org.bukkit.event.block.BlockPistonRetractEvent;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport javax.annotation.Nullable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.UUID;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\npublic class BlocksMissions extends BuiltinMission<KeyDataTracker> implements Listener {\n\n    private final Map<KeyRequirements, Integer> requiredBlocks = new LinkedHashMap<>();\n\n    private boolean onlyNatural;\n    private ProgressAction progressAction;\n\n    private Predicate<Location> isBarrelCheck = block -> false;\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        if (!section.contains(\"required-blocks\"))\n            throw new MissionLoadException(\"You must have the \\\"required-blocks\\\" section in the config.\");\n\n        for (String key : section.getConfigurationSection(\"required-blocks\").getKeys(false)) {\n            KeySet blocks = KeySet.createKeySet();\n            section.getStringList(\"required-blocks.\" + key + \".types\").forEach(requiredBlock ->\n                    blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH))));\n            int requiredAmount = section.getInt(\"required-blocks.\" + key + \".amount\");\n            this.requiredBlocks.put(new KeyRequirements(blocks), requiredAmount);\n        }\n\n        this.onlyNatural = section.getBoolean(\"only-natural-blocks\", false);\n        this.progressAction = section.getBoolean(\"blocks-placement\", false) ?\n                ProgressAction.PLACE : ProgressAction.BREAK;\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n\n        Bukkit.getScheduler().runTaskLater(plugin, () -> {\n            if (Bukkit.getPluginManager().isPluginEnabled(\"WildStacker\")) {\n                registerListener(new WildStackerListener());\n                this.isBarrelCheck = block -> WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(block);\n            }\n\n            if (Bukkit.getPluginManager().isPluginEnabled(\"WildTools\")) {\n                registerListener(new WildToolsListener());\n            }\n        }, 1L);\n    }\n\n    @Override\n    protected void clearModuleData(KeyDataTracker data) {\n        data.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker blocksCounter = get(superiorPlayer);\n\n        if (blocksCounter == null)\n            return 0.0;\n\n        int requiredBlocks = 0;\n        int interactions = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredBlock : this.requiredBlocks.entrySet()) {\n            requiredBlocks += requiredBlock.getValue();\n            interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue());\n        }\n\n        return (double) interactions / requiredBlocks;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker blocksCounter = get(superiorPlayer);\n\n        if (blocksCounter == null)\n            return 0;\n\n        int interactions = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredBlock : this.requiredBlocks.entrySet())\n            interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue());\n\n        return interactions;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, KeyDataTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            for (Map.Entry<Key, Counter> blockCountEntry : entry.getValue().getCounts().entrySet()) {\n                section.set(uuid + \".counts.\" + blockCountEntry.getKey(), blockCountEntry.getValue().get());\n            }\n        }\n\n        BlocksTracker.INSTANCE.save(section);\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            KeyDataTracker blocksCounter = new KeyDataTracker();\n            UUID playerUUID;\n\n            try {\n                playerUUID = UUID.fromString(uuid);\n            } catch (Exception error) {\n                // tracked section probably, skipping.\n                continue;\n            }\n\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, blocksCounter);\n\n            if (section.contains(uuid + \".counts\")) {\n                ConfigurationSection countsSection = section.getConfigurationSection(uuid + \".counts\");\n                if (countsSection != null) {\n                    for (String key : countsSection.getKeys(false)) {\n                        Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key));\n                        blocksCounter.load(typeKey, countsSection.getInt(key));\n                    }\n                }\n            } else {\n                ConfigurationSection countsSection = section.getConfigurationSection(uuid);\n                if (countsSection != null) {\n                    for (String key : countsSection.getKeys(false)) {\n                        Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key));\n                        blocksCounter.load(typeKey, section.getInt(uuid + \".\" + key));\n                    }\n                }\n            }\n\n            loadTrackedBlocks(section.getConfigurationSection(uuid + \".tracked.placed\"), section.getConfigurationSection(uuid + \".tracked.broken\"));\n        }\n\n        loadTrackedBlocks(section.getConfigurationSection(\"tracked.placed\"), section.getConfigurationSection(\"tracked.broken\"));\n    }\n\n    private static void loadTrackedBlocks(@Nullable ConfigurationSection trackedPlacedSection,\n                                          @Nullable ConfigurationSection trackedBrokenSection) {\n        if (trackedPlacedSection != null) {\n            for (String worldName : trackedPlacedSection.getKeys(false)) {\n                ConfigurationSection worldSection = trackedPlacedSection.getConfigurationSection(worldName);\n                BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.PLACED_BLOCKS, worldName, worldSection);\n            }\n        }\n\n        if (trackedBrokenSection != null) {\n            for (String worldName : trackedBrokenSection.getKeys(false)) {\n                ConfigurationSection worldSection = trackedBrokenSection.getConfigurationSection(worldName);\n                BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.BROKEN_BLOCKS, worldName, worldSection);\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (blocksCounter == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, itemMeta.getDisplayName(), true));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, line, true));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockPlace(BlockPlaceEvent e) {\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        Key blockKey = getMissionBlockKey(Key.of(e.getBlock()));\n        if (blockKey == null)\n            return;\n\n        if (this.progressAction == ProgressAction.PLACE) {\n            // We want to handle block place only if players gain progress by placing blocks.\n            handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, false);\n        }\n\n        if (this.onlyNatural) {\n            // We want to track block broken & placed only if this mission only progresses for natural blocks\n            // We do that in a delayed tick so all other missions will check for their progress as well.\n            Bukkit.getScheduler().runTaskLater(this.plugin, () -> {\n                BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock());\n                BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock());\n            }, 1L);\n        }\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockBreak(BlockBreakEvent e) {\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        Key blockKey = getMissionBlockKey(Key.of(e.getBlock()));\n        if (blockKey == null)\n            return;\n\n        if (this.progressAction == ProgressAction.BREAK) {\n            // We want to handle block break only if players gain progress by breaking blocks.\n            handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, true);\n        }\n\n        if (this.onlyNatural) {\n            // We want to track block broken & placed only if this mission only progresses for natural blocks\n            // We do that in a delayed tick so all other missions will check for their progress as well.\n            Bukkit.getScheduler().runTaskLater(this.plugin, () -> {\n                BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock());\n                BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock());\n            }, 1L);\n        }\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPistonRetract(BlockPistonRetractEvent e) {\n        if (!e.getBlocks().isEmpty())\n            handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPistonExtend(BlockPistonExtendEvent e) {\n        if (!e.getBlocks().isEmpty())\n            handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection());\n    }\n\n    private class WildStackerListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onBarrelUnstack(BarrelUnstackEvent e) {\n            if (onlyNatural || progressAction != ProgressAction.BREAK || !(e.getUnstackSource() instanceof Player))\n                return;\n\n            Player player = (Player) e.getUnstackSource();\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n            if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this))\n                return;\n\n            Key blockKey = getMissionBlockKey(Key.of(e.getBarrel().getType(), e.getBarrel().getData()));\n            if (blockKey == null)\n                return;\n\n            handleBlockAction(player, e.getBarrel().getLocation(), blockKey, superiorPlayer, false);\n        }\n\n    }\n\n    private class WildToolsListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onCuboidUse(CuboidWandUseEvent e) {\n            if (progressAction != ProgressAction.BREAK)\n                return;\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n            if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this))\n                return;\n\n            for (Location location : e.getBlocks()) {\n                Block block = location.getBlock();\n\n                Key blockKey = getMissionBlockKey(Key.of(block));\n                if (blockKey == null)\n                    return;\n\n                handleBlockAction(e.getPlayer(), location, blockKey, superiorPlayer, true);\n\n                if (onlyNatural) {\n                    // We want to track block broken & placed only if this mission only progresses for natural blocks\n                    // We do that in a delayed tick so all other missions will check for their progress as well.\n                    Bukkit.getScheduler().runTaskLater(plugin, () -> {\n                        BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block);\n                        BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, block);\n                    }, 1L);\n                }\n            }\n        }\n\n    }\n\n    private void handleBlockPistonMove(LinkedList<Block> blockList, BlockFace direction) {\n        blockList.removeIf(block -> getMissionBlockKey(Key.of(block)) == null ||\n                !BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, block));\n\n        if (blockList.isEmpty())\n            return;\n\n        List<Block> movedBlocks = blockList.stream()\n                .map(block -> block.getRelative(direction))\n                .collect(Collectors.toList());\n\n        List<Block> addedBlocks = new LinkedList<>(movedBlocks);\n        addedBlocks.removeAll(blockList);\n\n        List<Block> removedBlocks = new LinkedList<>(blockList);\n        removedBlocks.removeAll(movedBlocks);\n\n        removedBlocks.forEach(block -> BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block));\n        addedBlocks.forEach(block -> BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block));\n    }\n\n    /**\n     * Handle placing or breaking of a block and add count to mission progress.\n     *\n     * @param player         The player.\n     * @param blockLocation  The location of the block.\n     * @param blockKey       The {@link Key} of the block in @param blockLocation.\n     * @param superiorPlayer The {@link SuperiorPlayer} wrapper of @param player.\n     */\n    private void handleBlockAction(Player player, Location blockLocation, Key blockKey,\n                                   @Nullable SuperiorPlayer superiorPlayer, boolean checkForBarrels) {\n        int blockAmount = getBlockAmount(player, blockLocation);\n\n        if (superiorPlayer == null)\n            superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (checkForBarrels && this.isBarrelCheck.test(blockLocation))\n            return;\n\n        // In case we progress for breaking blocks, we want to ensure the block is not tracked in case\n        // the mission only progresses for natural blocks.\n        if (this.onlyNatural && this.progressAction == ProgressAction.BREAK &&\n                BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, blockLocation)) {\n            return;\n        }\n\n        handleBlockTrack(superiorPlayer, blockKey, blockAmount);\n    }\n\n    private void handleBlockTrack(SuperiorPlayer superiorPlayer, Key blockKey, int amount) {\n        KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        blocksCounter.track(blockKey, amount);\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(_player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private int getBlockAmount(Player player, Location blockLocation) {\n        int blockAmount = this.plugin.getStackedBlocks().getStackedBlockAmount(blockLocation);\n\n        // When sneaking, you'll break 64 from the stack. Otherwise, 1.\n        int amount = !player.isSneaking() ? 1 : 64;\n\n        // Fix amount so it won't be more than the stack's amount\n        amount = Math.min(amount, blockAmount);\n\n        return amount;\n    }\n\n    @Nullable\n    private Key getMissionBlockKey(Key blockKey) {\n        for (KeyRequirements requirementsList : requiredBlocks.keySet()) {\n            if (requirementsList.contains(blockKey))\n                return requirementsList.getKey(blockKey);\n        }\n\n        return null;\n    }\n\n    private enum ProgressAction {\n\n        BREAK,\n        PLACE\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.blocks;\n\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.EnumMap;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\npublic class BlocksTracker {\n\n    public static final BlocksTracker INSTANCE = new BlocksTracker();\n\n    private final EnumMap<TrackingType, Map<String, BlocksTrackingComponent>> trackingComponentMap = new EnumMap<>(TrackingType.class);\n    private EnumMap<TrackingType, Map<String, TrackedBlocksData>> rawData = null;\n\n    private boolean saved = false;\n\n    private BlocksTracker() {\n\n    }\n\n    public void trackBlock(TrackingType trackingType, Block block) {\n        getComponent(trackingType, block.getWorld()).add(block.getX(), block.getY(), block.getZ());\n    }\n\n    public boolean untrackBlock(TrackingType trackingType, Block block) {\n        return ifComponentExists(trackingType, block.getWorld(), false,\n                component -> component.remove(block.getX(), block.getY(), block.getZ()));\n    }\n\n    public boolean isTracked(TrackingType trackingType, Block block) {\n        return ifComponentExists(trackingType, block.getWorld(), false,\n                component -> component.contains(block.getX(), block.getY(), block.getZ()));\n    }\n\n    public boolean isTracked(TrackingType trackingType, Location blockLocation) {\n        return ifComponentExists(trackingType, blockLocation.getWorld(), false, component ->\n                component.contains(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ()));\n    }\n\n    public void loadTrackedBlocks(TrackingType trackingType, String worldName, ConfigurationSection section) {\n        if (this.rawData == null)\n            this.rawData = new EnumMap<>(TrackingType.class);\n\n        this.rawData.computeIfAbsent(trackingType, t -> new HashMap<>()).put(worldName, new TrackedBlocksData(section));\n    }\n\n    public void save(ConfigurationSection section) {\n        if (!this.saved) {\n            saveInternal(section, TrackingType.PLACED_BLOCKS);\n            saveInternal(section, TrackingType.BROKEN_BLOCKS);\n            this.saved = true;\n        }\n    }\n\n    private void saveInternal(ConfigurationSection section, TrackingType trackingType) {\n        Map<String, BlocksTrackingComponent> trackingComponentMap = this.trackingComponentMap.get(trackingType);\n\n        if (trackingComponentMap == null)\n            return;\n\n        trackingComponentMap.forEach((worldName, component) -> {\n            component.getBlocks().forEach((chunkKey, blocksBitSet) -> {\n                List<Integer> blocks = new LinkedList<>();\n                blocksBitSet.forEach(blocks::add);\n                if (!blocks.isEmpty())\n                    section.set(\"tracked.\" + trackingType.path + \".\" + worldName + \".\" + chunkKey, blocks);\n            });\n        });\n\n        if (this.rawData != null) {\n            Map<String, TrackedBlocksData> rawData = this.rawData.get(trackingType);\n            if (rawData != null) {\n                rawData.forEach((worldName, trackedBlocksData) -> {\n                    trackedBlocksData.getBlocks().forEach((chunkKey, blocksBitSet) -> {\n                        List<Integer> blocks = new LinkedList<>();\n                        blocksBitSet.forEach(blocks::add);\n                        if (!blocks.isEmpty())\n                            section.set(\"tracked.\" + trackingType.path + \".\" + worldName + \".\" + chunkKey, blocks);\n                    });\n                });\n            }\n        }\n    }\n\n    private BlocksTrackingComponent getComponent(TrackingType trackingType, World world) {\n        BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world);\n        return trackingComponent != null ? trackingComponent :\n                trackingComponentMap.computeIfAbsent(trackingType, t -> new HashMap<>())\n                        .computeIfAbsent(world.getName(), uuid -> new BlocksTrackingComponent(world));\n    }\n\n    private <R> R ifComponentExists(TrackingType trackingType, World world, R def, Function<BlocksTrackingComponent, R> function) {\n        String worldName = world.getName();\n\n        BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world);\n        if (trackingComponent != null)\n            return function.apply(trackingComponent);\n\n        Map<String, BlocksTrackingComponent> trackingTypeComponents = trackingComponentMap.get(trackingType);\n        if (trackingTypeComponents != null) {\n            trackingComponent = trackingTypeComponents.get(worldName);\n            if (trackingComponent != null)\n                return function.apply(trackingComponent);\n        }\n\n        return def;\n    }\n\n    private BlocksTrackingComponent loadRawData(TrackingType trackingType, World world) {\n        String worldName = world.getName();\n\n        if (this.rawData != null) {\n            Map<String, TrackedBlocksData> rawData = this.rawData.get(trackingType);\n            if (rawData != null) {\n                TrackedBlocksData trackedBlocksData = rawData.remove(worldName);\n                if (trackedBlocksData != null) {\n                    BlocksTrackingComponent trackingComponent = new BlocksTrackingComponent(world);\n                    trackingComponent.loadBlocks(trackedBlocksData);\n                    this.trackingComponentMap.computeIfAbsent(trackingType, i -> new HashMap<>())\n                            .put(worldName, trackingComponent);\n                    if (rawData.isEmpty()) {\n                        this.rawData.remove(trackingType);\n                        if(this.rawData.isEmpty())\n                            this.rawData = null;\n                    }\n                    return trackingComponent;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    public enum TrackingType {\n\n        PLACED_BLOCKS(\"placed\"),\n        BROKEN_BLOCKS(\"broken\");\n\n        private final String path;\n\n        TrackingType(String path) {\n            this.path = path;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.blocks;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport org.bukkit.World;\n\nimport java.util.Map;\n\npublic class BlocksTrackingComponent {\n\n    private static final ReflectMethod<Integer> WORLD_GET_MIN_HEIGHT = new ReflectMethod<>(\n            new ClassInfo(\"CraftWorld\", ClassInfo.PackageType.CRAFTBUKKIT),\n            \"getMinHeight\",\n            new ClassInfo[0]);\n\n    // Key represents chunk's coords\n    // Value represents all blocks broken in that chunk\n    private TrackedBlocksData trackedBlocksData = new TrackedBlocksData();\n\n    private final int worldMinHeight;\n\n    public BlocksTrackingComponent(World world) {\n        this(!WORLD_GET_MIN_HEIGHT.isValid() ? 0 : WORLD_GET_MIN_HEIGHT.invoke(world));\n    }\n\n    public BlocksTrackingComponent(int worldMinHeight) {\n        this.worldMinHeight = worldMinHeight;\n    }\n\n    public int getWorldMinHeight() {\n        return worldMinHeight;\n    }\n\n    public void add(int blockX, int blockY, int blockZ) {\n        long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4);\n        this.trackedBlocksData.track(chunkKey, serializeLocation(blockX, blockY, blockZ));\n    }\n\n    public boolean remove(int blockX, int blockY, int blockZ) {\n        long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4);\n        return this.trackedBlocksData.untrack(chunkKey, () -> serializeLocation(blockX, blockY, blockZ));\n    }\n\n    public boolean contains(int blockX, int blockY, int blockZ) {\n        long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4);\n        return this.trackedBlocksData.contains(chunkKey, () -> serializeLocation(blockX, blockY, blockZ));\n    }\n\n    public void loadBlocks(TrackedBlocksData trackedBlocksData) {\n        this.trackedBlocksData = trackedBlocksData;\n    }\n\n    public Map<Long, ChunkBitSet> getBlocks() {\n        return this.trackedBlocksData.getBlocks();\n    }\n\n    private int serializeLocation(int blockX, int blockY, int blockZ) {\n        int chunkMinX = blockX >> 4 << 4;\n        int chunkMinZ = blockZ >> 4 << 4;\n\n\n        byte relativeX = (byte) (blockX - chunkMinX);\n        short relativeY = (short) (blockY - this.worldMinHeight);\n        byte relativeZ = (byte) (blockZ - chunkMinZ);\n\n        return (relativeY << 8) | (relativeX << 4) | relativeZ;\n    }\n\n    private static long serializeChunk(int chunkX, int chunkZ) {\n        return (long) chunkX << 32 | chunkZ;\n    }\n\n}\n"
  },
  {
    "path": "Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.blocks;\n\nimport java.util.Arrays;\nimport java.util.BitSet;\nimport java.util.function.IntConsumer;\n\npublic class ChunkBitSet {\n\n    private static final BitSet[] EMPTY_BIT_SET_ARRAY = new BitSet[0];\n\n    private BitSet[] bitSets = EMPTY_BIT_SET_ARRAY;\n\n    public ChunkBitSet() {\n\n    }\n\n    public void set(int index) {\n        BitSet bitSet = getBitSetForBlock(index, true);\n        if (bitSet == null)\n            throw new IllegalStateException();\n        int blockIdx = index & 0xFFF;\n        bitSet.set(blockIdx);\n    }\n\n    public boolean clear(int index) {\n        BitSet bitSet = getBitSetForBlock(index, false);\n        if (bitSet == null)\n            return false;\n        int blockIdx = index & 0xFFF;\n        boolean old = bitSet.get(blockIdx);\n        bitSet.clear(blockIdx);\n        return old;\n    }\n\n    public boolean get(int index) {\n        BitSet bitSet = getBitSetForBlock(index, false);\n        if (bitSet == null)\n            return false;\n        int blockIdx = index & 0xFFF;\n        return bitSet.get(blockIdx);\n    }\n\n    public void forEach(IntConsumer consumer) {\n        for (int i = 0; i < this.bitSets.length; ++i) {\n            BitSet bitSet = this.bitSets[i];\n            if (bitSet != null) {\n                for (int j = bitSet.nextSetBit(0); j != -1; j = bitSet.nextSetBit(j + 1)) {\n                    consumer.accept(((i << 4) << 8) | j);\n                }\n            }\n        }\n    }\n\n    private void ensureCapacity(int capacity) {\n        if (bitSets.length >= capacity)\n            return;\n\n        bitSets = Arrays.copyOf(bitSets, capacity);\n    }\n\n    private BitSet getBitSetForBlock(int block, boolean createNew) {\n        int sectionIdx = (block >> 8) >> 4;\n\n        if (bitSets.length <= sectionIdx) {\n            if (!createNew)\n                return null;\n\n            ensureCapacity(sectionIdx + 1);\n        }\n\n        BitSet bitSet = bitSets[sectionIdx];\n\n        if (bitSet == null) {\n            if (!createNew)\n                return null;\n\n            bitSet = bitSets[sectionIdx] = new BitSet();\n        }\n\n        return bitSet;\n    }\n\n}\n"
  },
  {
    "path": "Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.blocks;\n\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.IntSupplier;\n\npublic class TrackedBlocksData {\n\n    private final Map<Long, ChunkBitSet> TRACKED_BLOCKS = new HashMap<>();\n    private final Map<Long, ChunkBitSet> TRACKED_BLOCKS_VIEW = Collections.unmodifiableMap(TRACKED_BLOCKS);\n\n    public TrackedBlocksData(ConfigurationSection section) {\n        for (String chunkKey : section.getKeys(false)) {\n            List<Integer> trackedBlocks = section.getIntegerList(chunkKey);\n            ChunkBitSet bitSet = new ChunkBitSet();\n            trackedBlocks.forEach(bitSet::set);\n            try {\n                TRACKED_BLOCKS.put(Long.parseLong(chunkKey), bitSet);\n            } catch (NumberFormatException ignored) {\n            }\n        }\n    }\n\n    public TrackedBlocksData() {\n\n    }\n\n    public void track(long chunkKey, int block) {\n        TRACKED_BLOCKS.computeIfAbsent(chunkKey, key -> new ChunkBitSet()).set(block);\n    }\n\n    public boolean untrack(long chunkKey, IntSupplier block) {\n        return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey))\n                .map(bitSet -> bitSet.clear(block.getAsInt()))\n                .orElse(false);\n    }\n\n    public boolean contains(long chunkKey, IntSupplier block) {\n        return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey))\n                .map(bitSet -> bitSet.get(block.getAsInt()))\n                .orElse(false);\n    }\n\n    public Map<Long, ChunkBitSet> getBlocks() {\n        return TRACKED_BLOCKS_VIEW;\n    }\n\n}\n"
  },
  {
    "path": "Missions/BrewingMissions/build.gradle",
    "content": "group 'Missions:BrewingMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.brewing'\n}"
  },
  {
    "path": "Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.CustomRequirements;\nimport org.bukkit.Bukkit;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.BrewingStand;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.event.inventory.BrewEvent;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.BrewerInventory;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.Potion;\nimport org.bukkit.potion.PotionType;\n\nimport javax.annotation.Nullable;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.function.Predicate;\n\npublic final class BrewingMissions extends BuiltinMission<BrewingMissions.BrewingTracker> implements Listener {\n\n    private static final boolean isUsing18 = Bukkit.getServer().getClass().getPackage().getName().contains(\"1_8\");\n\n    private final Map<CustomRequirements<PotionData>, Integer> requiredPotions = new LinkedHashMap<>();\n    private final Map<Location, boolean[]> trackedBrewItems = new HashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredPotionsSection = section.getConfigurationSection(\"required-potions\");\n\n        if (requiredPotionsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-potions\\\" section in the config.\");\n\n        for (String key : requiredPotionsSection.getKeys(false)) {\n            CustomRequirements<PotionData> requiredPotions = new CustomRequirements<>();\n\n            ConfigurationSection potionsSection = section.getConfigurationSection(\"required-potions.\" + key + \".potions\");\n\n            for (String potionSectionName : potionsSection.getKeys(false)) {\n                ConfigurationSection potionSection = potionsSection.getConfigurationSection(potionSectionName);\n\n                if (potionSection == null) {\n                    plugin.getLogger().info(ChatColor.RED + \"Potion section \" + potionSectionName + \" is invalid, skipping...\");\n                    continue;\n                }\n\n                PotionType potionType;\n\n                try {\n                    potionType = PotionType.valueOf(potionSection.getString(\"type\"));\n                } catch (Exception ex) {\n                    plugin.getLogger().info(ChatColor.RED + \"Potion type in section \"\n                            + potionsSection.getCurrentPath() + \".\" + potionSectionName + \" is invalid, skipping...\");\n                    continue;\n                }\n\n                boolean upgraded = potionSection.getBoolean(\"upgraded\", false);\n                boolean extended = potionSection.getBoolean(\"extended\", false);\n                boolean splash = potionSection.getBoolean(\"splash\", false);\n\n                requiredPotions.add(new PotionData(potionType, upgraded, extended, splash));\n            }\n\n            if (!requiredPotions.isEmpty()) {\n                int requiredAmount = section.getInt(\"required-potions.\" + key + \".amount\");\n                this.requiredPotions.put(requiredPotions, requiredAmount);\n            }\n        }\n\n        if (requiredPotions.isEmpty()) {\n            throw new MissionLoadException(\"There are no valid required potions for this mission.\");\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(BrewingTracker data) {\n        data.brewingTracker.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        BrewingTracker brewingTracker = get(superiorPlayer);\n\n        if (brewingTracker == null)\n            return 0.0;\n\n        int requiredPotions = 0;\n        int kills = 0;\n\n        for (Map.Entry<CustomRequirements<PotionData>, Integer> requiredPotion : this.requiredPotions.entrySet()) {\n            requiredPotions += requiredPotion.getValue();\n            kills += Math.min(brewingTracker.getBrews(requiredPotion.getKey()), requiredPotion.getValue());\n        }\n\n        return (double) kills / requiredPotions;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        BrewingTracker brewingTracker = get(superiorPlayer);\n\n        if (brewingTracker == null)\n            return 0;\n\n        int kills = 0;\n\n        for (Map.Entry<CustomRequirements<PotionData>, Integer> requiredEntity : this.requiredPotions.entrySet())\n            kills += Math.min(brewingTracker.getBrews(requiredEntity.getKey()), requiredEntity.getValue());\n\n        return kills;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, BrewingTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            for (Map.Entry<PotionData, Integer> brokenEntry : entry.getValue().brewingTracker.entrySet()) {\n                section.set(uuid + \".\" + brokenEntry.getKey(), brokenEntry.getValue());\n            }\n        }\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            BrewingTracker brewingTracker = new BrewingTracker();\n            UUID playerUUID = UUID.fromString(uuid);\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, brewingTracker);\n\n            for (String key : section.getConfigurationSection(uuid).getKeys(false)) {\n                brewingTracker.brewingTracker.put(PotionData.fromString(key), section.getInt(uuid + \".\" + key));\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker());\n\n        if (brewingTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        Placeholders.PlaceholdersFunctions<CustomRequirements<PotionData>> placeholdersFunctions = new Placeholders.PlaceholdersFunctions<CustomRequirements<PotionData>>() {\n            @Override\n            public CustomRequirements<PotionData> getRequirementFromKey(String key) {\n                PotionData potionData = PotionData.fromString(key);\n\n                for (CustomRequirements<PotionData> requirements : requiredPotions.keySet()) {\n                    if (requirements.contains(potionData))\n                        return requirements;\n                }\n\n                return null;\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(CustomRequirements<PotionData> requirement) {\n                return Optional.ofNullable(requiredPotions.get(requirement));\n            }\n\n            @Override\n            public int getCountForRequirement(CustomRequirements<PotionData> requirement) {\n                return brewingTracker.getBrews(requirement);\n            }\n        };\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new LinkedList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBrew(BrewEvent e) {\n        ItemStack[] originalResultItems = new ItemStack[3];\n        for (int i = 0; i < 3; ++i) {\n            ItemStack resultItem = e.getContents().getItem(i);\n            if (resultItem != null) {\n                originalResultItems[i] = resultItem.clone();\n            }\n        }\n\n        Bukkit.getScheduler().runTaskLater(plugin, () -> {\n            for (int i = 0; i < 3; ++i) {\n                ItemStack resultItem = e.getContents().getItem(i);\n                if (resultItem != null && !resultItem.isSimilar(originalResultItems[i]) && isMissionBrewing(resultItem)) {\n                    trackedBrewItems.computeIfAbsent(e.getBlock().getLocation(), block -> new boolean[3])[i] = true;\n                }\n            }\n        }, 1L);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBrew(InventoryClickEvent e) {\n        if (!(e.getClickedInventory() instanceof BrewerInventory) || e.getRawSlot() > 2)\n            return;\n\n        BrewerInventory inventory = (BrewerInventory) e.getClickedInventory();\n\n        handleBrewing((Player) e.getWhoClicked(), inventory, slot -> slot == e.getRawSlot());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockBreak(BlockBreakEvent e) {\n        BlockState blockState = e.getBlock().getState();\n\n        if (!(blockState instanceof BrewingStand))\n            return;\n\n        BrewingStand brewingStand = (BrewingStand) blockState;\n\n        handleBrewing(e.getPlayer(), brewingStand.getInventory(), slot -> true);\n    }\n\n    private void handleBrewing(Player player, BrewerInventory inventory, Predicate<Integer> checkSlot) {\n        Block block = inventory.getHolder().getBlock();\n\n        boolean[] brewItems = this.trackedBrewItems.get(block.getLocation());\n\n        if (brewItems == null) {\n            return;\n        }\n\n        try {\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player);\n\n            if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n                return;\n\n            BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker());\n\n            if (brewingTracker == null)\n                return;\n\n            for (int i = 0; i < 3; ++i) {\n                if (checkSlot.test(i) && brewItems[i]) {\n                    brewItems[i] = false;\n\n                    ItemStack brewItem = inventory.getItem(i);\n\n                    brewingTracker.track(brewItem, brewItem.getAmount());\n                }\n            }\n\n            this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(unused -> {\n                if (canComplete(superiorPlayer))\n                    this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n            }), 2L);\n        } finally {\n            if (!brewItems[0] && !brewItems[1] && !brewItems[2])\n                this.trackedBrewItems.remove(block.getLocation());\n        }\n    }\n\n    private boolean isMissionBrewing(ItemStack itemStack) {\n        PotionData potionData = PotionData.fromItemStack(itemStack);\n\n        if (potionData == null)\n            return false;\n\n        for (Collection<PotionData> requiredPotion : requiredPotions.keySet()) {\n            if (requiredPotion.contains(potionData))\n                return true;\n        }\n\n        return false;\n    }\n\n\n    public static class BrewingTracker {\n\n        private final Map<PotionData, Integer> brewingTracker = new HashMap<>();\n\n        void track(ItemStack brewing, int amount) {\n            PotionData potionData = PotionData.fromItemStack(brewing);\n            int newAmount = amount + brewingTracker.getOrDefault(potionData, 0);\n            brewingTracker.put(potionData, newAmount);\n        }\n\n        int getBrews(Collection<PotionData> potions) {\n            int amount = 0;\n\n            for (Map.Entry<PotionData, Integer> potionData : brewingTracker.entrySet()) {\n                if (potions.contains(potionData.getKey()))\n                    amount += potionData.getValue();\n            }\n\n            return amount;\n        }\n\n    }\n\n    private static class PotionData {\n\n        private final PotionType potionType;\n        private final boolean upgraded;\n        private final boolean extended;\n        private final boolean splash;\n\n        public PotionData(PotionType potionType, boolean upgraded, boolean extended, boolean splash) {\n            this.potionType = potionType;\n            this.upgraded = upgraded;\n            this.extended = extended;\n            this.splash = splash;\n        }\n\n        @Nullable\n        public static PotionData fromItemStack(ItemStack itemStack) {\n            return isUsing18 ? fromItemStack18(itemStack) : fromItemStack19(itemStack);\n        }\n\n        public static PotionData fromString(String line) {\n            String[] sections = line.split(\";\");\n\n            PotionType potionType;\n\n            try {\n                potionType = PotionType.valueOf(sections[0]);\n            } catch (IllegalArgumentException ex) {\n                throw new IllegalArgumentException(\"Potion type '\" + sections[0] + \"' is invalid.\");\n            }\n\n            boolean upgraded = sections.length >= 2 && Boolean.parseBoolean(sections[1]);\n            boolean extended = sections.length >= 3 && Boolean.parseBoolean(sections[2]);\n            boolean splash = sections.length >= 4 && Boolean.parseBoolean(sections[3]);\n\n            return new PotionData(potionType, upgraded, extended, splash);\n        }\n\n        private static PotionData fromItemStack19(ItemStack itemStack) {\n            ItemMeta itemMeta = itemStack.getItemMeta();\n\n            if (!(itemMeta instanceof PotionMeta)) {\n                return null;\n            }\n\n            PotionMeta potionMeta = (PotionMeta) itemMeta;\n            org.bukkit.potion.PotionData potionData = potionMeta.getBasePotionData();\n\n            return new PotionData(potionData.getType(), potionData.isUpgraded(), potionData.isExtended(),\n                    itemStack.getType() == Material.SPLASH_POTION);\n        }\n\n        @SuppressWarnings(\"deprecation\")\n        private static PotionData fromItemStack18(ItemStack itemStack) {\n            Potion potion = Potion.fromItemStack(itemStack);\n            return new PotionData(potion.getType(), potion.getLevel() > 1, potion.hasExtendedDuration(), potion.isSplash());\n        }\n\n        @Override\n        public String toString() {\n            return potionType.name() + \";\" + upgraded + \";\" + extended + \";\" + splash;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n            PotionData that = (PotionData) o;\n            return upgraded == that.upgraded && extended == that.extended && splash == that.splash && potionType == that.potionType;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(potionType, upgraded, extended, splash);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/CraftingMissions/build.gradle",
    "content": "group 'Missions:EnchantingMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.crafting'\n}"
  },
  {
    "path": "Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.HumanEntity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.PlayerInventory;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic final class CraftingMissions extends BuiltinMission<CraftingMissions.CraftingsTracker> implements Listener {\n\n    private final Map<ItemStack, Integer> itemsToCraft = new LinkedHashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection craftingsSection = section.getConfigurationSection(\"craftings\");\n\n        if (craftingsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"craftings\\\" section in the config.\");\n\n        for (String key : craftingsSection.getKeys(false)) {\n            String type = section.getString(\"craftings.\" + key + \".type\");\n            short data = (short) section.getInt(\"craftings.\" + key + \".data\", 0);\n            int amount = section.getInt(\"craftings.\" + key + \".amount\", 1);\n            Material material;\n\n            try {\n                material = Material.valueOf(type);\n            } catch (IllegalArgumentException ex) {\n                throw new MissionLoadException(\"Invalid crafting result \" + type + \".\");\n            }\n\n            this.itemsToCraft.put(new ItemStack(material, 1, data), amount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(CraftingsTracker data) {\n        data.craftedItems.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        CraftingsTracker craftingsTracker = get(superiorPlayer);\n\n        if (craftingsTracker == null)\n            return 0.0;\n\n        int requiredItems = 0;\n        int interactions = 0;\n\n        for (Map.Entry<ItemStack, Integer> entry : this.itemsToCraft.entrySet()) {\n            requiredItems += entry.getValue();\n            interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue());\n        }\n\n        return (double) interactions / requiredItems;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        CraftingsTracker craftingsTracker = get(superiorPlayer);\n\n        if (craftingsTracker == null)\n            return 0;\n\n        int interactions = 0;\n\n        for (Map.Entry<ItemStack, Integer> entry : this.itemsToCraft.entrySet())\n            interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue());\n\n        return interactions;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, CraftingsTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            int index = 0;\n            for (Map.Entry<ItemStack, Integer> craftedEntry : entry.getValue().craftedItems.entrySet()) {\n                section.set(uuid + \".\" + index + \".item\", craftedEntry.getKey());\n                section.set(uuid + \".\" + index + \".amount\", craftedEntry.getValue());\n                index++;\n            }\n        }\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            if (uuid.equals(\"players\"))\n                continue;\n\n            CraftingsTracker craftingsTracker = new CraftingsTracker();\n            UUID playerUUID = UUID.fromString(uuid);\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, craftingsTracker);\n\n            for (String key : section.getConfigurationSection(uuid).getKeys(false)) {\n                ItemStack itemStack = section.getItemStack(uuid + \".\" + key + \".item\");\n                int amount = section.getInt(uuid + \".\" + key + \".amount\");\n                craftingsTracker.craftedItems.put(itemStack, amount);\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        CraftingsTracker craftingsTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker());\n\n        if (craftingsTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        Placeholders.PlaceholdersFunctions<ItemStack> placeholdersFunctions = new Placeholders.PlaceholdersFunctions<ItemStack>() {\n            @Override\n            public ItemStack getRequirementFromKey(String key) {\n                return new ItemStack(Material.valueOf(key));\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(ItemStack requirement) {\n                return itemsToCraft.entrySet().stream()\n                        .filter(e -> e.getKey().isSimilar(requirement))\n                        .findFirst()\n                        .map(Map.Entry::getValue);\n            }\n\n            @Override\n            public int getCountForRequirement(ItemStack requirement) {\n                return craftingsTracker.getCrafts(requirement);\n            }\n        };\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onInventoryClick(InventoryClickEvent e) {\n        if (e.getClickedInventory() == null || (e.getClickedInventory().getType() != InventoryType.WORKBENCH &&\n                e.getClickedInventory().getType() != InventoryType.CRAFTING && e.getClickedInventory().getType() != InventoryType.FURNACE))\n            return;\n\n        int requiredSlot = e.getClickedInventory().getType() == InventoryType.FURNACE ? 2 : 0;\n\n        ItemStack resultItem = e.getCurrentItem().clone();\n        resultItem.setAmount(1);\n\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer((Player) e.getWhoClicked());\n\n        if (e.getRawSlot() == requiredSlot && itemsToCraft.containsKey(resultItem) &&\n                this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) {\n            int amountOfResult = countItems(e.getWhoClicked(), resultItem);\n            Bukkit.getScheduler().runTaskLater(this.plugin, () -> {\n                int afterTickAmountOfResult = countItems(e.getWhoClicked(), resultItem);\n                resultItem.setAmount(afterTickAmountOfResult - amountOfResult);\n                trackItem(superiorPlayer, resultItem);\n            }, 1L);\n        }\n\n    }\n\n    private void trackItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        CraftingsTracker blocksTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker());\n\n        if (blocksTracker == null)\n            return;\n\n        blocksTracker.trackItem(itemStack);\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private static int countItems(HumanEntity humanEntity, ItemStack itemStack) {\n        int amount = 0;\n\n        if (itemStack == null)\n            return amount;\n\n        PlayerInventory playerInventory = humanEntity.getInventory();\n\n        for (ItemStack invItem : playerInventory.getContents()) {\n            if (invItem != null && itemStack.isSimilar(invItem))\n                amount += invItem.getAmount();\n        }\n\n        if (humanEntity.getItemOnCursor() != null && itemStack.isSimilar(humanEntity.getItemOnCursor()))\n            amount += humanEntity.getItemOnCursor().getAmount();\n\n        return amount;\n    }\n\n    public static class CraftingsTracker {\n\n        private final Map<ItemStack, Integer> craftedItems = new HashMap<>();\n\n        void trackItem(ItemStack itemStack) {\n            ItemStack keyItem = itemStack.clone();\n            keyItem.setAmount(1);\n            craftedItems.put(keyItem, craftedItems.getOrDefault(keyItem, 0) + itemStack.getAmount());\n        }\n\n        int getCrafts(ItemStack itemStack) {\n            ItemStack keyItem = itemStack.clone();\n            keyItem.setAmount(1);\n            return craftedItems.getOrDefault(keyItem, 0);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/EnchantingMissions/build.gradle",
    "content": "group 'Missions:EnchantingMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_9_R1:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.enchanting'\n}"
  },
  {
    "path": "Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.RawDataTracker;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.enchantment.EnchantItemEvent;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.EnchantmentStorageMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic final class EnchantingMissions extends BuiltinMission<RawDataTracker> implements Listener {\n\n    private static final Pattern ENCHANTED_PATTERN = Pattern.compile(\"\\\\{enchanted_(.+?)}\");\n\n    private final Map<Requirements, RequiredEnchantment> requiredEnchantments = new LinkedHashMap<>();\n\n    private String enchantedPlaceholder, notEnchantedPlaceholder;\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredEnchantsSection = section.getConfigurationSection(\"required-enchants\");\n\n        if (requiredEnchantsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-enchants\\\" section in the config.\");\n\n        for (String key : requiredEnchantsSection.getKeys(false)) {\n            List<String> itemTypes = section.getStringList(\"required-enchants.\" + key + \".types\");\n            Map<Enchantment, Integer> enchantments = new HashMap<>();\n\n            ConfigurationSection enchantsSection = section.getConfigurationSection(\"required-enchants.\" + key + \".enchants\");\n\n            if (enchantsSection == null)\n                throw new MissionLoadException(\"You must have the \\\"required-enchants.\" + key + \".enchants\\\" section in the config.\");\n\n            for (String enchantment : enchantsSection.getKeys(false)) {\n                Enchantment _enchantment = Enchantment.getByName(enchantment.toUpperCase(Locale.ENGLISH));\n\n                if (_enchantment == null)\n                    throw new MissionLoadException(\"Enchantment \" + enchantment + \" is not valid.\");\n\n                enchantments.put(_enchantment, section.getInt(\"required-enchants.\" + key + \".enchants.\" + enchantment));\n            }\n\n            if (!enchantments.isEmpty()) {\n                this.requiredEnchantments.put(new Requirements(itemTypes), new RequiredEnchantment(key, enchantments,\n                        section.getInt(\"required-enchants.\" + key + \".amount\", 1)));\n            }\n        }\n\n        this.enchantedPlaceholder = section.getString(\"enchanted-placeholder\", \"Yes\");\n        this.notEnchantedPlaceholder = section.getString(\"not-enchanted-placeholder\", \"No\");\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n\n        try {\n            Class.forName(\"org.bukkit.event.inventory.PrepareAnvilEvent\");\n            registerListener(new PrepareAnvilListener());\n        } catch (Exception ignored) {\n        }\n    }\n\n    @Override\n    protected void clearModuleData(RawDataTracker data) {\n        data.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        RawDataTracker enchantsTracker = get(superiorPlayer);\n\n        if (enchantsTracker == null)\n            return 0.0;\n\n        int requiredItems = 0;\n        int enchants = 0;\n\n        for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) {\n            requiredItems += requiredEnchantment.amount;\n            enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount);\n        }\n\n        return (double) enchants / requiredItems;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        RawDataTracker enchantsTracker = get(superiorPlayer);\n\n        if (enchantsTracker == null)\n            return 0;\n\n        int enchants = 0;\n\n        for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) {\n            enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount);\n        }\n\n        return enchants;\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker());\n\n        if (enchantsTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        Placeholders.PlaceholdersFunctions<Requirements> placeholdersFunctions = new Placeholders.PlaceholdersFunctions<Requirements>() {\n            @Override\n            public Requirements getRequirementFromKey(String key) {\n                for (Requirements requirements : requiredEnchantments.keySet()) {\n                    if (requirements.contains(key))\n                        return requirements;\n                }\n\n                return null;\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(Requirements requirement) {\n                return Optional.ofNullable(requiredEnchantments.get(requirement))\n                        .map(requiredEnchantment -> requiredEnchantment.amount);\n            }\n\n            @Override\n            public int getCountForRequirement(Requirements requirement) {\n                return Optional.ofNullable(requiredEnchantments.get(requirement))\n                        .map(requiredEnchantment -> enchantsTracker.getCount(requiredEnchantment.key))\n                        .orElse(0);\n            }\n        };\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(parsePlaceholders(placeholdersFunctions, enchantsTracker, itemMeta.getDisplayName()));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(parsePlaceholders(placeholdersFunctions, enchantsTracker, line));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onItemEnchant(EnchantItemEvent e) {\n        ItemStack simulateEnchanted = e.getItem().clone();\n        ItemMeta itemMeta = simulateEnchanted.getItemMeta();\n\n        for (Map.Entry<Enchantment, Integer> entry : e.getEnchantsToAdd().entrySet()) {\n            if (simulateEnchanted.getType() == Material.BOOK) {\n                simulateEnchanted = new ItemStack(Material.ENCHANTED_BOOK);\n                itemMeta = simulateEnchanted.getItemMeta();\n            }\n\n            if (itemMeta == null)\n                continue;\n\n            if (simulateEnchanted.getType() == Material.ENCHANTED_BOOK) {\n                ((EnchantmentStorageMeta) itemMeta).addStoredEnchant(entry.getKey(), entry.getValue(), true);\n            } else if (entry.getKey().canEnchantItem(simulateEnchanted)) {\n                itemMeta.addEnchant(entry.getKey(), entry.getValue(), true);\n            }\n        }\n\n        simulateEnchanted.setItemMeta(itemMeta);\n\n        getMissionRequirement(simulateEnchanted).ifPresent(requirement -> handleEnchanting(e.getEnchanter(), requirement));\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, RawDataTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            List<String> data = new ArrayList<>();\n            entry.getValue().getCounts().forEach((enchant, amount) -> data.add(enchant + \";\" + amount.get()));\n            section.set(uuid, data);\n        }\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            RawDataTracker enchantsTracker = new RawDataTracker();\n            UUID playerUUID = UUID.fromString(uuid);\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, enchantsTracker);\n\n            section.getStringList(uuid).forEach(line -> {\n                String[] sections = line.split(\";\");\n                int amount = sections.length == 2 ? Integer.parseInt(sections[1]) : 1;\n                String enchantment = sections[0];\n                enchantsTracker.load(enchantment, amount);\n            });\n        }\n    }\n\n    private Optional<RequiredEnchantment> getMissionRequirement(ItemStack itemStack) {\n        outerLoop:\n        for (Map.Entry<Requirements, RequiredEnchantment> requirement : this.requiredEnchantments.entrySet()) {\n            if (!requirement.getKey().contains(itemStack.getType().name()))\n                continue;\n\n            for (Map.Entry<Enchantment, Integer> requiredEnchantment : requirement.getValue().enchantments.entrySet()) {\n                Enchantment enchantment = requiredEnchantment.getKey();\n                int requiredLevel = requiredEnchantment.getValue();\n\n                if (itemStack.getType() == Material.ENCHANTED_BOOK) {\n                    EnchantmentStorageMeta storageMeta = (EnchantmentStorageMeta) itemStack.getItemMeta();\n                    if (storageMeta == null || storageMeta.getStoredEnchantLevel(enchantment) < requiredLevel)\n                        continue outerLoop;\n                } else if (itemStack.getEnchantmentLevel(enchantment) < requiredLevel) {\n                    continue outerLoop;\n                }\n            }\n\n            return Optional.of(requirement.getValue());\n        }\n\n        return Optional.empty();\n    }\n\n    private void handleEnchanting(Player player, RequiredEnchantment requirement) {\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker());\n\n        if (enchantsTracker == null)\n            return;\n\n        enchantsTracker.track(requirement.key, 1);\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(_player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private String parsePlaceholders(Placeholders.PlaceholdersFunctions<Requirements> placeholdersFunctions,\n                                     RawDataTracker enchantsTracker, String line) {\n        Matcher matcher = ENCHANTED_PATTERN.matcher(line);\n\n        if (matcher.find()) {\n            String requiredBlock = matcher.group(1).toUpperCase(Locale.ENGLISH);\n\n            Optional<Map.Entry<Requirements, RequiredEnchantment>> entry = requiredEnchantments.entrySet().stream()\n                    .filter(e -> e.getKey().contains(requiredBlock)).findAny();\n\n            if (entry.isPresent()) {\n                RequiredEnchantment requiredEnchantment = entry.get().getValue();\n                line = matcher.replaceAll(enchantsTracker.getCount(requiredEnchantment.key) > 0 ? enchantedPlaceholder : notEnchantedPlaceholder);\n            }\n        }\n\n        return Placeholders.parsePlaceholders(line, placeholdersFunctions);\n    }\n\n    private static class RequiredEnchantment {\n\n        private final String key;\n        private final Map<Enchantment, Integer> enchantments;\n        private final Integer amount;\n\n        RequiredEnchantment(String key, Map<Enchantment, Integer> enchantments, Integer amount) {\n            this.key = key;\n            this.enchantments = enchantments;\n            this.amount = amount;\n        }\n\n    }\n\n    private class PrepareAnvilListener implements Listener {\n\n        private final Map<UUID, RequiredEnchantment> addingEnchantments = new HashMap<>();\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onItemAnvil(org.bukkit.event.inventory.PrepareAnvilEvent e) {\n            if (e.getResult() == null || !isAddingEnchantment(e))\n                return;\n\n            getMissionRequirement(e.getResult()).ifPresent(requirement ->\n                    addingEnchantments.put(e.getView().getPlayer().getUniqueId(), requirement));\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onItemAnvil(InventoryClickEvent e) {\n            if (e.getRawSlot() != 2)\n                return;\n\n            RequiredEnchantment requiredEnchantment = addingEnchantments.remove(e.getWhoClicked().getUniqueId());\n            if (requiredEnchantment == null)\n                return;\n\n            handleEnchanting((Player) e.getWhoClicked(), requiredEnchantment);\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onInventoryClose(InventoryCloseEvent e) {\n            addingEnchantments.remove(e.getPlayer().getUniqueId());\n        }\n\n        private boolean isAddingEnchantment(org.bukkit.event.inventory.PrepareAnvilEvent e) {\n            ItemStack result = e.getResult();\n            if (result == null)\n                return false;\n\n            ItemStack firstSlot = e.getInventory().getItem(0);\n            if (firstSlot == null)\n                return false;\n\n            ItemStack secondSlot = e.getInventory().getItem(1);\n            if (secondSlot == null)\n                return false;\n\n            return firstSlot.getType() == secondSlot.getType() || secondSlot.getType().name().contains(\"BOOK\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/FarmingMissions/build.gradle",
    "content": "group 'Missions:FarmingMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.farming'\n}"
  },
  {
    "path": "Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker;\nimport com.bgsoftware.superiorskyblock.missions.farming.PlantType;\nimport com.bgsoftware.superiorskyblock.missions.farming.PlantsTracker;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.data.Ageable;\nimport org.bukkit.block.data.BlockData;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.event.block.BlockGrowEvent;\nimport org.bukkit.event.block.BlockPistonExtendEvent;\nimport org.bukkit.event.block.BlockPistonRetractEvent;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.event.block.BlockSpreadEvent;\nimport org.bukkit.event.entity.EntityExplodeEvent;\nimport org.bukkit.event.world.StructureGrowEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport javax.annotation.Nullable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic final class FarmingMissions extends BuiltinMission<KeyDataTracker> implements Listener {\n\n    private static final BlockFace[] STEM_NEARBY_BLOCKS = new BlockFace[]{\n            BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH\n    };\n    private static final BlockFace[] CHORUS_NEARBY_BLOCKS = new BlockFace[]{\n            BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN\n    };\n\n    private final Map<KeyRequirements, Integer> requiredPlants = new LinkedHashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredPlantsSection = section.getConfigurationSection(\"required-plants\");\n\n        if (requiredPlantsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-plants\\\" section in the config.\");\n\n        for (String key : requiredPlantsSection.getKeys(false)) {\n            KeySet requiredPlants = KeySet.createKeySet();\n            section.getStringList(\"required-plants.\" + key + \".types\").forEach(requiredPlant ->\n                    requiredPlants.add(Key.ofMaterialAndData(requiredPlant.toUpperCase(Locale.ENGLISH))));\n            int requiredAmount = section.getInt(\"required-plants.\" + key + \".amount\");\n            this.requiredPlants.put(new KeyRequirements(requiredPlants), requiredAmount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(KeyDataTracker data) {\n        data.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker farmingTracker = get(superiorPlayer);\n\n        if (farmingTracker == null)\n            return 0.0;\n\n        int requiredPlants = 0;\n        int grewPlants = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredPlant : this.requiredPlants.entrySet()) {\n            requiredPlants += requiredPlant.getValue();\n            grewPlants += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue());\n        }\n\n        return (double) grewPlants / requiredPlants;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker farmingTracker = get(superiorPlayer);\n\n        if (farmingTracker == null)\n            return 0;\n\n        int kills = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredPlant : this.requiredPlants.entrySet())\n            kills += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue());\n\n        return kills;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, KeyDataTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            entry.getValue().getCounts().forEach((plant, count) ->\n                    section.set(\"grown-plants.\" + uuid + \".\" + plant, count.get()));\n        }\n\n        PlantsTracker.INSTANCE.save(section);\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        ConfigurationSection grownPlants = section.getConfigurationSection(\"grown-plants\");\n        if (grownPlants != null) {\n            for (String uuid : grownPlants.getKeys(false)) {\n                KeyDataTracker farmingTracker = new KeyDataTracker();\n                UUID playerUUID = UUID.fromString(uuid);\n                SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n                insertData(superiorPlayer, farmingTracker);\n\n                for (String key : grownPlants.getConfigurationSection(uuid).getKeys(false)) {\n                    Key typeKey = getMissionPlantKey(Key.ofMaterialAndData(key));\n                    farmingTracker.load(typeKey, grownPlants.getInt(uuid + \".\" + key));\n                }\n            }\n        }\n\n        ConfigurationSection placedPlants = section.getConfigurationSection(\"placed-plants\");\n        if (placedPlants != null) {\n            int dataVersion = section.getInt(\"data-version\", 0);\n\n            if (dataVersion == 0) {\n                loadLegacyData(placedPlants);\n            } else {\n                for (String placerUUID : placedPlants.getKeys(false)) {\n                    UUID placer = UUID.fromString(placerUUID);\n                    ConfigurationSection placerSection = placedPlants.getConfigurationSection(placerUUID);\n                    if (placerSection == null)\n                        continue;\n\n                    for (String worldName : placerSection.getKeys(false)) {\n                        ConfigurationSection worldSection = placerSection.getConfigurationSection(worldName);\n                        if (worldSection == null)\n                            continue;\n\n                        for (String chunkKey : worldSection.getKeys(false)) {\n                            PlantsTracker.INSTANCE.load(worldName, Long.parseLong(chunkKey),\n                                    worldSection.getIntegerList(chunkKey), placer);\n                        }\n                    }\n                }\n\n                ConfigurationSection legacyPlacedPlants = section.getConfigurationSection(\"placed-plants-legacy\");\n                if (legacyPlacedPlants != null)\n                    loadLegacyData(legacyPlacedPlants);\n            }\n        }\n    }\n\n    private void loadLegacyData(ConfigurationSection section) {\n        for (String locationKey : section.getKeys(false)) {\n            UUID placer = UUID.fromString(section.getString(locationKey));\n            String[] sections = locationKey.split(\";\");\n            if (sections.length == 4) {\n                BlockPosition plantPosition = plugin.getFactory().createBlockPosition(Integer.parseInt(sections[1]),\n                        Integer.parseInt(sections[2]), Integer.parseInt(sections[3]));\n                PlantsTracker.INSTANCE.loadLegacy(sections[0], plantPosition, placer);\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        KeyDataTracker farmingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (farmingTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, itemMeta.getDisplayName(), true));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, line, true));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockPlace(BlockPlaceEvent e) {\n        PlantType plantType = PlantType.getBySaplingType(e.getBlock().getType());\n        Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(e.getBlock()) : plantType.getCachedKey();\n\n        if (getMissionPlantKey(plantKey) == null)\n            return;\n\n        PlantsTracker.INSTANCE.track(e.getBlock(), e.getPlayer().getUniqueId());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockBreak(BlockBreakEvent e) {\n        PlantsTracker.INSTANCE.untrack(e.getBlock());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBlockExplode(EntityExplodeEvent e) {\n        for (Block block : e.blockList())\n            PlantsTracker.INSTANCE.untrack(block);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPistonRetract(BlockPistonRetractEvent e) {\n        for (Block block : e.getBlocks())\n            PlantsTracker.INSTANCE.untrack(block);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPistonRetract(BlockPistonExtendEvent e) {\n        for (Block block : e.getBlocks())\n            PlantsTracker.INSTANCE.untrack(block);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onBambooGrow(BlockSpreadEvent e) {\n        handlePlantGrow(e.getBlock(), e.getNewState());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlantGrow(StructureGrowEvent e) {\n        Block block = e.getLocation().getBlock();\n        handlePlantGrow(block, block.getState());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlantGrow(BlockGrowEvent e) {\n        handlePlantGrow(e.getBlock(), e.getNewState());\n    }\n\n    private void handlePlantGrow(Block plantBlock, BlockState newState) {\n        PlantType plantType = PlantType.getByType(newState.getType());\n        Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(newState) : plantType.getCachedKey();\n        plantKey = getMissionPlantKey(plantKey);\n\n        if (plantKey == null)\n            return;\n\n        int maxAge = plantType.getMaxAge();\n        if (maxAge > 0 && getBlockAge(newState) < maxAge)\n            return;\n\n        Location placedBlockLocation = plantBlock.getLocation();\n\n        switch (plantType) {\n            case CACTUS:\n            case SUGAR_CANE:\n            case BAMBOO:\n                placedBlockLocation = getRoot(plantBlock);\n                break;\n            case MELON:\n            case PUMPKIN:\n                placedBlockLocation = getStemRoot(plantType, plantBlock);\n                break;\n            case CHORUS_PLANT:\n                placedBlockLocation = getChorusRoot(plantBlock);\n                break;\n        }\n\n        UUID placerUUID = PlantsTracker.INSTANCE.getPlacer(placedBlockLocation);\n\n        if (placerUUID == null)\n            return;\n\n        SuperiorPlayer playerTracked;\n\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(placerUUID);\n        if (getIslandMission()) {\n            // In case this is an island mission, we want to get the uuid of the owner.\n            Island island = superiorPlayer.getIsland();\n            if (island == null)\n                return;\n            playerTracked = island.getOwner();\n        } else {\n            playerTracked = superiorPlayer;\n        }\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(playerTracked, this))\n            return;\n\n        KeyDataTracker farmingTracker = getOrCreate(playerTracked, s -> new KeyDataTracker());\n\n        if (farmingTracker == null)\n            return;\n\n        farmingTracker.track(plantKey, 1);\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> playerTracked.runIfOnline(player -> {\n            if (canComplete(playerTracked))\n                this.plugin.getMissions().rewardMission(this, playerTracked, true);\n        }), 2L);\n    }\n\n    private int getBlockAge(BlockState newState) {\n        try {\n            BlockData blockData = newState.getBlockData();\n            return blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0;\n        } catch (Throwable error) {\n            // noinspection deprecation\n            return newState.getRawData();\n        }\n    }\n\n    private static Location getRoot(Block original) {\n        Block lastSimilarBlock = original.getRelative(BlockFace.DOWN);\n\n        Material originalType = lastSimilarBlock.getType();\n\n        while (lastSimilarBlock.getType() == originalType) {\n            lastSimilarBlock = lastSimilarBlock.getRelative(BlockFace.DOWN);\n        }\n\n        return lastSimilarBlock.getLocation().add(0, 1, 0);\n    }\n\n    private static Location getStemRoot(PlantType plantType, Block plantBlock) {\n        Material stemType = plantType == PlantType.PUMPKIN ? Material.PUMPKIN_STEM : Material.MELON_STEM;\n\n        for (BlockFace blockFace : STEM_NEARBY_BLOCKS) {\n            Block nearbyBlock = plantBlock.getRelative(blockFace);\n            if (nearbyBlock.getType() == stemType) {\n                return nearbyBlock.getLocation();\n            }\n        }\n\n        return plantBlock.getLocation();\n    }\n\n    private static Location getChorusRoot(Block plantBlock) {\n        return findChorusRoot(plantBlock, BlockFace.SELF).orElseGet(plantBlock::getLocation);\n    }\n\n    private static Optional<Location> findChorusRoot(Block plantBlock, BlockFace ignoredFace) {\n        Block downBlock = plantBlock.getRelative(BlockFace.DOWN);\n\n        if (downBlock.getType() == Material.END_STONE)\n            return Optional.of(plantBlock.getLocation());\n\n        for (BlockFace blockFace : CHORUS_NEARBY_BLOCKS) {\n            if (blockFace != ignoredFace) {\n                Block nearbyBlock = plantBlock.getRelative(blockFace);\n                if (PlantType.getByType(nearbyBlock.getType()) == PlantType.CHORUS_PLANT) {\n                    Optional<Location> nearbyResult = findChorusRoot(nearbyBlock, blockFace.getOppositeFace());\n                    if (nearbyResult.isPresent())\n                        return nearbyResult;\n                }\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    @Nullable\n    private Key getMissionPlantKey(@Nullable Key blockKey) {\n        if (blockKey == null)\n            return null;\n\n        for (KeyRequirements requirement : requiredPlants.keySet()) {\n            if (requirement.contains(blockKey))\n                return requirement.getKey(blockKey);\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.farming;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport org.bukkit.Material;\n\nimport java.util.EnumMap;\n\npublic enum PlantType {\n\n    BAMBOO(0, Plants.of(\"BAMBOO\"), Plants.of(\"BAMBOO_SAPLING\")),\n    BEETROOT(3, Plants.of(\"BEETROOT\", \"BEETROOTS\", \"BEETROOT_SEEDS\")),\n    CACTUS(0, Plants.of(\"CACTUS\")),\n    CARROT(7, Plants.of(\"CARROT\", \"CARROTS\")),\n    CHORUS_PLANT(0, Plants.of(\"CHORUS_PLANT\", \"CHORUS_FLOWER\")),\n    COCOA(2, Plants.of(\"COCOA\", \"COCOA_BEANS\")),\n    MELON(-1, Plants.of(\"MELON\", \"MELON_BLOCK\"), Plants.of(\"MELON_STEM\")),\n    NETHER_WART(3, Plants.of(\"NETHER_WART\", \"NETHER_STALK\")),\n    POTATO(7, Plants.of(\"POTATO\", \"POTATOES\")),\n    PUMPKIN(-1, Plants.of(\"PUMPKIN\"), Plants.of(\"PUMPKIN_STEM\")),\n    SUGAR_CANE(0, Plants.of(\"SUGAR_CANE\", \"SUGAR_CANE_BLOCK\")),\n    SWEET_BERRY_BUSH(3, Plants.of(\"SWEET_BERRY_BUSH\")),\n    WHEAT(7, Plants.of(\"WHEAT\", \"CROPS\", \"WHEAT_SEEDS\")),\n\n    UNKNOWN(-1, Plants.EMPTY);\n\n    private static final EnumMap<Material, PlantType> MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class);\n    private static final EnumMap<Material, PlantType> SAPLING_MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class);\n    private static boolean hasRegisteredPlantTypes = false;\n\n    private final String[] plantTypes;\n    private final String[] saplingTypes;\n    private final int maxAge;\n    private final Key cachedKey;\n\n    PlantType(int maxAge, Plants plantTypes) {\n        this(maxAge, plantTypes, plantTypes);\n    }\n\n    PlantType(int maxAge, Plants plantTypes, Plants saplingTypes) {\n        this.maxAge = maxAge;\n        this.plantTypes = plantTypes.arr;\n        this.saplingTypes = saplingTypes.arr;\n        this.cachedKey = Key.ofMaterialAndData(name());\n    }\n\n    public int getMaxAge() {\n        return maxAge;\n    }\n\n    public Key getCachedKey() {\n        return cachedKey;\n    }\n\n    public static PlantType getByType(Material material) {\n        registerPlantTypes();\n        return MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN);\n    }\n\n    public static PlantType getBySaplingType(Material material) {\n        registerPlantTypes();\n        return SAPLING_MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN);\n    }\n\n    private static void registerPlantType(PlantType plantType) {\n        for (String material : plantType.plantTypes) {\n            try {\n                MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType);\n            } catch (IllegalArgumentException ignored) {\n            }\n        }\n        for (String material : plantType.saplingTypes) {\n            try {\n                SAPLING_MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType);\n            } catch (IllegalArgumentException ignored) {\n            }\n        }\n    }\n\n    private static void registerPlantTypes() {\n        if (!hasRegisteredPlantTypes) {\n            for (PlantType plantType : PlantType.values())\n                registerPlantType(plantType);\n            hasRegisteredPlantTypes = true;\n        }\n    }\n\n    private static class Plants {\n\n        static Plants EMPTY = of();\n\n        private final String[] arr;\n\n        static Plants of(String... arr) {\n            return new Plants(arr);\n        }\n\n        Plants(String[] arr) {\n            this.arr = arr;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.farming;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport javax.annotation.Nullable;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class PlantsTracker {\n\n    public static final PlantsTracker INSTANCE = new PlantsTracker();\n\n    private final Map<String, PlantsTrackingComponent> plantsTracker = new HashMap<>();\n    private Map<String, TrackedPlantsData> rawData = null;\n    private Map<String, Map<UUID, List<BlockPosition>>> legacyRawData = null;\n    private boolean saved = false;\n\n    private PlantsTracker() {\n\n    }\n\n    public void track(Block block, UUID placer) {\n        track(block.getWorld(), block.getX(), block.getY(), block.getZ(), placer);\n    }\n\n    public void track(World world, int x, int y, int z, UUID placer) {\n        loadRawData(world);\n        plantsTracker.computeIfAbsent(world.getName(), s -> new PlantsTrackingComponent(world))\n                .track(x, y, z, placer);\n    }\n\n    public void untrack(Block block) {\n        untrack(block.getWorld(), block.getX(), block.getY(), block.getZ());\n    }\n\n    public void untrack(World world, int x, int y, int z) {\n        loadRawData(world);\n        PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName());\n        if (trackingComponent != null)\n            trackingComponent.untrack(x, y, z);\n    }\n\n    @Nullable\n    public UUID getPlacer(Location location) {\n        World world = location.getWorld();\n        return world == null ? null : getPlacer(world, location.getBlockX(), location.getBlockY(), location.getBlockZ());\n    }\n\n    @Nullable\n    public UUID getPlacer(World world, int x, int y, int z) {\n        loadRawData(world);\n        PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName());\n        return trackingComponent == null ? null : trackingComponent.getPlacer(x, y, z);\n    }\n\n    public void load(String worldName, long chunkKey, List<Integer> blocks, UUID placer) {\n        if (this.rawData == null)\n            this.rawData = new HashMap<>();\n        TrackedPlantsData trackedPlantsData = this.rawData.computeIfAbsent(worldName, w -> new TrackedPlantsData());\n        blocks.forEach(block -> trackedPlantsData.track(chunkKey, block, placer));\n    }\n\n    public void loadLegacy(String worldName, BlockPosition plant, UUID placer) {\n        if (this.legacyRawData == null)\n            this.legacyRawData = new HashMap<>();\n        this.legacyRawData.computeIfAbsent(worldName, w -> new LinkedHashMap<>())\n                .computeIfAbsent(placer, i -> new LinkedList<>()).add(plant);\n    }\n\n    public void save(ConfigurationSection section) {\n        if (!this.saved) {\n            saveInternal(section);\n            this.saved = true;\n        }\n    }\n\n    private void saveInternal(ConfigurationSection section) {\n        MutableBoolean savedData = new MutableBoolean(false);\n\n        this.plantsTracker.forEach((worldName, component) -> {\n            component.getPlants().forEach((chunkKey, blocks) -> {\n                blocks.forEach((block, placer) -> {\n                    String path = \"placed-plants.\" + placer + \".\" + worldName + \".\" + chunkKey;\n                    List<Integer> blocksList = section.getIntegerList(path);\n                    blocksList.add(block);\n                    section.set(path, blocksList);\n                    savedData.set(true);\n                });\n            });\n        });\n\n        if (this.rawData != null) {\n            this.rawData.forEach((worldName, worldData) -> {\n                worldData.getPlants().forEach((chunkKey, blocks) -> {\n                    blocks.forEach((block, placer) -> {\n                        String path = \"placed-plants.\" + placer + \".\" + worldName + \".\" + chunkKey;\n                        List<Integer> blocksList = section.getIntegerList(path);\n                        blocksList.add(block);\n                        section.set(path, blocksList);\n                        savedData.set(true);\n                    });\n                });\n            });\n        }\n\n        if (this.legacyRawData != null) {\n            this.legacyRawData.forEach((worldName, worldData) -> {\n                worldData.forEach((placer, plants) -> {\n                    plants.forEach(plant -> {\n                        String plantKey = worldName + \";\" + plant.getX() + \";\" + plant.getY() + \";\" + plant.getZ();\n                        section.set(\"placed-plants-legacy.\" + plantKey, placer.toString());\n                        savedData.set(true);\n                    });\n                });\n            });\n        }\n\n        if (savedData.get()) {\n            section.set(\"data-version\", 1);\n        }\n    }\n\n    private void loadRawData(World world) {\n        String worldName = world.getName();\n\n        if (this.rawData != null) {\n            TrackedPlantsData rawDataForWorld = this.rawData.remove(worldName);\n            if (rawDataForWorld != null) {\n                plantsTracker.put(worldName, new PlantsTrackingComponent(world, rawDataForWorld));\n\n                if (this.rawData.isEmpty())\n                    this.rawData = null;\n            }\n        }\n\n        if (this.legacyRawData != null) {\n            Map<UUID, List<BlockPosition>> legacyRawDataForWorld = this.legacyRawData.remove(worldName);\n            if (legacyRawDataForWorld != null) {\n                PlantsTrackingComponent plantsTrackingComponent = new PlantsTrackingComponent(world);\n                legacyRawDataForWorld.forEach((placer, plants) -> {\n                    plants.forEach(plant -> plantsTrackingComponent.track(plant.getX(), plant.getY(), plant.getZ(), placer));\n                });\n                this.plantsTracker.put(worldName, plantsTrackingComponent);\n\n                if (this.legacyRawData.isEmpty())\n                    this.legacyRawData = null;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.farming;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport org.bukkit.World;\n\nimport javax.annotation.Nullable;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class PlantsTrackingComponent {\n\n    private static final ReflectMethod<Integer> WORLD_GET_MIN_HEIGHT = new ReflectMethod<>(\n            new ClassInfo(\"CraftWorld\", ClassInfo.PackageType.CRAFTBUKKIT),\n            \"getMinHeight\",\n            new ClassInfo[0]);\n\n    private final TrackedPlantsData trackedPlantsData;\n\n    private final int worldMinHeight;\n\n    public PlantsTrackingComponent(World world) {\n        this(world, new TrackedPlantsData());\n    }\n\n    public PlantsTrackingComponent(World world, TrackedPlantsData trackedPlantsData) {\n        this.worldMinHeight = WORLD_GET_MIN_HEIGHT.isValid() ? WORLD_GET_MIN_HEIGHT.invoke(world) : 0;\n        this.trackedPlantsData = trackedPlantsData;\n    }\n\n    public void track(int x, int y, int z, UUID placer) {\n        int block = getBlockIndex(x, y, z);\n        trackedPlantsData.track(getChunkKey(x, z), block, placer);\n    }\n\n    public void untrack(int x, int y, int z) {\n        int block = getBlockIndex(x, y, z);\n        trackedPlantsData.untrack(getChunkKey(x, z), block);\n    }\n\n    @Nullable\n    public UUID getPlacer(int x, int y, int z) {\n        int block = getBlockIndex(x, y, z);\n        return trackedPlantsData.getPlacer(getChunkKey(x, z), block);\n    }\n\n    public Map<Long, Map<Integer, UUID>> getPlants() {\n        return this.trackedPlantsData.getPlants();\n    }\n\n    private int getBlockIndex(int blockX, int blockY, int blockZ) {\n        int chunkMinX = blockX >> 4 << 4;\n        int chunkMinZ = blockZ >> 4 << 4;\n\n\n        byte relativeX = (byte) (blockX - chunkMinX);\n        short relativeY = (short) (blockY - this.worldMinHeight);\n        byte relativeZ = (byte) (blockZ - chunkMinZ);\n\n        return (relativeY << 8) | (relativeX << 4) | relativeZ;\n    }\n\n    private static long getChunkKey(int blockX, int blockZ) {\n        int chunkX = blockX >> 4;\n        int chunkZ = blockZ >> 4;\n        return (long) chunkX << 32 | chunkZ;\n    }\n\n}\n"
  },
  {
    "path": "Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.farming;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class TrackedPlantsData {\n\n    private final Map<Long, Map<Integer, UUID>> trackedData = new HashMap<>();\n\n    public void track(long chunkKey, int block, UUID placer) {\n        trackedData.computeIfAbsent(chunkKey, i -> new HashMap<>()).put(block, placer);\n    }\n\n    public void untrack(long chunkKey, int block) {\n        Map<Integer, UUID> chunkTrackedData = this.trackedData.get(chunkKey);\n        if (chunkTrackedData != null)\n            chunkTrackedData.remove(block);\n    }\n\n    public UUID getPlacer(long chunkKey, int block) {\n        Map<Integer, UUID> chunkTrackedData = this.trackedData.get(chunkKey);\n        return chunkTrackedData == null ? null : chunkTrackedData.get(block);\n    }\n\n    public Map<Long, Map<Integer, UUID>> getPlants() {\n        return trackedData;\n    }\n\n}\n"
  },
  {
    "path": "Missions/FishingMissions/build.gradle",
    "content": "group 'Missions:FishingMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.fishing'\n}"
  },
  {
    "path": "Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker;\nimport org.bukkit.Bukkit;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.Item;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerFishEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport javax.annotation.Nullable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.UUID;\n\npublic final class FishingMissions extends BuiltinMission<KeyDataTracker> implements Listener {\n\n    private final Map<KeyRequirements, Integer> itemsToCatch = new LinkedHashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredCaughtsSection = section.getConfigurationSection(\"required-caughts\");\n        if (requiredCaughtsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-caughts\\\" section in the config.\");\n\n        for (String key : requiredCaughtsSection.getKeys(false)) {\n            KeySet blocks = KeySet.createKeySet();\n            section.getStringList(\"required-caughts.\" + key + \".types\").forEach(requiredBlock ->\n                    blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH))));\n            int amount = section.getInt(\"required-caughts.\" + key + \".amount\", 1);\n            this.itemsToCatch.put(new KeyRequirements(blocks), amount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(KeyDataTracker data) {\n        data.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker fishingTracker = get(superiorPlayer);\n\n        if (fishingTracker == null)\n            return 0.0;\n\n        int requiredItems = 0;\n        int interactions = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> entry : this.itemsToCatch.entrySet()) {\n            requiredItems += entry.getValue();\n            interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue());\n        }\n\n        return (double) interactions / requiredItems;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker fishingTracker = get(superiorPlayer);\n\n        if (fishingTracker == null)\n            return 0;\n\n        int interactions = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> entry : this.itemsToCatch.entrySet())\n            interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue());\n\n        return interactions;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, KeyDataTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            int index = 0;\n            for (Map.Entry<Key, Counter> craftedEntry : entry.getValue().getCounts().entrySet()) {\n                section.set(uuid + \".\" + index + \".item\", craftedEntry.getKey().toString());\n                section.set(uuid + \".\" + index + \".amount\", craftedEntry.getValue().get());\n                index++;\n            }\n        }\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            if (uuid.equals(\"players\"))\n                continue;\n\n            KeyDataTracker fishingTracker = new KeyDataTracker();\n            UUID playerUUID = UUID.fromString(uuid);\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, fishingTracker);\n\n            for (String key : section.getConfigurationSection(uuid).getKeys(false)) {\n                Key typeKey;\n                if (section.isItemStack(uuid + \".\" + key + \".item\")) {\n                    ItemStack itemStack = section.getItemStack(uuid + \".\" + key + \".item\");\n                    typeKey = itemStack == null ? null : Key.of(itemStack);\n                } else {\n                    typeKey = Key.ofMaterialAndData(section.getString(uuid + \".\" + key + \".item\"));\n                }\n                if (typeKey != null) {\n                    typeKey = getMissionItemKey(typeKey);\n                    int amount = section.getInt(uuid + \".\" + key + \".amount\");\n                    fishingTracker.load(typeKey, amount);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        KeyDataTracker fishingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (fishingTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, itemMeta.getDisplayName(), true));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, line, true));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerFish(PlayerFishEvent e) {\n        if (!(e.getCaught() instanceof Item) || e.getState() != PlayerFishEvent.State.CAUGHT_FISH)\n            return;\n\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        Item caughtItem = (Item) e.getCaught();\n        ItemStack caughtItemStack = caughtItem.getItemStack();\n\n        Key itemKey = getMissionItemKey(Key.of(caughtItemStack));\n        if (itemKey == null)\n            return;\n\n        trackItem(superiorPlayer, itemKey, caughtItemStack.getAmount());\n    }\n\n    private void trackItem(SuperiorPlayer superiorPlayer, Key itemKey, int count) {\n        KeyDataTracker blocksTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (blocksTracker == null)\n            return;\n\n        blocksTracker.track(itemKey, count);\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    @Nullable\n    private Key getMissionItemKey(Key blockKey) {\n        for (KeyRequirements requirementsList : itemsToCatch.keySet()) {\n            if (requirementsList.contains(blockKey))\n                return requirementsList.getKey(blockKey);\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/build.gradle",
    "content": "group 'Missions:IslandMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.island'\n}"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.events.IslandEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent;\nimport com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.island.DynamicRegisteredListener;\nimport com.bgsoftware.superiorskyblock.missions.island.EventsHelper;\nimport com.bgsoftware.superiorskyblock.missions.island.timings.ITimings;\nimport org.bukkit.Bukkit;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.EventException;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.Plugin;\nimport org.bukkit.plugin.RegisteredServiceProvider;\n\nimport javax.annotation.Nullable;\nimport javax.script.SimpleBindings;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\npublic final class IslandMissions extends BuiltinMission<Boolean> implements Listener {\n\n    private String successCheck;\n    private PlaceholdersService placeholdersService;\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        if (!section.contains(\"events\"))\n            throw new MissionLoadException(\"You must have the \\\"events\\\" section in the config.\");\n\n        for (String event : section.getStringList(\"events\")) {\n            boolean targetPlayer = false;\n            String eventName = event;\n\n            if (event.toLowerCase().endsWith(\"-target\")) {\n                targetPlayer = true;\n                eventName = event.split(\"-\")[0];\n            }\n\n            try {\n                registerEventListener(plugin, eventName, targetPlayer);\n            } catch (ClassNotFoundException error) {\n                plugin.getLogger().warning(\"The event \" + eventName + \" is not valid, skipping\");\n            } catch (Exception error) {\n                plugin.getLogger().warning(\"Cannot register IslandMission for \" + eventName + \":\");\n                error.printStackTrace();\n            }\n        }\n\n        this.successCheck = section.getString(\"success-check\", \"true\");\n\n        RegisteredServiceProvider<PlaceholdersService> registeredServiceProvider = plugin.getServer()\n                .getServicesManager().getRegistration(PlaceholdersService.class);\n\n        if (registeredServiceProvider != null) {\n            this.placeholdersService = registeredServiceProvider.getProvider();\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(Boolean data) {\n        // Do nothing\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        return get(superiorPlayer) == null ? 0.0 : 1.0;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        return 0;\n    }\n\n    private void registerEventListener(Plugin plugin, String eventName, boolean isTarget) throws Exception {\n        Class<?> eventClass = Class.forName(\"com.bgsoftware.superiorskyblock.api.events.\" + eventName);\n\n        if (!Event.class.isAssignableFrom(eventClass))\n            return;\n\n        HandlerList handlerList = EventsHelper.getEventListeners(eventClass.asSubclass(Event.class));\n        ITimings timings = ITimings.of(plugin, \"Plugin: \" + plugin.getDescription().getFullName() +\n                \" Event: DynamicRegisteredListener::\" + eventName + \"(\" + eventClass.getSimpleName() + \")\");\n\n        Method getPlayerMethod = getMethodSilently(eventClass, \"getPlayer\");\n        Method getTargetMethod = getMethodSilently(eventClass, \"getTarget\");\n\n        handlerList.register(new DynamicRegisteredListener(plugin, (listener, event) -> {\n            try {\n                if (eventClass.isAssignableFrom(event.getClass()) &&\n                        (event instanceof IslandEvent || event instanceof MissionCompleteEvent)) {\n                    boolean isAsync = event.isAsynchronous();\n\n                    if (!isAsync) {\n                        timings.startTiming();\n                    }\n\n                    SuperiorPlayer superiorPlayer;\n                    SuperiorPlayer targetPlayer;\n\n                    if (event instanceof IslandTransferEvent) {\n                        superiorPlayer = ((IslandTransferEvent) event).getOldOwner();\n                        targetPlayer = ((IslandTransferEvent) event).getNewOwner();\n                    } else {\n                        superiorPlayer = getPlayerMethod != null ? (SuperiorPlayer) getPlayerMethod.invoke(event) :\n                                event instanceof IslandEvent ? ((IslandEvent) event).getIsland().getOwner() : null;\n                        targetPlayer = getTargetMethod == null ? null : (SuperiorPlayer) getTargetMethod.invoke(event);\n                    }\n\n                    tryComplete(event, superiorPlayer, targetPlayer, isTarget);\n\n                    if (!isAsync) {\n                        timings.stopTiming();\n                    }\n                }\n            } catch (InvocationTargetException var4) {\n                throw new EventException(var4.getCause());\n            } catch (Throwable var5) {\n                throw new EventException(var5);\n            }\n        }));\n    }\n\n    private void tryComplete(Event event, @Nullable SuperiorPlayer superiorPlayer,\n                             @Nullable SuperiorPlayer targetPlayer, boolean isTarget) {\n        boolean success = false;\n\n        SimpleBindings bindings = new SimpleBindings();\n        bindings.put(\"event\", event);\n\n        IScriptEngine scriptEngine = this.plugin.getScriptEngine();\n\n        try {\n            String result = scriptEngine.eval(successCheck, bindings) + \"\";\n            if (this.placeholdersService != null && superiorPlayer != null) {\n                result = placeholdersService.parsePlaceholders(superiorPlayer.asOfflinePlayer(), result);\n            }\n            success = Boolean.parseBoolean(result);\n        } catch (Throwable error) {\n            plugin.getLogger().warning(\"Error occurred while checking for success condition for IslandMission.\");\n            plugin.getLogger().warning(\"Current Script Engine: \" + scriptEngine);\n            error.printStackTrace();\n        }\n\n        if (success) {\n            SuperiorPlayer rewardedPlayer = isTarget ? targetPlayer : superiorPlayer;\n            if (rewardedPlayer != null) {\n                Bukkit.getScheduler().runTaskLater(plugin, () -> {\n                    insertData(rewardedPlayer, true);\n                    this.plugin.getMissions().rewardMission(this, rewardedPlayer, true);\n                }, 5L);\n            }\n        }\n    }\n\n    private static Method getMethodSilently(Class<?> clazz, String methodName) {\n        try {\n            return clazz.getDeclaredMethod(methodName);\n        } catch (Exception error) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island;\n\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.EventExecutor;\nimport org.bukkit.plugin.Plugin;\nimport org.bukkit.plugin.TimedRegisteredListener;\n\npublic class DynamicRegisteredListener extends TimedRegisteredListener {\n\n    private static final Listener EMPTY_LISTENER = new Listener() {\n    };\n\n    public DynamicRegisteredListener(Plugin plugin, EventExecutor executor) {\n        super(EMPTY_LISTENER, executor, EventPriority.MONITOR, plugin, true);\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island;\n\nimport org.bukkit.event.Event;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.plugin.IllegalPluginAccessException;\n\nimport java.lang.reflect.Method;\n\npublic class EventsHelper {\n\n    private EventsHelper() {\n\n    }\n\n    public static HandlerList getEventListeners(Class<? extends Event> type) {\n        try {\n            Method method = getRegistrationClass(type).getDeclaredMethod(\"getHandlerList\");\n            method.setAccessible(true);\n            return (HandlerList) method.invoke(null);\n        } catch (Exception var3) {\n            throw new IllegalPluginAccessException(var3.toString());\n        }\n    }\n\n    private static Class<? extends Event> getRegistrationClass(Class<? extends Event> clazz) {\n        try {\n            clazz.getDeclaredMethod(\"getHandlerList\");\n            return clazz;\n        } catch (NoSuchMethodException var3) {\n            if (clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Event.class) && Event.class.isAssignableFrom(clazz.getSuperclass())) {\n                return getRegistrationClass(clazz.getSuperclass().asSubclass(Event.class));\n            } else {\n                throw new IllegalPluginAccessException(\"Unable to find handler list for event \" + clazz.getName() + \". Static getHandlerList method required!\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island.timings;\n\npublic class DummyTimings implements ITimings {\n\n    public static final DummyTimings INSTANCE = new DummyTimings();\n\n    private DummyTimings() {\n\n    }\n\n    @Override\n    public void startTiming() {\n        // Do nothing.\n    }\n\n    @Override\n    public void stopTiming() {\n        // Do nothing.\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island.timings;\n\nimport org.bukkit.plugin.Plugin;\n\npublic interface ITimings {\n\n    void startTiming();\n\n    void stopTiming();\n\n    static ITimings of(Plugin plugin, String name) {\n        try {\n            return TimingsWrapper.create(plugin, name);\n        } catch (Throwable error) {\n            try {\n                return LegacyTimingsWrapper.create(name);\n            } catch (Throwable error2) {\n                return DummyTimings.INSTANCE;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island.timings;\n\nimport org.spigotmc.CustomTimingsHandler;\n\npublic class LegacyTimingsWrapper implements ITimings {\n\n    private final CustomTimingsHandler handle;\n\n    public static ITimings create(String name) {\n        return new LegacyTimingsWrapper(name);\n    }\n\n    private LegacyTimingsWrapper(String name) {\n        this.handle = new CustomTimingsHandler(name);\n    }\n\n    @Override\n    public void startTiming() {\n        this.handle.startTiming();\n    }\n\n    @Override\n    public void stopTiming() {\n        this.handle.stopTiming();\n    }\n\n}\n"
  },
  {
    "path": "Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.island.timings;\n\nimport co.aikar.timings.Timing;\nimport co.aikar.timings.Timings;\nimport co.aikar.timings.TimingsManager;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport org.bukkit.plugin.Plugin;\n\nimport javax.annotation.Nullable;\n\npublic class TimingsWrapper implements ITimings {\n\n    private static final ReflectMethod<Timing> START_TIMING = new ReflectMethod<>(Timing.class, \"startTiming\");\n\n    @Nullable\n    private final Timing handle;\n\n    public static ITimings create(Plugin plugin, String name) {\n        return Timings.isTimingsEnabled() ? new TimingsWrapper(plugin, name) : DummyTimings.INSTANCE;\n    }\n\n    private static final ReflectMethod<Timing> TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT = new ReflectMethod<>(\n            TimingsManager.class, \"getHandler\", String.class, String.class, Timing.class, boolean.class);\n    private static final ReflectMethod<Timing> TIMINGS_MANAGER_GET_HANDLER = new ReflectMethod<>(\n            TimingsManager.class, \"getHandler\", String.class, String.class, Timing.class);\n\n    private TimingsWrapper(Plugin plugin, String name) {\n        String pluginName = plugin.getName();\n\n        if (TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.isValid()) {\n            Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null,\n                    pluginName, \"Combined Total\", TimingsManager.PLUGIN_GROUP_HANDLER, false);\n            this.handle = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null,\n                    pluginName, name, pluginHandler, true);\n        } else if (TIMINGS_MANAGER_GET_HANDLER.isValid()) {\n            Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER.invoke(null,\n                    pluginName, \"Combined Total\", TimingsManager.PLUGIN_GROUP_HANDLER);\n            this.handle = TIMINGS_MANAGER_GET_HANDLER.invoke(null,\n                    pluginName, name, pluginHandler);\n        } else {\n            this.handle = null;\n        }\n    }\n\n    @Override\n    public void startTiming() {\n        if (this.handle != null) {\n            try {\n                this.handle.startTiming();\n            } catch (Throwable error) {\n                START_TIMING.invoke(this.handle);\n            }\n        }\n    }\n\n    @Override\n    public void stopTiming() {\n        if (this.handle != null)\n            this.handle.stopTiming();\n    }\n\n}\n"
  },
  {
    "path": "Missions/ItemsMissions/build.gradle",
    "content": "group 'Missions:ItemsMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.items'\n}"
  },
  {
    "path": "Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.inventory.ClickType;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.event.player.PlayerPickupItemEvent;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.PlayerInventory;\n\nimport javax.annotation.Nullable;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\n@SuppressWarnings(\"unused\")\npublic final class ItemsMissions extends BuiltinMission<ItemsMissions.ItemsTracker> implements Listener {\n\n    private static final int ADDITIONAL_SLOT_START = 36; // Boots\n    private static final int ADDITIONAL_SLOT_END = 40; // Off hand\n\n    private final Map<KeyRequirements, Integer> requiredItems = new LinkedHashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredItemsSection = section.getConfigurationSection(\"required-items\");\n\n        if (requiredItemsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-items\\\" section in the config.\");\n\n        for (String key : requiredItemsSection.getKeys(false)) {\n            KeySet itemStacks = KeySet.createKeySet();\n            section.getStringList(\"required-items.\" + key + \".types\").forEach(itemStackName ->\n                    itemStacks.add(Key.ofMaterialAndData(itemStackName.toUpperCase(Locale.ENGLISH))));\n            int requiredAmount = section.getInt(\"required-items.\" + key + \".amount\");\n            requiredItems.put(new KeyRequirements(itemStacks), requiredAmount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(ItemsTracker data) {\n        data.itemsTracker.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        double progress = 0.0;\n\n        Player player = superiorPlayer.asPlayer();\n\n        if (player == null)\n            return progress;\n\n        Inventory inventory = player.getInventory();\n        Map<ItemStack, Integer> countedItems = countItems(inventory);\n\n        int totalRequiredAmount = 0;\n        int totalItemAmount = 0;\n\n        ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker());\n\n        if (itemsTracker == null)\n            return 0.0;\n\n        for (Map.Entry<KeyRequirements, Integer> entry : requiredItems.entrySet()) {\n            KeyRequirements requirement = entry.getKey();\n            int requiredAmount = entry.getValue();\n\n            int itemAmount = 0;\n            for (Key item : requirement) {\n                try {\n                    //Get the amount of the item.\n                    Material type = Material.valueOf(item.getGlobalKey());\n                    short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey());\n                    int currentItemAmount = countedItems.get(new ItemStack(type, 1, data));\n\n                    //Making sure to not exceed the required item amount\n                    if (itemAmount + currentItemAmount > requiredAmount)\n                        currentItemAmount = requiredAmount - itemAmount;\n\n                    //Summing the amount to a global variable\n                    itemAmount += currentItemAmount;\n\n                    //Adding the item to a list, so we can remove it later.\n                    itemsTracker.track(new ItemStack(type, currentItemAmount, data));\n                } catch (Exception ignored) {\n                }\n            }\n\n            totalRequiredAmount += requiredAmount;\n            totalItemAmount += itemAmount;\n        }\n\n        progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount);\n\n        return progress;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        Player player = superiorPlayer.asPlayer();\n\n        if (player == null)\n            return 0;\n\n        Inventory inventory = player.getInventory();\n        Map<ItemStack, Integer> countedItems = countItems(inventory);\n\n        int totalItemAmount = 0;\n\n        ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker());\n\n        if (itemsTracker == null)\n            return 0;\n\n        for (Map.Entry<KeyRequirements, Integer> entry : requiredItems.entrySet()) {\n            KeyRequirements requirement = entry.getKey();\n            int requiredAmount = entry.getValue();\n\n            int itemAmount = 0;\n            for (Key item : requirement) {\n                try {\n                    //Get the amount of the item.\n                    Material type = Material.valueOf(item.getGlobalKey());\n                    short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey());\n                    int currentItemAmount = countedItems.get(new ItemStack(type, 1, data));\n\n                    //Making sure to not exceed the required item amount\n                    if (itemAmount + currentItemAmount > requiredAmount)\n                        currentItemAmount = requiredAmount - itemAmount;\n\n                    //Summing the amount to a global variable\n                    itemAmount += currentItemAmount;\n\n                    //Adding the item to a list, so we can remove it later.\n                    itemsTracker.track(new ItemStack(type, currentItemAmount, data));\n                } catch (Exception ignored) {\n                }\n            }\n\n            totalItemAmount += itemAmount;\n        }\n\n        return totalItemAmount;\n    }\n\n    @Override\n    public void onComplete(SuperiorPlayer superiorPlayer) {\n        getProgress(superiorPlayer);\n        ItemsTracker itemsTracker = get(superiorPlayer);\n\n        if (itemsTracker == null)\n            return;\n\n        Player player = superiorPlayer.asPlayer();\n        assert player != null;\n\n        removeItems(player.getInventory(), itemsTracker.getItems().toArray(new ItemStack[0]));\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onItemPickup(PlayerPickupItemEvent e) {\n        ItemStack itemStack = e.getItem().getItemStack();\n        handleItemPickup(e.getPlayer(), e.getItem().getItemStack());\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onInventoryClick(InventoryClickEvent e) {\n        if (!(e.getWhoClicked() instanceof Player) || e.getClickedInventory() == null ||\n                e.getClickedInventory().getType() != InventoryType.CHEST || e.getClick() != ClickType.SHIFT_LEFT)\n            return;\n\n        handleItemPickup((Player) e.getWhoClicked(), e.getCurrentItem());\n    }\n\n    private void handleItemPickup(Player player, @Nullable ItemStack itemStack) {\n        if (!isMissionItem(itemStack))\n            return;\n\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(unused -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private boolean isMissionItem(@Nullable ItemStack itemStack) {\n        if (itemStack == null)\n            return false;\n\n        for (KeyRequirements requirement : requiredItems.keySet()) {\n            if (requirement.contains(Key.of(itemStack)))\n                return true;\n        }\n\n        return false;\n    }\n\n    private static Map<ItemStack, Integer> countItems(Inventory inventory) {\n        Map<ItemStack, Integer> countedItems = new HashMap<>();\n\n        Arrays.stream(inventory.getContents()).filter(Objects::nonNull).forEach(itemStack -> {\n            ItemStack key = itemStack.clone();\n            key.setAmount(1);\n            countedItems.put(key, countedItems.getOrDefault(key, 0) + itemStack.getAmount());\n        });\n\n        return countedItems;\n    }\n\n    private static void removeItems(PlayerInventory inventory, ItemStack... itemStacks) {\n        Collection<ItemStack> leftOvers = inventory.removeItem(itemStacks).values();\n\n        if (leftOvers.isEmpty())\n            return;\n\n        // We try to remove the item from the offhand as well.\n\n        for (int additionalSlot = ADDITIONAL_SLOT_START; additionalSlot < ADDITIONAL_SLOT_END; ++additionalSlot) {\n            ItemStack additionalItem;\n\n            try {\n                additionalItem = inventory.getItem(additionalSlot);\n            } catch (Exception ignored) {\n                continue;\n            }\n\n            if (additionalItem != null && additionalItem.getType() != Material.AIR) {\n                for (ItemStack itemStack : leftOvers) {\n                    if (additionalItem.isSimilar(itemStack)) {\n                        if (additionalItem.getAmount() > itemStack.getAmount()) {\n                            additionalItem.setAmount(additionalItem.getAmount() - itemStack.getAmount());\n                        } else {\n                            itemStack.setAmount(itemStack.getAmount() - additionalItem.getAmount());\n                            inventory.setItem(additionalSlot, new ItemStack(Material.AIR));\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public static class ItemsTracker {\n\n        private final Set<ItemStack> itemsTracker = new HashSet<>();\n\n        void track(ItemStack itemStack) {\n            itemsTracker.add(itemStack.clone());\n        }\n\n        Set<ItemStack> getItems() {\n            return itemsTracker;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/KillsMissions/build.gradle",
    "content": "group 'Missions:KillsMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly 'com.bgsoftware:WildStackerAPI:3.6.3'\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.kills'\n}"
  },
  {
    "path": "Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker;\nimport com.bgsoftware.wildstacker.api.WildStackerAPI;\nimport org.bukkit.Bukkit;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.LivingEntity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.Projectile;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.entity.EntityDamageByEntityEvent;\nimport org.bukkit.event.entity.EntityDamageEvent;\nimport org.bukkit.event.entity.EntityDeathEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.projectiles.ProjectileSource;\n\nimport javax.annotation.Nullable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.UUID;\nimport java.util.function.Function;\n\npublic final class KillsMissions extends BuiltinMission<KeyDataTracker> implements Listener {\n\n    private final Map<KeyRequirements, Integer> requiredEntities = new LinkedHashMap<>();\n\n    private Function<LivingEntity, Integer> getEntityCount;\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredEntitiesSection = section.getConfigurationSection(\"required-entities\");\n\n        if (requiredEntitiesSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-entities\\\" section in the config.\");\n\n        for (String key : requiredEntitiesSection.getKeys(false)) {\n            KeySet entityTypes = KeySet.createKeySet();\n            section.getStringList(\"required-entities.\" + key + \".types\").forEach(entityTypeName ->\n                    entityTypes.add(Key.ofEntityType(entityTypeName.toUpperCase(Locale.ENGLISH))));\n            int requiredAmount = section.getInt(\"required-entities.\" + key + \".amount\");\n            requiredEntities.put(new KeyRequirements(entityTypes), requiredAmount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n\n        plugin.getServer().getScheduler().runTaskLater(plugin, () -> {\n            if (plugin.getServer().getPluginManager().isPluginEnabled(\"WildStacker\")) {\n                this.getEntityCount = WildStackerAPI::getEntityAmount;\n            } else {\n                this.getEntityCount = entity -> 1;\n            }\n        }, 1L);\n    }\n\n    @Override\n    protected void clearModuleData(KeyDataTracker data) {\n        data.clear();\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker killsTracker = get(superiorPlayer);\n\n        if (killsTracker == null)\n            return 0.0;\n\n        int requiredEntities = 0;\n        int kills = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredEntity : this.requiredEntities.entrySet()) {\n            requiredEntities += requiredEntity.getValue();\n            kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue());\n        }\n\n        return (double) kills / requiredEntities;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        KeyDataTracker killsTracker = get(superiorPlayer);\n\n        if (killsTracker == null)\n            return 0;\n\n        int kills = 0;\n\n        for (Map.Entry<KeyRequirements, Integer> requiredEntity : this.requiredEntities.entrySet())\n            kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue());\n\n        return kills;\n    }\n\n    @Override\n    public void saveProgress(ConfigurationSection section) {\n        for (Map.Entry<SuperiorPlayer, KeyDataTracker> entry : entrySet()) {\n            String uuid = entry.getKey().getUniqueId().toString();\n            entry.getValue().getCounts().forEach((killedType, count) ->\n                    section.set(uuid + \".\" + killedType, count.get()));\n        }\n    }\n\n    @Override\n    public void loadProgress(ConfigurationSection section) {\n        for (String uuid : section.getKeys(false)) {\n            KeyDataTracker killsTracker = new KeyDataTracker();\n            UUID playerUUID = UUID.fromString(uuid);\n            SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID);\n\n            insertData(superiorPlayer, killsTracker);\n\n            for (String key : section.getConfigurationSection(uuid).getKeys(false)) {\n                killsTracker.load(Key.ofEntityType(key), section.getInt(uuid + \".\" + key));\n            }\n        }\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (killsTracker == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, itemMeta.getDisplayName(), false));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, line, false));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onEntityKill(EntityDeathEvent e) {\n        if (!isMissionEntity(e.getEntity()))\n            return;\n\n        EntityDamageEvent damageCause = e.getEntity().getLastDamageCause();\n\n        if (!(damageCause instanceof EntityDamageByEntityEvent))\n            return;\n\n        EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) damageCause;\n\n        Player damager = null;\n\n        if (entityDamageByEntityEvent.getDamager() instanceof Player) {\n            damager = (Player) entityDamageByEntityEvent.getDamager();\n        } else if (entityDamageByEntityEvent.getDamager() instanceof Projectile) {\n            ProjectileSource shooter = ((Projectile) entityDamageByEntityEvent.getDamager()).getShooter();\n            if (shooter instanceof Player)\n                damager = (Player) shooter;\n        }\n\n        if (damager == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(damager);\n\n        if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker());\n\n        if (killsTracker == null)\n            return;\n\n        killsTracker.track(Key.of(e.getEntity()), this.getEntityCount.apply(e.getEntity()));\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private boolean isMissionEntity(@Nullable Entity entity) {\n        if (entity == null || entity instanceof ArmorStand)\n            return false;\n\n        Key entityKey = Key.of(entity);\n\n        for (KeyRequirements requirement : requiredEntities.keySet()) {\n            if (requirement.contains(entityKey))\n                return true;\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "Missions/StatisticsMissions/build.gradle",
    "content": "group 'Missions:StatisticsMissions'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n}\n\nshadowJar {\n    relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.statistics'\n}"
  },
  {
    "path": "Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.missions;\n\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.missions.common.BuiltinMission;\nimport com.bgsoftware.superiorskyblock.missions.common.Placeholders;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Material;\nimport org.bukkit.Statistic;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerStatisticIncrementEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport javax.annotation.Nullable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.OptionalInt;\n\npublic final class StatisticsMissions extends BuiltinMission<Void> implements Listener {\n\n    private final Map<Requirements, Integer> requiredStatistics = new LinkedHashMap<>();\n\n    @Override\n    protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException {\n        ConfigurationSection requiredStatisticsSection = section.getConfigurationSection(\"required-statistics\");\n\n        if (requiredStatisticsSection == null)\n            throw new MissionLoadException(\"You must have the \\\"required-blocks\\\" section in the config.\");\n\n        for (String key : requiredStatisticsSection.getKeys(false)) {\n            List<String> statistics = section.getStringList(\"required-statistics.\" + key + \".statistics\");\n            int requiredAmount = section.getInt(\"required-statistics.\" + key + \".amount\");\n            requiredStatistics.put(new Requirements(statistics), requiredAmount);\n        }\n    }\n\n    @Override\n    protected void registerListeners() {\n        registerListener(this);\n    }\n\n    @Override\n    protected void clearModuleData(Void data) {\n        // Do nothing\n    }\n\n    @Override\n    public double getProgress(SuperiorPlayer superiorPlayer) {\n        double progress = 0.0;\n        int totalRequiredAmount = 0;\n        int totalItemAmount = 0;\n        Player player = superiorPlayer.asPlayer();\n\n        if (player == null)\n            return progress;\n\n        for (Map.Entry<Requirements, Integer> entry : this.requiredStatistics.entrySet()) {\n            Requirements requirement = entry.getKey();\n            int requiredAmount = entry.getValue();\n\n            int statisticAmount = 0;\n            for (String statistic : requirement) {\n                OptionalInt currentStatisticAmountOptional = getStatisticAmount(player, statistic);\n\n                if (!currentStatisticAmountOptional.isPresent())\n                    continue;\n\n                int currentStatisticAmount = currentStatisticAmountOptional.getAsInt();\n\n                //Making sure to not exceed the required item amount\n                if (statisticAmount + currentStatisticAmount > requiredAmount)\n                    currentStatisticAmount = requiredAmount - statisticAmount;\n\n                //Summing the amount to a global variable\n                statisticAmount += currentStatisticAmount;\n            }\n\n            totalRequiredAmount += requiredAmount;\n            totalItemAmount += statisticAmount;\n        }\n\n        progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount);\n\n        return progress;\n    }\n\n    @Override\n    public int getProgressValue(SuperiorPlayer superiorPlayer) {\n        int totalItemAmount = 0;\n\n        Player player = superiorPlayer.asPlayer();\n        if (player == null)\n            return totalItemAmount;\n\n        for (Map.Entry<Requirements, Integer> entry : this.requiredStatistics.entrySet()) {\n            Requirements requirement = entry.getKey();\n            int requiredAmount = entry.getValue();\n\n            int statisticAmount = 0;\n            for (String statistic : requirement) {\n                OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic);\n\n                if (!currentItemAmountOptional.isPresent())\n                    continue;\n\n                int currentItemAmount = currentItemAmountOptional.getAsInt();\n\n                //Making sure to not exceed the required item amount\n                if (statisticAmount + currentItemAmount > requiredAmount)\n                    currentItemAmount = requiredAmount - statisticAmount;\n\n                //Summing the amount to a global variable\n                statisticAmount += currentItemAmount;\n            }\n\n            totalItemAmount += statisticAmount;\n        }\n\n        return totalItemAmount;\n    }\n\n    @Override\n    public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) {\n        Player player = superiorPlayer.asPlayer();\n\n        if (player == null)\n            return;\n\n        ItemMeta itemMeta = itemStack.getItemMeta();\n\n        if (itemMeta == null)\n            return;\n\n        Placeholders.PlaceholdersFunctions<Requirements> placeholdersFunctions = new Placeholders.PlaceholdersFunctions<Requirements>() {\n            @Override\n            public Requirements getRequirementFromKey(String key) {\n                for (Requirements requirements : requiredStatistics.keySet()) {\n                    if (requirements.contains(key))\n                        return requirements;\n                }\n\n                return null;\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(Requirements requirement) {\n                return Optional.ofNullable(requiredStatistics.get(requirement));\n            }\n\n            @Override\n            public int getCountForRequirement(Requirements requirement) {\n                int statisticAmount = 0;\n\n                for (String statistic : requirement) {\n                    OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic);\n\n                    if (currentItemAmountOptional.isPresent())\n                        statisticAmount += currentItemAmountOptional.getAsInt();\n                }\n\n                return statisticAmount;\n            }\n        };\n\n        if (itemMeta.hasDisplayName())\n            itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions));\n\n        if (itemMeta.hasLore()) {\n            List<String> lore = new ArrayList<>();\n            for (String line : Objects.requireNonNull(itemMeta.getLore()))\n                lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions));\n            itemMeta.setLore(lore);\n        }\n\n        itemStack.setItemMeta(itemMeta);\n    }\n\n    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n    public void onPlayerStatistic(PlayerStatisticIncrementEvent e) {\n        SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n\n        if (!isMissionStatistic(e.getStatistic()) || !this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this))\n            return;\n\n        Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> {\n            if (canComplete(superiorPlayer))\n                this.plugin.getMissions().rewardMission(this, superiorPlayer, true);\n        }), 2L);\n    }\n\n    private boolean isMissionStatistic(@Nullable Statistic statistic) {\n        if (statistic == null)\n            return false;\n\n        for (Requirements requirement : requiredStatistics.keySet()) {\n            if (requirement.contains(statistic.name()) || (statistic.isSubstatistic() &&\n                    requirement.stream().anyMatch(line -> line.contains(statistic.name()))))\n                return true;\n        }\n\n        return false;\n    }\n\n    private static OptionalInt getStatisticAmount(Player player, String statisticsString) {\n        String[] sections = statisticsString.split(\":\");\n        OptionalInt currentStatisticAmount = OptionalInt.empty();\n\n        try {\n            Statistic statistic = Statistic.valueOf(sections[0]);\n\n            if (sections.length == 1) {\n                currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic));\n            } else if (sections.length == 2) {\n                Material material = getEnumSafe(Material.class, sections[1]);\n                if (material != null) {\n                    currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, material));\n                } else {\n                    EntityType entityType = getEnumSafe(EntityType.class, sections[1]);\n                    if (entityType != null)\n                        currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, entityType));\n                }\n            }\n        } catch (Exception ignored) {\n        }\n\n        return currentStatisticAmount;\n    }\n\n    private static <T extends Enum<T>> T getEnumSafe(Class<T> clazz, String name) {\n        try {\n            return Enum.valueOf(clazz, name);\n        } catch (Throwable ex) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "Missions/build.gradle",
    "content": "group 'Missions'\n\nsubprojects {\n    dependencies {\n        implementation project(\":Missions\")\n        compileOnly project(\":API\")\n        compileOnly project(\":\")\n    }\n}\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionLoadException;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.Listener;\nimport org.bukkit.plugin.java.JavaPlugin;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic abstract class BuiltinMission<V> extends Mission<V> {\n\n    private final List<Listener> registeredListeners = new LinkedList<>();\n\n    protected SuperiorSkyblock plugin;\n\n    @Override\n    public final void load(JavaPlugin plugin, ConfigurationSection section) throws MissionLoadException {\n        this.plugin = (SuperiorSkyblock) plugin;\n\n        loadConfiguration(section);\n        registerListeners();\n\n        setClearMethod(this::clearModuleData);\n    }\n\n    protected abstract void loadConfiguration(ConfigurationSection section) throws MissionLoadException;\n\n    protected abstract void registerListeners();\n\n    protected abstract void clearModuleData(V data);\n\n    protected final void registerListener(Listener listener) {\n        Bukkit.getPluginManager().registerEvents(listener, plugin);\n        this.registeredListeners.add(listener);\n    }\n\n    @Override\n    public void onComplete(SuperiorPlayer superiorPlayer) {\n\n    }\n\n    @Override\n    public void onCompleteFail(SuperiorPlayer superiorPlayer) {\n\n    }\n\n    public final void unload() {\n        this.registeredListeners.forEach(HandlerList::unregisterAll);\n        this.registeredListeners.clear();\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements;\nimport com.bgsoftware.superiorskyblock.missions.common.tracker.DataTracker;\nimport org.bukkit.ChatColor;\n\nimport javax.annotation.Nullable;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class Placeholders {\n\n    private static final Pattern PERCENTAGE_PATTERN = Pattern.compile(\"\\\\{percentage_(.+?)}\");\n    private static final Pattern VALUES_PATTERN = Pattern.compile(\"\\\\{value_(.+?)}\");\n\n    private static final Function<String, Key> MATERIAL_KEY_CREATION = Key::ofMaterialAndData;\n    private static final Function<String, Key> ENTITY_KEY_CREATION = Key::ofEntityType;\n\n    private Placeholders() {\n\n    }\n\n    public static String parseKeyPlaceholders(Map<KeyRequirements, Integer> requirements,\n                                              DataTracker<Key, KeyRequirements> dataTracker,\n                                              String line, boolean isMaterial) {\n        Function<String, Key> creationMethod;\n\n        if (isMaterial) {\n            creationMethod = MATERIAL_KEY_CREATION;\n        } else {\n            creationMethod = ENTITY_KEY_CREATION;\n        }\n\n        return parsePlaceholders(line, new PlaceholdersFunctions<KeyRequirements>() {\n            @Override\n            public KeyRequirements getRequirementFromKey(String key) {\n                Key requirementKey = creationMethod.apply(key);\n\n                for (KeyRequirements requirements : requirements.keySet()) {\n                    if (requirements.contains(requirementKey)) {\n                        return requirements;\n                    }\n                }\n\n                return null;\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(KeyRequirements requirementsKey) {\n                return Optional.ofNullable(requirements.get(requirementsKey));\n            }\n\n            @Override\n            public int getCountForRequirement(KeyRequirements requirementsKey) {\n                int totalCount = 0;\n\n                for (Key requirementKey : requirementsKey) {\n                    totalCount += dataTracker.getCount(requirementKey);\n                }\n\n                return totalCount;\n            }\n        });\n    }\n\n    public static String parsePlaceholders(Map<Requirements, Integer> requirements, DataTracker<String, Requirements> dataTracker, String line) {\n        return parsePlaceholders(line, new PlaceholdersFunctions<Requirements>() {\n            @Override\n            public Requirements getRequirementFromKey(String key) {\n                for (Requirements requirements : requirements.keySet()) {\n                    if (requirements.contains(key))\n                        return requirements;\n                }\n\n                return null;\n            }\n\n            @Override\n            public Optional<Integer> lookupRequirement(Requirements requirementsKey) {\n                return Optional.ofNullable(requirements.get(requirementsKey));\n            }\n\n            @Override\n            public int getCountForRequirement(Requirements requirementsKey) {\n                int totalCount = 0;\n\n                for (String requirementKey : requirementsKey) {\n                    totalCount += dataTracker.getCount(requirementKey);\n                }\n\n                return totalCount;\n            }\n        });\n    }\n\n    public static <E> String parsePlaceholders(String line, PlaceholdersFunctions<E> functions) {\n        Matcher matcher = PERCENTAGE_PATTERN.matcher(line);\n        if (matcher.find()) {\n            String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH);\n            E requirement = functions.getRequirementFromKey(requirementKey);\n            Optional<Integer> entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement);\n\n            if (entry.isPresent()) {\n                int count = Math.min(functions.getCountForRequirement(requirement), entry.get());\n                line = matcher.replaceAll(\"\" + (count * 100) / entry.get());\n            }\n        }\n\n        if ((matcher = VALUES_PATTERN.matcher(line)).find()) {\n            String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH);\n            E requirement = functions.getRequirementFromKey(requirementKey);\n            Optional<Integer> entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement);\n\n            if (entry.isPresent()) {\n                int count = Math.min(functions.getCountForRequirement(requirement), entry.get());\n                line = matcher.replaceAll(String.valueOf(count));\n            }\n        }\n\n        return ChatColor.translateAlternateColorCodes('&', line);\n    }\n\n    public static abstract class PlaceholdersFunctions<E> {\n\n        @Nullable\n        public abstract E getRequirementFromKey(String key);\n\n        public abstract Optional<Integer> lookupRequirement(E requirement);\n\n        public abstract int getCountForRequirement(E requirement);\n\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.requirements;\n\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\n\npublic class CustomRequirements<E> extends RequirementsAbstract<E> {\n\n    public CustomRequirements() {\n        super(new LinkedHashSet<>());\n    }\n\n    public CustomRequirements(Collection<E> elements) {\n        this();\n        addAll(elements);\n    }\n\n    @Override\n    protected boolean isAllElement(E element) {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.requirements;\n\nimport java.util.Set;\n\npublic interface IRequirements<K> extends Set<K> {\n\n    boolean isContainsAll();\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.requirements;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\n\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\n\npublic class KeyRequirements extends RequirementsAbstract<Key> {\n\n    public KeyRequirements(Collection<Key> elements) {\n        super(KeySet.createKeySet(LinkedHashSet::new));\n        addAll(elements);\n    }\n\n    @Override\n    protected boolean isAllElement(Key element) {\n        return element.getGlobalKey().equalsIgnoreCase(\"ALL\");\n    }\n\n    public Key getKey(Key original) {\n        return ((KeySet) delegate()).getKey(original, original);\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.requirements;\n\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\n\npublic class Requirements extends RequirementsAbstract<String> {\n\n    public Requirements(Collection<String> elements) {\n        super(new LinkedHashSet<>());\n        addAll(elements);\n    }\n\n    @Override\n    protected boolean isAllElement(String element) {\n        return element.equalsIgnoreCase(\"all\");\n    }\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.requirements;\n\nimport com.google.common.collect.ForwardingSet;\n\nimport java.util.Set;\n\npublic abstract class RequirementsAbstract<E> extends ForwardingSet<E> implements IRequirements<E> {\n\n    private final Set<E> handle;\n    private boolean containsAll = false;\n\n    public RequirementsAbstract(Set<E> handle) {\n        this.handle = handle;\n    }\n\n    @Override\n    public boolean add(E element) {\n        if (containsAll)\n            return true;\n\n        if (isAllElement(element)) {\n            this.containsAll = true;\n            return true;\n        }\n\n        return super.add(element);\n    }\n\n    @Override\n    public boolean contains(Object object) {\n        return isContainsAll() || super.contains(object);\n    }\n\n    public boolean isContainsAll() {\n        return this.containsAll;\n    }\n\n    @Override\n    protected Set<E> delegate() {\n        return this.handle;\n    }\n\n    protected abstract boolean isAllElement(E element);\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.tracker;\n\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.IRequirements;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Optional;\n\npublic abstract class DataTracker<K, R extends IRequirements<K>> {\n\n    private final Map<K, Counter> trackedData;\n    private final Counter globalCounter = new Counter(0);\n\n    protected DataTracker(Map<K, Counter> trackedData) {\n        this.trackedData = trackedData;\n    }\n\n    public void track(K key, int amount) {\n        this.trackedData.computeIfAbsent(key, k -> new Counter(0)).inc(amount);\n        globalCounter.inc(amount);\n    }\n\n    public void load(K blockKey, int amount) {\n        this.trackedData.put(blockKey, new Counter(amount));\n        globalCounter.inc(amount);\n    }\n\n    public int getCount(K blockKey) {\n        return Optional.ofNullable(this.trackedData.get(blockKey)).map(Counter::get).orElse(0);\n    }\n\n    public int getGlobalCounter() {\n        return this.globalCounter.get();\n    }\n\n    public int getCounts(R blocks) {\n        if (blocks.isContainsAll())\n            return getGlobalCounter();\n\n        Counter blocksCount = new Counter(0);\n        blocks.forEach(block -> blocksCount.inc(getCount(block)));\n        return blocksCount.get();\n    }\n\n    public void clear() {\n        this.trackedData.clear();\n    }\n\n    public Map<K, Counter> getCounts() {\n        return Collections.unmodifiableMap(this.trackedData);\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.tracker;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements;\n\npublic class KeyDataTracker extends DataTracker<Key, KeyRequirements> {\n\n    public KeyDataTracker() {\n        super(KeyMap.createKeyMap());\n    }\n\n}\n"
  },
  {
    "path": "Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.missions.common.tracker;\n\nimport com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements;\n\nimport java.util.HashMap;\n\npublic class RawDataTracker extends DataTracker<String, Requirements> {\n\n    public RawDataTracker() {\n        super(new HashMap<>());\n    }\n\n}\n"
  },
  {
    "path": "NMS/Paper/build.gradle",
    "content": "group 'NMS:Paper'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":NMS:Spigot\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}"
  },
  {
    "path": "NMS/Paper/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/PaperGlowEnchantment.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.algorithms;\n\nimport io.papermc.paper.enchantments.EnchantmentRarity;\nimport net.kyori.adventure.text.Component;\nimport org.bukkit.entity.EntityCategory;\nimport org.bukkit.inventory.EquipmentSlot;\n\nimport java.util.Collections;\nimport java.util.Set;\n\npublic class PaperGlowEnchantment extends SpigotGlowEnchantment {\n\n    public PaperGlowEnchantment(String name) {\n        super(name);\n    }\n\n    @Override\n    public Component displayName(int i) {\n        return Component.empty();\n    }\n\n    @Override\n    public boolean isTradeable() {\n        return false;\n    }\n\n    @Override\n    public boolean isDiscoverable() {\n        return false;\n    }\n\n    @Override\n    public EnchantmentRarity getRarity() {\n        return EnchantmentRarity.COMMON;\n    }\n\n    @Override\n    public float getDamageIncrease(int i, EntityCategory entityCategory) {\n        return 0;\n    }\n\n    @Override\n    public Set<EquipmentSlot> getActiveSlots() {\n        return Collections.emptySet();\n    }\n\n}\n"
  },
  {
    "path": "NMS/Paper-1_20_3/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\ngroup 'NMS:Paper-1_20_3'\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ndependencies {\n    paperweight.paperDevBundle(\"1.20.4-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}"
  },
  {
    "path": "NMS/Paper-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/PaperGlowEnchantment.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms;\n\nimport io.papermc.paper.enchantments.EnchantmentRarity;\nimport net.kyori.adventure.text.Component;\nimport org.bukkit.entity.EntityCategory;\nimport org.bukkit.inventory.EquipmentSlot;\n\nimport java.util.Collections;\nimport java.util.Set;\n\npublic class PaperGlowEnchantment extends SpigotGlowEnchantment {\n\n    public PaperGlowEnchantment(String name) {\n        super(name);\n    }\n\n    @Override\n    public Component displayName(int i) {\n        return Component.empty();\n    }\n\n    @Override\n    public boolean isTradeable() {\n        return false;\n    }\n\n    @Override\n    public boolean isDiscoverable() {\n        return false;\n    }\n\n    @Override\n    public EnchantmentRarity getRarity() {\n        return EnchantmentRarity.COMMON;\n    }\n\n    @Override\n    public float getDamageIncrease(int i, EntityCategory entityCategory) {\n        return 0;\n    }\n\n    @Override\n    public Set<EquipmentSlot> getActiveSlots() {\n        return Collections.emptySet();\n    }\n\n}\n"
  },
  {
    "path": "NMS/Spigot/build.gradle",
    "content": "group 'NMS:Spigot'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}"
  },
  {
    "path": "NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.algorithms;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.data.BlockData;\n\npublic class NMSCachedBlock implements ICachedBlock {\n\n    private static final ObjectsPool<NMSCachedBlock> POOL = new ObjectsPool<>(NMSCachedBlock::new);\n\n    private BlockData blockData;\n\n    public static NMSCachedBlock obtain(Block block) {\n        return POOL.obtain().initialize(block);\n    }\n\n    private NMSCachedBlock() {\n    }\n\n    private NMSCachedBlock initialize(Block block) {\n        this.blockData = block.getBlockData();\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location) {\n        World world = location.getWorld();\n        if (world != null)\n            world.getBlockAt(location).setBlockData(blockData);\n    }\n\n    @Override\n    public void release() {\n        this.blockData = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/SpigotGlowEnchantment.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.algorithms;\n\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.enchantments.EnchantmentTarget;\n\npublic class SpigotGlowEnchantment extends Enchantment {\n\n    public SpigotGlowEnchantment(String name) {\n        super(NamespacedKey.minecraft(name));\n    }\n\n    @Override\n    public String getName() {\n        return \"SuperiorSkyblockGlow\";\n    }\n\n    @Override\n    public int getMaxLevel() {\n        return 1;\n    }\n\n    @Override\n    public int getStartLevel() {\n        return 0;\n    }\n\n    @Override\n    public EnchantmentTarget getItemTarget() {\n        return null;\n    }\n\n    public boolean isTreasure() {\n        return false;\n    }\n\n    public boolean isCursed() {\n        return false;\n    }\n\n    @Override\n    public boolean conflictsWith(Enchantment enchantment) {\n        return false;\n    }\n\n    @Override\n    public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "NMS/Spigot-1_20_3/build.gradle",
    "content": "group 'NMS:Spigot-1_20_R3'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_20_R3:b3973-3\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}"
  },
  {
    "path": "NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.data.BlockData;\n\npublic class NMSCachedBlock implements ICachedBlock {\n\n    private static final ObjectsPool<NMSCachedBlock> POOL = new ObjectsPool<>(NMSCachedBlock::new);\n\n    private BlockData blockData;\n\n    public static NMSCachedBlock obtain(Block block) {\n        return POOL.obtain().initialize(block);\n    }\n\n    private NMSCachedBlock() {\n    }\n\n    private NMSCachedBlock initialize(Block block) {\n        this.blockData = block.getBlockData();\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location) {\n        World world = location.getWorld();\n        if (world != null)\n            world.getBlockAt(location).setBlockData(blockData);\n    }\n\n    @Override\n    public void release() {\n        this.blockData = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/SpigotGlowEnchantment.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms;\n\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.enchantments.EnchantmentTarget;\n\npublic class SpigotGlowEnchantment extends Enchantment {\n\n    private final NamespacedKey key;\n\n    public SpigotGlowEnchantment(String name) {\n        this.key = NamespacedKey.minecraft(name);\n    }\n\n    @Override\n    public String getName() {\n        return \"SuperiorSkyblockGlow\";\n    }\n\n    @Override\n    public int getMaxLevel() {\n        return 1;\n    }\n\n    @Override\n    public int getStartLevel() {\n        return 0;\n    }\n\n    @Override\n    public EnchantmentTarget getItemTarget() {\n        return null;\n    }\n\n    public boolean isTreasure() {\n        return false;\n    }\n\n    public boolean isCursed() {\n        return false;\n    }\n\n    @Override\n    public boolean conflictsWith(Enchantment enchantment) {\n        return false;\n    }\n\n    @Override\n    public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) {\n        return true;\n    }\n\n    @Override\n    public NamespacedKey getKey() {\n        return this.key;\n    }\n\n}\n"
  },
  {
    "path": "NMS/build.gradle",
    "content": "group 'NMS'\n\nsubprojects {\n    def generatedSrcDir = file(\"$buildDir/generated/sources/nms\")\n\n    task generateNmsSources {\n        doLast {\n            delete generatedSrcDir\n\n            generatedSrcDir.mkdirs()\n\n            def props = new Properties()\n            def propertiesFile = file(\"$projectDir/properties\")\n            if (!propertiesFile.exists()) {\n                return\n            }\n\n            propertiesFile.withInputStream { stream ->\n                props.load(stream)\n            }\n\n            def templatesDir = file(\"${rootDir}/NMS/src/main/templates/\")\n            def templates = fileTree(templatesDir) {\n                include '**/*.template'\n            }\n\n            templates.each { File templateFile ->\n                def relativePath = templatesDir.toPath().relativize(templateFile.toPath()).toString()\n                def outputFile = new File(generatedSrcDir, relativePath.replace('.template', ''))\n                outputFile.parentFile.mkdirs()\n\n                def templateText = templateFile.text\n                props.each { k, v ->\n                    templateText = templateText.replace(\"\\${${k}}\", v)\n                }\n                outputFile.text = templateText\n                println \"Generated ${outputFile}\"\n            }\n\n        }\n    }\n\n    sourceSets {\n        main {\n            java {\n                srcDirs = ['src/main/java', generatedSrcDir]\n            }\n        }\n    }\n\n    compileJava.dependsOn(generateNmsSources)\n}"
  },
  {
    "path": "NMS/src/main/templates/AbstractNMSAlgorithms.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter;\nimport com.bgsoftware.superiorskyblock.core.io.ClassProcessor;\nimport com.bgsoftware.superiorskyblock.listener.BukkitEventsListener;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuBrewingStandBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuDispenserBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuFurnaceBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuHopperBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.BlockEntityCache;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.google.common.collect.Multimap;\nimport com.google.common.collect.MultimapBuilder;\nimport io.papermc.paper.chat.ChatRenderer;\nimport net.kyori.adventure.audience.Audience;\nimport net.kyori.adventure.text.TextReplacementConfig;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.Container;\nimport net.minecraft.world.entity.item.FallingBlockEntity;\nimport net.minecraft.world.entity.${ABSTRACT_MINECART_SUBPACKAGE}.AbstractMinecart;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.attribute.Attribute;\nimport org.bukkit.attribute.AttributeModifier;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.data.Ageable;\nimport org.bukkit.block.data.BlockData;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftServer;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftFallingBlock;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecart;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.event.world.GenericGameEvent;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.PotionEffect;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.EnumMap;\nimport java.util.Optional;\nimport java.util.function.BiFunction;\n\npublic abstract class AbstractNMSAlgorithms implements NMSAlgorithms {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Multimap<Attribute, AttributeModifier> EMPTY_ATTRIBUTES_MAP =\n            MultimapBuilder.hashKeys().hashSetValues().build();\n\n    private static final EnumBridge<Biome> BIOME_ENUM_BRIDGE = new EnumBridge<>() {\n        @Override\n        public Biome[] getValues() {\n            return Biome.values();\n        }\n\n        @Override\n        public String getName(Biome enumValue) {\n            return enumValue.name();\n        }\n    };\n\n    static final int DATA_VERSION = ((CraftMagicNumbers) new ReflectField<>(\n            CraftMagicNumbers.class, Object.class, \"INSTANCE\").get(null)).getDataVersion();\n\n    private static final EnumMap<InventoryType, MenuCreator> MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class);\n\n    static {\n        MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new);\n    }\n\n    private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() {\n        @Override\n        public byte[] processClass(byte[] classBytes, String path) {\n            return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes);\n        }\n    };\n\n    @Override\n    public void registerCommand(BukkitCommand command) {\n        ((CraftServer) plugin.getServer()).getCommandMap().register(\"superiorskyblock2\", command);\n    }\n\n    @Override\n    public int getCombinedId(Location location) {\n        org.bukkit.World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return 0;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n        BlockState blockState;\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            blockState = serverLevel.getBlockState(wrapper.getHandle());\n        }\n        return Block.getId(blockState);\n    }\n\n    @Override\n    public int getCombinedId(Material material, byte data) {\n        BlockState blockState;\n\n        if (data == 0) {\n            Block block = CraftMagicNumbers.getBlock(material);\n            if (block == null)\n                return -1;\n            blockState = block.defaultBlockState();\n        } else {\n            blockState = CraftMagicNumbers.getBlock(material, data);\n        }\n\n        return blockState == null ? -1 : Block.getId(blockState);\n    }\n\n    @Override\n    public Optional<String> getTileEntityIdFromCombinedId(int combinedId) {\n        BlockState blockState = Block.stateById(combinedId);\n\n        if (!blockState.hasBlockEntity())\n            return Optional.empty();\n\n        String id = BlockEntityCache.getBlockEntityId(blockState);\n\n        return Text.isBlank(id) ? Optional.empty() : Optional.of(id);\n    }\n\n    @Override\n    public int compareMaterials(Material o1, Material o2) {\n        int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal();\n        int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal();\n        return Integer.compare(firstMaterial, secondMaterial);\n    }\n\n    @Override\n    public short getBlockDataValue(org.bukkit.block.BlockState blockState) {\n        BlockData blockData = blockState.getBlockData();\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0);\n    }\n\n    @Override\n    public short getBlockDataValue(org.bukkit.block.Block block) {\n        BlockData blockData = block.getBlockData();\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0);\n    }\n\n    @Override\n    public short getMaxBlockDataValue(Material material) {\n        if (!material.isBlock())\n            return 0;\n\n        BlockData blockData = Bukkit.createBlockData(material);\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0);\n    }\n\n    @Override\n    public Key getBlockKey(int combinedId) {\n        Block block = Block.stateById(combinedId).getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) {\n        AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle();\n        Block block = minecart.getDisplayBlockState().getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public Key getFallingBlockType(FallingBlock bukkitFallingBlock) {\n        FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle();\n        Block block = fallingBlock.getBlockState().getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public void setCustomModel(ItemMeta itemMeta, int customModel) {\n        itemMeta.setCustomModelData(customModel);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) {\n        if (!potionMeta.hasCustomEffects())\n            potionMeta.setColor(potionEffect.getType().getColor());\n        potionMeta.addCustomEffect(potionEffect, true);\n    }\n\n    @Nullable\n    @Override\n    public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) {\n        MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType);\n        return menuCreator == null ? null : menuCreator.apply(defaultHolder, title);\n    }\n\n    @Override\n    public int getMaxWorldSize() {\n        return Bukkit.getMaxWorldSize();\n    }\n\n    @Override\n    public int getDataVersion() {\n        return DATA_VERSION;\n    }\n\n    @Override\n    public ClassProcessor getClassProcessor() {\n        return CLASS_PROCESSOR;\n    }\n\n    @Override\n    public void handlePaperChatRenderer(Object event) {\n        if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent))\n            return;\n\n        ChatRenderer originalRenderer = asyncChatEvent.renderer();\n        asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer);\n    }\n\n    @Override\n    public void hideAttributes(ItemMeta itemMeta) {\n        itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP);\n    }\n\n    @Override\n    public EnumBridge<Biome> getBiomeBridge() {\n        return BIOME_ENUM_BRIDGE;\n    }\n\n    @Override\n    public BukkitEventsListener.GameEventCreator getGenericGameCreator() {\n        return (eventType, priority, event) -> {\n            GameEventArgs.GenericGameEvent genericGameEvent = new GameEventArgs.GenericGameEvent();\n            genericGameEvent.world = ((GenericGameEvent) event).getWorld();\n            genericGameEvent.gameEvent = ((GenericGameEvent) event).getEvent().getKey().getKey();\n            genericGameEvent.location = ((GenericGameEvent) event).getLocation();\n            return eventType.createEvent(genericGameEvent);\n        };\n    }\n\n    private interface MenuCreator extends BiFunction<InventoryHolder, String, Container> {\n    }\n\n    private static class ChatRendererWrapper {\n\n        private static final String MESSAGE_PLACEHOLDER = \"{message}\";\n        private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT =\n                net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER);\n\n        private final ChatRenderer renderer = new ChatRenderer() {\n            @Override\n            public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source,\n                                                                      net.kyori.adventure.text.@NotNull Component sourceDisplayName,\n                                                                      net.kyori.adventure.text.@NotNull Component message,\n                                                                      @NotNull Audience viewer) {\n                String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer\n                        .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer));\n\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source);\n                Island island = superiorPlayer.getIsland();\n\n                return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize(\n                                Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island)))\n                        .replaceText(TextReplacementConfig.builder()\n                                .matchLiteral(MESSAGE_PLACEHOLDER)\n                                .replacement(message)\n                                .build());\n            }\n        };\n\n        private final ChatRenderer originalRenderer;\n\n        public ChatRendererWrapper(ChatRenderer originalRenderer) {\n            this.originalRenderer = originalRenderer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/AbstractNMSChunks.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.NMSChunks;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.SlabBlock;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.SlabType;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.phys.AABB;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftChunk;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftNamespacedKey;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic abstract class AbstractNMSChunks implements NMSChunks {\n\n    protected final SuperiorSkyblockPlugin plugin;\n\n    protected AbstractNMSChunks(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        KeyBlocksCache.cacheAllBlocks();\n        CropsTickingMethod.register();\n    }\n\n    @Override\n    public void setBiome(List<ChunkPosition> chunkPositions, org.bukkit.block.Biome bukkitBiome,\n                         Collection<org.bukkit.entity.Player> playersToUpdate) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, getBiomesChunkCallback(bukkitBiome, playersToUpdate));\n    }\n\n    protected abstract NMSUtils.ChunkCallback getBiomesChunkCallback(\n            org.bukkit.block.Biome bukkitBiome, Collection<org.bukkit.entity.Player> playersToUpdate);\n\n    @Override\n    public void deleteChunks(Island island, List<ChunkPosition> chunkPositions, @Nullable Runnable onFinish) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(),\n                chunkPosition.getX(), chunkPosition.getZ(), false));\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, getDeleteChunkCallback(onFinish));\n    }\n\n    protected abstract NMSUtils.ChunkCallback getDeleteChunkCallback(@Nullable Runnable onFinish);\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Blocks>> calculateChunks(List<ChunkPosition> chunkPositions,\n                                                                    Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache) {\n        List<CalculatedChunk.Blocks> allCalculatedChunks = new LinkedList<>();\n        List<ChunkPosition> chunkPositionsToCalculate = new LinkedList<>();\n\n        Iterator<ChunkPosition> chunkPositionsIterator = chunkPositions.iterator();\n        while (chunkPositionsIterator.hasNext()) {\n            ChunkPosition chunkPosition = chunkPositionsIterator.next();\n            CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition));\n            if (cachedCalculatedChunk != null) {\n                allCalculatedChunks.add(cachedCalculatedChunk);\n                chunkPositionsIterator.remove();\n            } else {\n                chunkPositionsToCalculate.add(chunkPosition);\n            }\n        }\n\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(allCalculatedChunks);\n\n        CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture = new CompletableFuture<>();\n\n        NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false,\n                getCalculateChunkCallback(completableFuture, unloadedChunksCache, allCalculatedChunks));\n\n        return completableFuture;\n    }\n\n    protected abstract NMSUtils.ChunkCallback getCalculateChunkCallback(\n            CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n            Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n            List<CalculatedChunk.Blocks> allCalculatedChunks);\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Entities>> calculateChunkEntities(Collection<ChunkPosition> chunkPositions) {\n        CompletableFuture<List<CalculatedChunk.Entities>> completableFuture = new CompletableFuture<>();\n\n        List<CalculatedChunk.Entities> allCalculatedChunks = new LinkedList<>();\n        List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds = new LinkedList<>();\n\n        NMSUtils.runActionOnEntityChunks(chunkPositions,\n                getEntitiesChunkCallback(allCalculatedChunks, unloadedChunkCompounds, completableFuture));\n\n        return completableFuture;\n    }\n\n    protected abstract NMSUtils.ChunkCallback getEntitiesChunkCallback(\n            List<CalculatedChunk.Entities> allCalculatedChunks, List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n            CompletableFuture<List<CalculatedChunk.Entities>> completableFuture);\n\n    protected abstract Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel);\n\n    @Override\n    public void injectChunkSections(Chunk chunk) {\n        // No implementation\n    }\n\n    @Override\n    public boolean isChunkEmpty(Chunk bukkitChunk) {\n        ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle();\n        LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ());\n        return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection ->\n                chunkSection == null || NMSUtilsVersioned.isLevelChunkSectionEmpty(chunkSection));\n    }\n\n    @Override\n    public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) {\n        ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n        ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false);\n        return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null;\n    }\n\n    @Override\n    public void startTickingChunk(Island island, Chunk chunk, boolean stop) {\n        if (plugin.getSettings().getCropsInterval() <= 0)\n            return;\n\n        if (stop) {\n            long packedPos = NMSUtils.getChunkPackedPos(chunk.getX(), chunk.getZ());\n            CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(chunk.getWorld().getName(), packedPos);\n            if (cropsBlockEntity != null)\n                cropsBlockEntity.remove();\n        } else {\n            ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle();\n            LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ());\n            CropsBlockEntity.create(island, chunk.getWorld().getName(), levelChunk);\n        }\n    }\n\n    @Override\n    public void updateCropsTicker(List<ChunkPosition> chunkPositions, double newCropGrowthMultiplier) {\n        if (chunkPositions.isEmpty()) return;\n        CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity ->\n                cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier));\n    }\n\n    @Override\n    public void shutdown() {\n        List<CompletableFuture<Void>> pendingTasks = NMSUtils.getPendingChunkActions();\n\n        if (pendingTasks.isEmpty())\n            return;\n\n        Log.info(\"Waiting for chunk tasks to complete.\");\n\n        CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join();\n    }\n\n    @Override\n    public List<Location> getBlockEntities(Chunk chunk) {\n        ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle();\n        LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ());\n\n        List<Location> blockEntities = new LinkedList<>();\n\n        World bukkitWorld = chunk.getWorld();\n\n        levelChunk.getBlockEntities().keySet().forEach(blockPos ->\n                blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ())));\n\n        return blockEntities;\n    }\n\n    protected CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) {\n        KeyMap<Counter> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        List<Location> spawnersLocations = new LinkedList<>();\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            LevelChunkSection levelChunkSection = chunkSections[i];\n            if (levelChunkSection != null && !NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection)) {\n                int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4;\n                for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) {\n                    BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ());\n                    calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition,\n                            sectionBottomY, blockCounts, spawnersLocations);\n                }\n            }\n        }\n\n        return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations);\n    }\n\n    protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, LevelChunk levelChunk) {\n        KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n        for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) {\n            if (!BukkitEntities.canBypassEntityLimit(bukkitEntity))\n                chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1);\n        }\n\n        return new CalculatedChunk.Entities(chunkPosition, chunkEntities);\n    }\n\n    protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, ServerLevel serverLevel, ListTag entitiesTag) {\n        KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n        for (Tag entityTag : entitiesTag) {\n            Entity fakeEntity = createEntityFromTag((CompoundTag) entityTag, serverLevel).orElse(null);\n            if(fakeEntity == null)\n                continue;\n\n            fakeEntity.valid = false;\n            if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity()))\n                continue;\n\n            Key entityKey = Keys.of(fakeEntity.getBukkitEntity());\n\n            chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1);\n        }\n\n        return new CalculatedChunk.Entities(chunkPosition, chunkEntities);\n    }\n\n    private void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition,\n                                               int sectionBottomY, KeyMap<Counter> blockCounts,\n                                               List<Location> spawnersLocations) {\n        Block block = blockState.getBlock();\n\n        if (block == Blocks.AIR)\n            return;\n\n        Location location = new Location(chunkPosition.getWorld(),\n                (chunkPosition.getX() << 4) + x,\n                sectionBottomY + y,\n                (chunkPosition.getZ() << 4) + z);\n\n        int blockAmount = 1;\n\n        if (NMSUtils.isDoubleBlock(block, blockState)) {\n            blockAmount = 2;\n            blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM);\n        }\n\n        Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location);\n        blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount);\n        if (block == Blocks.SPAWNER) {\n            spawnersLocations.add(location);\n        }\n    }\n\n    protected void removeEntities(LevelChunk levelChunk) {\n        ServerLevel serverLevel = levelChunk.level;\n\n        int chunkWorldCoordX = levelChunk.locX << 4;\n        int chunkWorldCoordZ = levelChunk.locZ << 4;\n\n        AABB chunkBounds = new AABB(chunkWorldCoordX, NMSUtilsVersioned.getMinBuildHeight(serverLevel), chunkWorldCoordZ,\n                chunkWorldCoordX + 15, NMSUtilsVersioned.getMaxBuildHeight(serverLevel), chunkWorldCoordZ + 15);\n\n        List<Entity> worldEntities = new LinkedList<>();\n        serverLevel.getEntities().get(chunkBounds, worldEntities::add);\n\n        worldEntities.forEach(nmsEntity -> {\n            if (!(nmsEntity instanceof net.minecraft.world.entity.player.Player))\n                nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED);\n        });\n    }\n\n    protected void removeBlockEntities(LevelChunk levelChunk) {\n        levelChunk.blockEntities.values().forEach(BlockEntity::setRemoved);\n        levelChunk.blockEntities.clear();\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/AbstractNMSEntities.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.superiorskyblock.nms.NMSEntities;\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport org.bukkit.Material;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftAnimals;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecartFurnace;\nimport ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.Steerable;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.inventory.EntityEquipment;\nimport org.bukkit.inventory.ItemStack;\n\npublic abstract class AbstractNMSEntities implements NMSEntities {\n\n    @Override\n    public ItemStack[] getEquipment(EntityEquipment entityEquipment) {\n        ItemStack[] itemStacks = new ItemStack[7];\n\n        itemStacks[0] = new ItemStack(Material.ARMOR_STAND);\n        itemStacks[1] = entityEquipment.getItemInMainHand();\n        itemStacks[2] = entityEquipment.getItemInOffHand();\n        itemStacks[3] = entityEquipment.getHelmet();\n        itemStacks[4] = entityEquipment.getChestplate();\n        itemStacks[5] = entityEquipment.getLeggings();\n        itemStacks[6] = entityEquipment.getBoots();\n\n        return itemStacks;\n    }\n\n    @Override\n    public boolean isAnimalFood(ItemStack itemStack, Animals animals) {\n        return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack));\n    }\n\n    @Override\n    public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) {\n        Entity entity = ((CraftEntity) bukkitEntity).getHandle();\n        return getPortalTicks(entity);\n    }\n\n    protected abstract int getPortalTicks(Entity entity);\n\n    @Override\n    public boolean canShearSaddleFromEntity(org.bukkit.entity.Entity entity) {\n        return entity instanceof Steerable steerable && steerable.hasSaddle();\n    }\n}\n"
  },
  {
    "path": "NMS/src/main/templates/AbstractNMSTags.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.nms.NMSTags;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.item.ItemStack;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers;\n\npublic abstract class AbstractNMSTags implements NMSTags {\n\n    @Override\n    public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n        return setTagAndGetCompoundTag(itemStack, \"DataVersion\", AbstractNMSAlgorithms.DATA_VERSION);\n    }\n\n    protected abstract CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value);\n\n    @Override\n    public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) {\n        if (compoundTag.containsKey(\"NBT\")) {\n            // Old compound version, deserialize it accordingly\n            return deserializeItemOld(compoundTag);\n        }\n\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT();\n\n        int itemVersion = getCompoundTagInt(tagCompound, \"DataVersion\", 0);\n        if (itemVersion < AbstractNMSAlgorithms.DATA_VERSION) {\n            tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK,\n                    new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        ItemStack itemStack = parseItemStack(tagCompound);\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    protected abstract int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def);\n\n    protected abstract ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag);\n\n    private org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) {\n        String typeName = Materials.patchOldMaterialName(compoundTag.getString(\"type\").orElse(null));\n        Material type = Material.valueOf(typeName);\n        int amount = compoundTag.getInt(\"amount\").orElse(0);\n        short data = (short) compoundTag.getShort(\"data\").orElse(0);\n        CompoundTag nbtData = compoundTag.getCompound(\"NBT\").orElse(null);\n\n        org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data);\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n        if (nbtData != null) {\n            setItemStackCompoundTag(itemStack, (net.minecraft.nbt.CompoundTag) nbtData.toNBT());\n        }\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    protected abstract void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag);\n\n    @Override\n    public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) {\n        net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT();\n\n        if (compoundTag == null)\n            compoundTag = new net.minecraft.nbt.CompoundTag();\n\n        if (!compoundTag.contains(\"id\"))\n            //noinspection deprecation\n            compoundTag.putString(\"id\", entityType.getName());\n\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n\n        loadEntity(compoundTag, serverLevel, location);\n    }\n\n    protected abstract void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location);\n\n    @Override\n    public Object parseList(ListTag listTag) {\n        net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag();\n\n        for (Tag<?> tag : listTag)\n            nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT());\n\n        return nbtTagList;\n    }\n\n    @Override\n    public Object getNBTCompoundTag(Object object, String key) {\n        return ((net.minecraft.nbt.CompoundTag) object).get(key);\n    }\n\n    @Override\n    public void setNBTCompoundTagValue(Object object, String key, Object value) {\n        ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value);\n    }\n\n    @Override\n    public int getNBTTagListSize(Object object) {\n        return ((net.minecraft.nbt.ListTag) object).size();\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/AbstractNMSWorld.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.island.signs.IslandSigns;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.NMSWorld;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport ${COMMON_NMS_PACKAGE}.algorithms.NMSCachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator.IslandsGeneratorImpl;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners.TickingSpawnerBlockEntityNotifier;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.ChunkReaderImpl;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.sounds.SoundSource;\nimport net.minecraft.world.level.EmptyBlockGetter;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.SoundType;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.SpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.TickingBlockEntity;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.BlockData;\nimport org.bukkit.block.data.Waterlogged;\nimport org.bukkit.block.data.type.BubbleColumn;\nimport org.bukkit.block.data.type.CaveVinesPlant;\nimport org.bukkit.block.data.type.Sign;\nimport org.bukkit.block.data.type.WallSign;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.block.CraftBlock;\nimport ${CRAFTBUKKIT_PACKAGE}.block.CraftBlockState;\nimport ${CRAFTBUKKIT_PACKAGE}.block.CraftSign;\nimport ${CRAFTBUKKIT_PACKAGE}.block.data.CraftBlockData;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer;\nimport ${CRAFTBUKKIT_PACKAGE}.generator.CustomChunkGenerator;\nimport org.bukkit.entity.Player;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.IntFunction;\n\npublic abstract class AbstractNMSWorld implements NMSWorld {\n\n    private static final ReflectField<List<TickingBlockEntity>> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField();\n    private static final ReflectField<Object> CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class,\n            Object.class, \"chunkPacketBlockController\")\n            .removeFinal();\n    private static final ReflectField<ChunkGenerator> CUSTOM_CHUNK_GENERATOR_DELEGATE = new ReflectField<ChunkGenerator>(\n            CustomChunkGenerator.class, ChunkGenerator.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<Integer> NOISE_GENERATOR_SETTINGS_SEA_LEVEL = new ReflectField<Integer>(\n            NoiseGeneratorSettings.class, Integer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    protected final SuperiorSkyblockPlugin plugin;\n\n    protected AbstractNMSWorld(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return getBlockKeyInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return ConstantKeys.AIR;\n        }\n    }\n\n    private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock();\n\n        Location location = new Location(\n                Bukkit.getWorld(chunkSnapshot.getWorldName()),\n                (chunkSnapshot.getX() << 4) + x,\n                y,\n                (chunkSnapshot.getZ() << 4) + z\n        );\n\n        return Keys.of(KeyBlocksCache.getBlockKey(block), location);\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return canPlayerSuffocateInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return true;\n        }\n    }\n\n    private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        BlockState blockState = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState();\n        return !blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();\n    }\n\n    @Override\n    public void listenSpawner(Location location, IntFunction<Integer> delayChangeCallback) {\n        SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class);\n        if (spawnerBlockEntity == null)\n            return;\n\n        ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel();\n\n        List<TickingBlockEntity> blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel);\n        Iterator<TickingBlockEntity> blockEntityTickersIterator = blockEntityTickers.iterator();\n        List<TickingBlockEntity> tickersToAdd = new LinkedList<>();\n\n        while (blockEntityTickersIterator.hasNext()) {\n            TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next();\n            if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) &&\n                    !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) {\n                blockEntityTickersIterator.remove();\n                tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback));\n            }\n        }\n\n        if (!tickersToAdd.isEmpty())\n            blockEntityTickers.addAll(tickersToAdd);\n    }\n\n    @Override\n    public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) {\n        if (!plugin.getSettings().isWorldBorders())\n            return;\n\n        Player player = superiorPlayer.asPlayer();\n        World world = superiorPlayer.getWorld();\n\n        if (world == null || player == null)\n            return;\n\n        int islandSize = island == null ? 0 : island.getIslandSize();\n\n        boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0;\n\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n\n        WorldBorder worldBorder;\n\n        if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) {\n            worldBorder = serverLevel.getWorldBorder();\n        } else {\n            Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n            if (dimension == null)\n                return;\n\n            Location center = island.getCenter(dimension);\n\n            worldBorder = new WorldBorder();\n            try {\n                worldBorder.world = serverLevel;\n            } catch (Throwable ignored) {\n            }\n            worldBorder.setWarningBlocks(0);\n            worldBorder.setCenter(center.getX(), center.getZ());\n\n            switch (superiorPlayer.getBorderColor()) {\n                case BLUE:\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    break;\n                case GREEN:\n                    worldBorder.setSize((islandSize * 2) + 1.001D);\n                    lerpSizeBetween(worldBorder, worldBorder.getSize() - 0.001D, worldBorder.getSize());\n                    break;\n                case RED:\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    lerpSizeBetween(worldBorder, worldBorder.getSize(), worldBorder.getSize() - 0.001D);\n                    break;\n            }\n        }\n\n        ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder);\n        ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket);\n    }\n\n    protected abstract void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize);\n\n    @Override\n    public Object getBlockData(org.bukkit.block.Block block) {\n        return block.getBlockData();\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n            BlockState blockState =\n                    NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null);\n\n            if (blockState != null) {\n                serverLevel.getChunkSource().blockChanged(blockPos);\n                if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) {\n                    serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512);\n                }\n            }\n        }\n    }\n\n    @Override\n    public ICachedBlock cacheBlock(org.bukkit.block.Block block) {\n        return NMSCachedBlock.obtain(block);\n    }\n\n    @Override\n    public boolean isWaterLogged(org.bukkit.block.Block block) {\n        if (Materials.isWater(block.getType()))\n            return true;\n\n        BlockData blockData = block.getBlockData();\n\n        return blockData instanceof BubbleColumn ||\n                (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged());\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof WallSign)\n            return SignType.WALL_SIGN;\n        else if (sign instanceof Sign)\n            return SignType.STANDING_SIGN;\n        else\n            return SignType.UNKNOWN;\n    }\n\n    @Override\n    public boolean hasBerries(org.bukkit.block.Block block) {\n        return ((CaveVinesPlant) block.getBlockData()).isBerries();\n    }\n\n    @Override\n    public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) {\n        BlockState blockState = NMSUtilsVersioned.getBlockState(block);\n        return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()];\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) {\n        ServerLevel serverLevel = ((CraftWorld) bukkitBlock.getWorld()).getHandle();\n        BlockState blockState;\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());\n\n            blockState = serverLevel.getBlockState(blockPos);\n        }\n        return getDefaultAmountInternal(blockState);\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) {\n        return getDefaultAmountInternal(((CraftBlockState) bukkitBlockState).getHandle());\n    }\n\n    private int getDefaultAmountInternal(BlockState blockState) {\n        Block block = blockState.getBlock();\n        return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1;\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) {\n        return !bukkitBlock.isPassable();\n    }\n\n    @Override\n    public void placeSign(Island island, Location location) {\n        SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class);\n        if (signBlockEntity == null)\n            return;\n\n        String[] lines = new String[4];\n        Component[] messages = getSignBlockEntityText(signBlockEntity);\n        System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length);\n        String[] strippedLines = new String[4];\n        for (int i = 0; i < 4; i++)\n            strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]);\n\n        Component[] newLines;\n\n        IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false);\n        if (result.isCancelEvent()) {\n            newLines = CraftSign.sanitizeLines(strippedLines);\n        } else {\n            newLines = CraftSign.sanitizeLines(lines);\n        }\n\n        System.arraycopy(newLines, 0, messages, 0, 4);\n    }\n\n    protected abstract Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity);\n\n    @Override\n    public void playGeneratorSound(Location location) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            serverLevel.levelEvent(1501, blockPos, 0);\n        }\n    }\n\n    @Override\n    public void playBreakAnimation(org.bukkit.block.Block block) {\n        ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(block.getX(), block.getY(), block.getZ());\n            serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos)));\n        }\n    }\n\n    @Override\n    public void playPlaceSound(Location location) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType();\n\n            serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS,\n                    (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F);\n        }\n    }\n\n    @Override\n    public int getMinHeight(World world) {\n        return world.getMinHeight();\n    }\n\n    @Override\n    public void removeAntiXray(org.bukkit.World bukkitWorld) {\n        if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid())\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n        CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ${PAPER_CHUNK_BLOCK_CONTROLLER_CLASS}.NO_OPERATION_INSTANCE);\n    }\n\n    @Override\n    public void setOceanLevel(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n\n        if (!(serverLevel.getChunkSource().getGenerator() instanceof CustomChunkGenerator chunkGenerator))\n            return;\n\n        ChunkGenerator delegateChunkGenerator = getChunkGeneratorDelegate(chunkGenerator);\n\n        if (delegateChunkGenerator instanceof FlatLevelSource flatLevelSource) {\n            FlatLevelSource newLevelSource = createFlatLevelSource(flatLevelSource, plugin.getSettings().getWorlds().getSeaLevelHeight());\n            CUSTOM_CHUNK_GENERATOR_DELEGATE.set(chunkGenerator, newLevelSource);\n        } else if(delegateChunkGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n            NoiseGeneratorSettings settings = getNoiseGeneratorSettings(noiseBasedChunkGenerator);\n            NOISE_GENERATOR_SETTINGS_SEA_LEVEL.set(settings, plugin.getSettings().getWorlds().getSeaLevelHeight());\n\n        } else {\n            throw new IllegalStateException(\"Cannot set ocean level for chunk generator of type \" + delegateChunkGenerator);\n        }\n    }\n\n    protected abstract ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator);\n\n    protected abstract FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel);\n\n    protected abstract NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator);\n\n    @Override\n    public IslandsGenerator createGenerator(Dimension dimension) {\n        return new IslandsGeneratorImpl(dimension);\n    }\n\n    @Override\n    public WorldEditSession createEditSession(World world) {\n        return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle());\n    }\n\n    @Override\n    public WorldEditSession createPartialEditSession(Dimension dimension) {\n        return WorldEditSessionImpl.obtain(dimension);\n    }\n\n    @Override\n    public ChunkReader createChunkReader(Chunk chunk) {\n        return new ChunkReaderImpl(chunk);\n    }\n\n    private static ReflectField<List<TickingBlockEntity>> initializeLevelBlockEntityTickersField() {\n        ReflectField<List<TickingBlockEntity>> field = new ReflectField<>(\n                Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1);\n\n        if (!field.isValid())\n            field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n\n        return field;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/NMSDragonFightImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.nms.NMSDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.SpikesCache;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.google.common.cache.LoadingCache;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.entity.boss.enderdragon.EnderDragon;\nimport net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS};\nimport net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS};\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.World;\nimport org.bukkit.advancement.Advancement;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport org.bukkit.entity.Player;\n\nimport java.lang.reflect.Modifier;\nimport java.util.List;\n\npublic class NMSDragonFightImpl implements NMSDragonFight {\n\n    private static final ReflectField<EntityType.EntityFactory<?>> ENTITY_TYPES_BUILDER = new ReflectField<EntityType.EntityFactory<?>>(\n            EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> WORLD_DRAGON_BATTLE = new ReflectField<>(\n            ServerLevel.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1);\n\n    private static final ReflectField<LoadingCache<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>>> SPIKE_CACHE = new ReflectField<LoadingCache<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>>>(\n            ${SPIKE_FEATURE_CLASS}.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static boolean firstWorldPreparation = true;\n\n    static {\n        ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory<EnderDragon>) IslandEntityEnderDragon::fromEntityTypes);\n    }\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n        WORLD_DRAGON_BATTLE.set(serverLevel, new EndDragonFightWrapper(serverLevel));\n\n        if (firstWorldPreparation) {\n            firstWorldPreparation = false;\n            SPIKE_CACHE.set(null, SpikesCache.getInstance());\n        }\n    }\n\n    @Nullable\n    @Override\n    public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        World bukkitWorld = island.getCenter(dimension).getWorld();\n\n        if (bukkitWorld == null)\n            return null;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight))\n            return null;\n\n        IslandEndDragonFight enderDragonBattle = dragonFight.HANDLER.getDragonFight(island.getCache());\n        return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity();\n    }\n\n    @Override\n    public void startDragonBattle(Island island, Location location) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight))\n            return;\n\n        dragonFight.HANDLER.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location));\n    }\n\n    @Override\n    public void removeDragonBattle(Island island, Dimension dimension) {\n        World bukkitWorld = island.getCenter(dimension).getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight))\n            return;\n\n        ${END_DRAGON_FIGHT_CLASS} endDragonFight = dragonFight.HANDLER.removeDragonFight(island.getCache());\n\n        if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) {\n            islandEndDragonFight.removeBattlePlayers();\n            islandEndDragonFight.getEnderDragon().getBukkitEntity().remove();\n        }\n    }\n\n    @Override\n    public void awardTheEndAchievement(Player player) {\n        Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft(\"end/root\"));\n        if (advancement != null)\n            player.getAdvancementProgress(advancement).awardCriteria(\"\");\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/NMSHologramsImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.nms.NMSHolograms;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram.EntityHologram;\nimport com.google.common.base.Preconditions;\nimport net.minecraft.server.level.ServerLevel;\nimport org.bukkit.Location;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity;\nimport org.bukkit.entity.Entity;\n\npublic class NMSHologramsImpl implements NMSHolograms {\n\n    @Override\n    public Hologram createHologram(Location location) {\n        Preconditions.checkNotNull(location.getWorld(), \"Cannot create hologram in null worlds.\");\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n        EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ());\n        serverLevel.addFreshEntity(entityHologram);\n        return entityHologram;\n    }\n\n    @Override\n    public boolean isHologram(Entity entity) {\n        return ((CraftEntity) entity).getHandle() instanceof Hologram;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/NMSPlayersImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.NMSPlayers;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player.OfflinePlayerDataImpl;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask;\nimport com.mojang.authlib.properties.Property;\nimport net.md_5.bungee.api.ChatMessageType;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport net.minecraft.server.level.ServerPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.boss.BarColor;\nimport org.bukkit.boss.BarStyle;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\n\npublic class NMSPlayersImpl implements NMSPlayers {\n\n    private static final ReflectMethod<Locale> PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, \"locale\");\n\n    @Override\n    public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) {\n        return OfflinePlayerDataImpl.create(offlinePlayer);\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        Player player = superiorPlayer.asPlayer();\n\n        if (player == null)\n            return;\n\n        ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n        NMSUtilsVersioned.getProfileProperties(serverPlayer.getGameProfile()).get(\"textures\").stream().findFirst()\n                .ifPresent(property -> setSkinTexture(superiorPlayer, property));\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) {\n        superiorPlayer.setTextureValue(NMSUtilsVersioned.getPropertyValue(property));\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    public void sendActionBar(Player player, String message) {\n        player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));\n    }\n\n    @Override\n    public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) {\n        BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun);\n        bossBar.addPlayer(player);\n        return bossBar;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) {\n        player.sendTitle(title, subtitle, fadeIn, duration, fadeOut);\n    }\n\n    @Override\n    public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) {\n        return superiorPlayer.getUniqueId().equals(item.getThrower());\n    }\n\n    @Nullable\n    @Override\n    public Locale getPlayerLocale(Player player) {\n        if (PLAYER_LOCALE.isValid()) {\n            return player.locale();\n        } else try {\n            //noinspection deprecation\n            return PlayerLocales.getLocale(player.getLocale());\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }\n\n    private static class BossBarImpl implements BossBar {\n\n        private final org.bukkit.boss.BossBar bossBar;\n        private final BossBarTask bossBarTask;\n\n        public BossBarImpl(String message, BarColor color, double ticksToRun) {\n            bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID);\n            this.bossBarTask = BossBarTask.create(this, ticksToRun);\n        }\n\n        @Override\n        public void addPlayer(Player player) {\n            this.bossBar.addPlayer(player);\n            this.bossBarTask.registerTask(player);\n        }\n\n        @Override\n        public void removeAll() {\n            this.bossBar.removeAll();\n            this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask);\n        }\n\n        @Override\n        public void setProgress(double progress) {\n            this.bossBar.setProgress(progress);\n        }\n\n        @Override\n        public double getProgress() {\n            return this.bossBar.getProgress();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/NMSUtils.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION};\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper;\nimport com.bgsoftware.superiorskyblock.tag.ByteTag;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.IntArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ServerChunkCache;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.BlockTags;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.block.BedBlock;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.SlabBlock;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.block.state.properties.SlabType;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.levelgen.Heightmap;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.Consumer;\n\npublic class NMSUtils {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ReflectMethod<LevelChunk> CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>(\n            ServerChunkCache.class, \"getChunkAtIfCachedImmediately\", int.class, int.class);\n\n    private static final List<CompletableFuture<Void>> PENDING_CHUNK_ACTIONS = new LinkedList<>();\n\n    public static final ObjectsPool<ObjectsPools.Wrapper<BlockPos.MutableBlockPos>> BLOCK_POS_POOL =\n            ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0));\n\n    private NMSUtils() {\n\n    }\n\n    @Nullable\n    public static <T extends BlockEntity> T getBlockEntityAt(Location location, Class<T> type) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return null;\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);\n            return !type.isInstance(blockEntity) ? null : type.cast(blockEntity);\n        }\n    }\n\n    public static void runActionOnEntityChunks(Collection<ChunkPosition> chunksCoords,\n                                               ChunkCallback chunkCallback) {\n        runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks ->\n                runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback));\n    }\n\n    public static void runActionOnChunks(Collection<ChunkPosition> chunksCoords,\n                                         boolean saveChunks, ChunkCallback chunkCallback) {\n        runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks ->\n                runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback));\n    }\n\n    private static void runActionOnChunksInternal(Collection<ChunkPosition> chunksCoords,\n                                                  ChunkCallback chunkCallback,\n                                                  Consumer<List<ChunkPosition>> onUnloadChunkAction) {\n        List<ChunkPosition> unloadedChunks = new LinkedList<>();\n        List<LevelChunk> loadedChunks = new LinkedList<>();\n\n        chunksCoords.forEach(chunkPosition -> {\n            ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n            ChunkAccess chunkAccess;\n\n            try {\n                chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ());\n            } catch (Throwable ex) {\n                chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n            }\n\n            if (chunkAccess instanceof LevelChunk levelChunk) {\n                loadedChunks.add(levelChunk);\n            } else {\n                unloadedChunks.add(chunkPosition.copy());\n            }\n        });\n\n        boolean hasUnloadedChunks = !unloadedChunks.isEmpty();\n\n        if (!loadedChunks.isEmpty())\n            runActionOnLoadedChunks(loadedChunks, chunkCallback);\n\n        if (hasUnloadedChunks) {\n            onUnloadChunkAction.accept(unloadedChunks);\n        } else {\n            chunkCallback.onFinish();\n        }\n    }\n\n    private static void runActionOnLoadedChunks(Collection<LevelChunk> chunks, ChunkCallback chunkCallback) {\n        chunks.forEach(chunkCallback::onLoadedChunk);\n    }\n\n    private static void runActionOnUnloadedChunks(Collection<ChunkPosition> chunks,\n                                                  boolean saveChunks, ChunkCallback chunkCallback) {\n        if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) {\n            Iterator<ChunkPosition> chunksIterator = chunks.iterator();\n            while (chunksIterator.hasNext()) {\n                ChunkPosition chunkPosition = chunksIterator.next();\n\n                ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(\n                        chunkPosition.getX(), chunkPosition.getZ());\n\n                if (cachedUnloadedChunk != null) {\n                    chunkCallback.onLoadedChunk(cachedUnloadedChunk);\n                    chunksIterator.remove();\n                }\n            }\n\n            if (chunks.isEmpty()) {\n                chunkCallback.onFinish();\n                return;\n            }\n        }\n\n        CompletableFuture<Void> pendingTask = new CompletableFuture<>();\n        PENDING_CHUNK_ACTIONS.add(pendingTask);\n\n        BukkitExecutor.createTask().runAsync(v -> {\n            CountDownLatch countDownLatch;\n            if (chunkCallback.isWaitForChunkLoad) {\n                countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size());\n            } else {\n                countDownLatch = null;\n            }\n\n            List<UnloadedChunkCompound> chunkCompounds = new LinkedList<>();\n\n            chunks.forEach(chunkPosition -> {\n                ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap;\n\n                ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                boolean calledCountdown = false;\n                try {\n                    net.minecraft.nbt.CompoundTag chunkCompound = NMSUtilsVersioned.readChunk(chunkMap, chunkPos);\n\n                    if (chunkCompound == null) {\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                        return;\n                    }\n\n                    net.minecraft.nbt.CompoundTag chunkDataCompound = NMSUtilsVersioned.getChunkData(\n                            chunkMap, chunkCompound, serverLevel, chunkPos);\n\n                    UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound);\n                    chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                    calledCountdown = true;\n\n                    if (saveChunks)\n                        chunkCompounds.add(unloadedChunkCompound);\n                } catch (Exception error) {\n                    if (!calledCountdown && countDownLatch != null)\n                        countDownLatch.countDown();\n                    Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                }\n            });\n\n            if (countDownLatch != null) {\n                try {\n                    countDownLatch.await();\n                } catch (InterruptedException error) {\n                    throw new RuntimeException(error);\n                }\n            }\n\n            return chunkCompounds;\n        }).runSync(chunkCompounds -> {\n            chunkCompounds.forEach(unloadedChunkCompound -> {\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap;\n\n                ChunkPos chunkPos = unloadedChunkCompound.chunkPos();\n\n                try {\n                    NMSUtilsVersioned.saveChunkData(chunkMap, unloadedChunkCompound.chunkCompound, chunkPos);\n                } catch (Exception error) {\n                    Log.error(error, \"An unexpected error occurred while saving unloaded chunk \", unloadedChunkCompound.chunkPosition, \":\");\n                }\n            });\n\n            chunkCallback.onFinish();\n\n            pendingTask.complete(null);\n            PENDING_CHUNK_ACTIONS.remove(pendingTask);\n        });\n    }\n\n    private static void runActionOnUnloadedEntityChunks(Collection<ChunkPosition> chunks, ChunkCallback chunkCallback) {\n        CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size());\n\n        NMSUtilsVersioned.runActionOnUnloadedEntityChunks(chunks, chunkCallback, countDownLatch).runAsync(v -> {\n            try {\n                countDownLatch.await();\n            } catch (InterruptedException error) {\n                throw new RuntimeException(error);\n            }\n        }).runSync(v -> {\n            chunkCallback.onFinish();\n        });\n    }\n\n    public static List<CompletableFuture<Void>> getPendingChunkActions() {\n        return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return NMSUtilsVersioned.createProtoChunk(chunkPos, serverLevel);\n    }\n\n    public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId,\n                                      @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) {\n        ServerLevel serverLevel = levelChunk.level;\n        SetBlockContext setBlockContext = new SetBlockContext() {\n\n            @Override\n            public LevelHeightAccessor levelHeightAccessor() {\n                return serverLevel;\n            }\n\n            @Override\n            public void prepareChunkAccess(int chunkX, int chunkZ) {\n                // Do nothing\n            }\n\n            @Override\n            public LevelChunkSection getChunkSection(int i) {\n                return levelChunk.getSections()[i];\n            }\n\n            @Override\n            public Map<Heightmap.Types, Heightmap> getHeightmaps() {\n                return levelChunk.heightmaps;\n            }\n\n            @Override\n            public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) {\n                serverLevel.setBlock(blockPos, blockState, 3);\n            }\n\n            @Override\n            public void onPostSetBlock(BlockPos blockPos, BlockState blockState) {\n                NMSUtilsVersioned.markUnsaved(levelChunk);\n            }\n\n            @Override\n            public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) {\n                if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty)\n                    serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty);\n\n                serverLevel.getLightEngine().checkBlock(blockPos);\n            }\n\n            @Override\n            public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) {\n                net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT();\n                if (tileEntityCompound != null) {\n                    tileEntityCompound.putInt(\"x\", blockPos.getX());\n                    tileEntityCompound.putInt(\"y\", blockPos.getY());\n                    tileEntityCompound.putInt(\"z\", blockPos.getZ());\n                    BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos);\n                    if (worldBlockEntity != null) {\n                        NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, tileEntityCompound);\n                    }\n                }\n            }\n        };\n        return setBlock(setBlockContext, blockPos, combinedId, statesTag, tileEntity);\n    }\n\n    public static BlockState setBlock(SetBlockContext setBlockContext, BlockPos blockPos, int combinedId,\n                                      @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) {\n        if (!isValidPosition(setBlockContext, blockPos))\n            return null;\n\n        BlockState blockState = Block.stateById(combinedId);\n\n        if (statesTag != null) {\n            for (Map.Entry<String, Tag<?>> entry : statesTag.entrySet()) {\n                try {\n                    // noinspection rawtypes\n                    Property property = PropertiesMapper.getProperty(entry.getKey());\n                    if (property != null) {\n                        if (entry.getValue() instanceof ByteTag) {\n                            // noinspection unchecked\n                            blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1);\n                        } else if (entry.getValue() instanceof IntArrayTag) {\n                            int[] data = ((IntArrayTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockState = blockState.setValue(property, data[0]);\n                        } else if (entry.getValue() instanceof StringTag) {\n                            String data = ((StringTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data));\n                        }\n                    }\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        if ((NMSUtilsVersioned.isBlockStateLiquid(blockState) && plugin.getSettings().isLiquidUpdate()) ||\n                blockState.getBlock() instanceof BedBlock) {\n            setBlockContext.onSetBlockWithUpdate(blockPos, blockState);\n            return blockState;\n        }\n\n        setBlockContext.prepareChunkAccess(blockPos.getX() >> 4, blockPos.getZ() >> 4);\n\n        int indexY = setBlockContext.levelHeightAccessor().getSectionIndex(blockPos.getY());\n\n        LevelChunkSection levelChunkSection = setBlockContext.getChunkSection(indexY);\n\n        int blockX = blockPos.getX() & 15;\n        int blockY = blockPos.getY();\n        int blockZ = blockPos.getZ() & 15;\n\n        boolean isOriginallyChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection);\n\n        levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false);\n\n        Map<Heightmap.Types, Heightmap> heightmaps = setBlockContext.getHeightmaps();\n        heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState);\n        heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState);\n        heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState);\n        heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState);\n\n        setBlockContext.onPostSetBlock(blockPos, blockState);\n\n        boolean isChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection);\n\n        setBlockContext.onLightUpdate(blockPos, blockState, isOriginallyChunkSectionEmpty, isChunkSectionEmpty);\n\n        if (tileEntity != null) {\n            setBlockContext.onBlockEntityUpdate(blockPos, tileEntity);\n        }\n\n        return blockState;\n    }\n\n    public static boolean isDoubleBlock(Block block, BlockState blockState) {\n        return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) &&\n                blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE;\n    }\n\n    public static long getChunkPackedPos(int chunkX, int chunkZ) {\n        return (long) chunkX & 4294967295L | ((long) chunkZ & 4294967295L) << 32;\n    }\n\n    public record UnloadedChunkCompound(ChunkPosition chunkPosition,\n                                        net.minecraft.nbt.CompoundTag chunkCompound) {\n\n        public ServerLevel serverLevel () {\n            return ((CraftWorld) chunkPosition.getWorld()).getHandle();\n        }\n\n        public ChunkPos chunkPos () {\n            return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n        }\n\n    }\n\n    private static boolean isValidPosition(SetBlockContext setBlockContext, BlockPos blockPos) {\n        return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 &&\n                blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 &&\n                !setBlockContext.levelHeightAccessor().isOutsideBuildHeight(blockPos.getY());\n    }\n\n    public static abstract class ChunkCallback {\n\n        private final ChunkLoadReason chunkLoadReason;\n        private final boolean isWaitForChunkLoad;\n\n        @Nullable\n        protected CountDownLatch chunkLoadLatch;\n\n        public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) {\n            this.chunkLoadReason = chunkLoadReason;\n            this.isWaitForChunkLoad = isWaitForChunkLoad;\n        }\n\n        public abstract void onLoadedChunk(LevelChunk levelChunk);\n\n        public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound);\n\n        public abstract void onFinish();\n\n        protected final void latchCountDown() {\n            if (this.chunkLoadLatch != null)\n                this.chunkLoadLatch.countDown();\n        }\n\n        public final void onChunkNotExist(ChunkPosition chunkPosition) {\n            if (!plugin.getProviders().hasCustomWorldsSupport()) {\n                latchCountDown();\n                return;\n            }\n\n            ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> {\n                if (error == null) {\n                    BukkitExecutor.ensureMain(() -> {\n                        ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle();\n                        LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ());\n                        onLoadedChunk(levelChunk);\n                    });\n                } else {\n                    latchCountDown();\n                    throw new RuntimeException(error);\n                }\n            });\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/crops/CropsBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.LevelChunk;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class CropsBlockEntity extends BlockEntity {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Chunk2ObjectMap<CropsBlockEntity> tickingChunks = new Chunk2ObjectMap<>();\n\n    private final WeakReference<Island> island;\n    private final WeakReference<LevelChunk> chunk;\n\n    private int currentTick = 0;\n\n    private double cachedCropGrowthMultiplier;\n\n    private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) {\n        super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos));\n        this.island = new WeakReference<>(island);\n        this.chunk = new WeakReference<>(levelChunk);\n        setLevel(levelChunk.level);\n        levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this));\n        this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1;\n    }\n\n    public static void create(Island island, String worldName, LevelChunk levelChunk) {\n        int chunkX = levelChunk.locX;\n        int chunkZ = levelChunk.locZ;\n        long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ);\n        tickingChunks.computeIfAbsent(worldName, packedPos, () -> {\n            BlockPos blockPos = new BlockPos(chunkX << 4, 1, chunkZ << 4);\n            return new CropsBlockEntity(island, levelChunk, blockPos);\n        });\n    }\n\n    public static CropsBlockEntity remove(String worldName, long chunkPos) {\n        return tickingChunks.remove(worldName, chunkPos);\n    }\n\n    public static void forEachChunk(List<ChunkPosition> chunkPositions, Consumer<CropsBlockEntity> cropsBlockEntityConsumer) {\n        if (tickingChunks.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> {\n            long chunkKey = chunkPosition.asPair();\n            CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey);\n            if (cropsBlockEntity != null)\n                cropsBlockEntityConsumer.accept(cropsBlockEntity);\n        });\n    }\n\n    public boolean isValidBlockState(BlockState state) {\n        return true;\n    }\n\n    private net.minecraft.world.level.ChunkPos getPos() {\n        LevelChunk levelChunk = this.chunk.get();\n        return levelChunk == null ? null : levelChunk.getPos();\n    }\n\n    public void remove() {\n        this.remove = true;\n    }\n\n    public void tick() {\n        if (++currentTick <= plugin.getSettings().getCropsInterval())\n            return;\n\n        LevelChunk levelChunk = this.chunk.get();\n        Island island = this.island.get();\n        ServerLevel serverLevel = (ServerLevel) getLevel();\n\n        if (levelChunk == null || island == null || serverLevel == null) {\n            remove();\n            return;\n        }\n\n        currentTick = 0;\n\n        int worldRandomTick = serverLevel.getGameRules().${GET_RANDOM_TICK_SPEED_METHOD};\n        int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval());\n        if (chunkRandomTickSpeed > 0)\n            CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed);\n    }\n\n    public void setCropGrowthMultiplier(double cropGrowthMultiplier) {\n        this.cachedCropGrowthMultiplier = cropGrowthMultiplier;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops;\n\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.level.block.entity.TickingBlockEntity;\n\npublic record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity {\n\n\n    @Override\n    public void tick() {\n        cropsBlockEntity.tick();\n    }\n\n    @Override\n    public boolean isRemoved() {\n        return cropsBlockEntity.isRemoved();\n    }\n\n    @Override\n    public BlockPos getPos() {\n        return cropsBlockEntity.getBlockPos();\n    }\n\n    @Override\n    public String getType() {\n        return NMSUtilsVersioned.getBlockEntityTypeKey(cropsBlockEntity.getType()) + \"\";\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/crops/CropsTickingMethod.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.TickingBlockList;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic abstract class CropsTickingMethod {\n\n    private static final ReflectField<${SERVER_LEVEL_RANDOM_TYPE}> SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>(\n            ServerLevel.class, ${SERVER_LEVEL_RANDOM_TYPE}.class, \"simpleRandom\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ?\n            new PaperCropsTickingMethod() : new SpigotCropsTickingMethod();\n\n    private static Set<Block> CROPS_TO_GROW_CACHE;\n\n    static {\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate);\n    }\n\n    protected CropsTickingMethod() {\n\n    }\n\n    public static void register() {\n        // Calls the static initializer which registers the callback.\n    }\n\n    public static void tick(LevelChunk levelChunk, int tickSpeed) {\n        INSTANCE.doTick(levelChunk, tickSpeed);\n    }\n\n    protected abstract void doTick(LevelChunk levelChunk, int tickSpeed);\n\n    private static void onSettingsUpdate() {\n        CROPS_TO_GROW_CACHE = new HashSet<>();\n        plugin.getSettings().getCropsToGrow().forEach(cropName -> {\n            Key key = Keys.ofMaterialAndData(cropName);\n            if (key instanceof MaterialKey materialKey) {\n                Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial());\n                if (block != null && block.defaultBlockState().isRandomlyTicking())\n                    CROPS_TO_GROW_CACHE.add(block);\n            }\n        });\n    }\n\n    private static class PaperCropsTickingMethod extends CropsTickingMethod {\n\n        @Override\n        protected void doTick(LevelChunk levelChunk, int tickSpeed) {\n            ServerLevel serverLevel = levelChunk.level;\n            LevelChunkSection[] sections = levelChunk.getSections();\n\n            int minSection = NMSUtilsVersioned.getMinSection(serverLevel);\n            int chunkOffsetX = levelChunk.locX << 4;\n            int chunkOffsetZ = levelChunk.locZ << 4;\n\n            ${SERVER_LEVEL_RANDOM_TYPE} simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel);\n\n            for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {\n                LevelChunkSection levelChunkSection = sections[sectionIndex];\n                if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) {\n                    continue;\n                }\n\n                TickingBlockList tickList = NMSUtilsVersioned.getTickingBlockList(levelChunkSection);\n\n                int tickingBlocks = tickList.size();\n                if (tickingBlocks <= 0) {\n                    continue;\n                }\n\n                PalettedContainer<BlockState> states = levelChunkSection.states;\n\n                int offsetY = (sectionIndex + minSection) << 4;\n\n                for (int i = 0; i < tickSpeed; ++i) {\n                    int index = simpleRandom.nextInt() & 0xFFF;\n\n                    if (index >= tickingBlocks) {\n                        continue;\n                    }\n\n                    int location = (int) tickList.getRaw(index) & 0xFFFF;\n                    BlockState blockState = states.get(location);\n                    if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock()))\n                        continue;\n\n                    // do not use a mutable pos, as some random tick implementations store the input without calling immutable()!\n                    BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX,\n                            ((location >>> 8) & 15) | offsetY,\n                            ((location >>> 4) & 15) | chunkOffsetZ);\n\n                    blockState.randomTick(serverLevel, blockPos, simpleRandom);\n                }\n            }\n\n        }\n\n    }\n\n    private static class SpigotCropsTickingMethod extends CropsTickingMethod {\n\n        private static int random = ThreadLocalRandom.current().nextInt();\n\n        @Override\n        protected void doTick(LevelChunk levelChunk, int tickSpeed) {\n            LevelChunkSection[] sections = levelChunk.getSections();\n            ServerLevel serverLevel = levelChunk.level;\n\n            int chunkOffsetX = levelChunk.locX << 4;\n            int chunkOffsetZ = levelChunk.locZ << 4;\n\n            for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) {\n                LevelChunkSection levelChunkSection = sections[sectionIndex];\n                if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) {\n                    continue;\n                }\n\n                int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4;\n\n                for (int i = 0; i < tickSpeed; i++) {\n                    random = random * 3 + 1013904223;\n                    int factor = random >> 2;\n                    int x = factor & 15;\n                    int z = factor >> 8 & 15;\n                    int y = factor >> 16 & 15;\n                    BlockState blockState = levelChunkSection.getBlockState(x, y, z);\n                    if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) {\n                        BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ);\n                        blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom());\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.entity.boss.enderdragon.EnderDragon;\nimport net.minecraft.world.level.Level;\nimport org.bukkit.Location;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftEnderDragon;\n\npublic class AbstractIslandEntityEnderDragon extends EnderDragon {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @NotNull\n    public static EnderDragon fromEntityTypes(EntityType<? extends EnderDragon> entityTypes, Level level) {\n        return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) :\n                new EnderDragon(entityTypes, level);\n    }\n\n    protected final ServerLevel serverLevel;\n    protected final Dimension dimension;\n    protected BlockPos islandBlockPos;\n\n    protected AbstractIslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        this(level);\n        this.islandBlockPos = islandBlockPos;\n    }\n\n    protected AbstractIslandEntityEnderDragon(Level level) {\n        super(EntityType.ENDER_DRAGON, level);\n        this.serverLevel = (ServerLevel) level;\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld());\n    }\n\n    @Override\n    public void aiStep() {\n        DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep);\n    }\n\n    @Override\n    @NotNull\n    public CraftEnderDragon getBukkitEntity() {\n        return (CraftEnderDragon) super.getBukkitEntity();\n    }\n\n    protected void finalizeIslandEnderDragon() {\n        if (!(NMSUtilsVersioned.getEndDragonFight(this.serverLevel) instanceof EndDragonFightWrapper dragonFight))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null)\n            return;\n\n        Location middleBlock = island.getCenter(dimension);\n\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        if (dimensionConfig instanceof SettingsManager.Worlds.End) {\n            middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock);\n        }\n\n        this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ());\n\n        IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel,\n                this.islandBlockPos, (IslandEntityEnderDragon) this);\n        dragonFight.HANDLER.addDragonFight(island.getCache(), dragonBattle);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/dragon/DragonUtils.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.level.levelgen.feature.EndPodiumFeature;\n\nimport java.lang.reflect.Modifier;\n\npublic class DragonUtils {\n\n    private static final ReflectField<BlockPos> END_PODIUM_LOCATION = new ReflectField<BlockPos>(\n            EndPodiumFeature.class, BlockPos.class,\n            Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static BlockPos currentPodiumPosition = BlockPos.ZERO;\n\n    private DragonUtils() {\n\n    }\n\n    public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) {\n        try {\n            END_PODIUM_LOCATION.set(null, podiumPosition);\n            currentPodiumPosition = podiumPosition;\n            runnable.run();\n        } finally {\n            END_PODIUM_LOCATION.set(null, BlockPos.ZERO);\n            currentPodiumPosition = BlockPos.ZERO;\n        }\n    }\n\n    public static BlockPos getCurrentPodiumPosition() {\n        return currentPodiumPosition;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS};\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class EndWorldEndDragonFightHandler {\n\n    private static final IslandCacheKey<IslandEndDragonFight> CACHE_KEY = IslandCacheKeys.register(\"DRAGON_FIGHT\", IslandEndDragonFight.class);\n\n    private final List<IslandEndDragonFight> worldDragonFightsList = new LinkedList<>();\n\n    EndWorldEndDragonFightHandler() {\n    }\n\n    public void tick() {\n        this.worldDragonFightsList.forEach(IslandEndDragonFight::tick);\n    }\n\n    public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) {\n        IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight);\n        if (oldDragonFight != null)\n            this.worldDragonFightsList.remove(oldDragonFight);\n        this.worldDragonFightsList.add(endDragonFight);\n    }\n\n    @Nullable\n    public IslandEndDragonFight getDragonFight(IslandCache islandCache) {\n        return islandCache.get(CACHE_KEY);\n    }\n\n    @Nullable\n    public IslandEndDragonFight removeDragonFight(IslandCache islandCache) {\n        IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY);\n        if (endDragonFight != null)\n            this.worldDragonFightsList.remove(endDragonFight);\n        return endDragonFight;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/dragon/IslandEndDragonFight.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.world.entity.boss.enderdragon.EnderDragon;\nimport net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase;\nimport net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance;\nimport net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.TheEndPortalBlockEntity;\nimport net.minecraft.world.level.block.state.pattern.BlockInWorld;\nimport net.minecraft.world.level.block.state.pattern.BlockPattern;\nimport net.minecraft.world.level.block.state.pattern.BlockPatternBuilder;\nimport net.minecraft.world.level.block.state.predicate.BlockPredicate;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS};\nimport net.minecraft.world.level.levelgen.Heightmap;\nimport net.minecraft.world.phys.Vec3;\nimport org.bukkit.Location;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\n\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class IslandEndDragonFight extends EndDragonFightWrapper {\n\n    private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> DRAGON_BATTLE = initializeDragonBattleField();\n    private static final ReflectField<Boolean> SCAN_FOR_LEGACY_PORTALS = new ReflectField<>(\n            ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 3);\n    private static final ReflectField<Boolean> WAS_DRAGON_KILLED = new ReflectField<>(\n            ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 1);\n\n    private static final ReflectField<Integer> TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>(\n            ${END_DRAGON_FIGHT_CLASS}.class, int.class, Modifier.PRIVATE, 4);\n    private static final ReflectField<Vec3> LANDING_TARGET_POSITION = new ReflectField<>(\n            DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1);\n\n    private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start()\n            .aisle(\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \")\n            .aisle(\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \")\n            .aisle(\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \")\n            .aisle(\"  ###  \", \" #   # \", \"#     #\", \"#  #  #\", \"#     #\", \" #   # \", \"  ###  \")\n            .aisle(\"       \", \"  ###  \", \" ##### \", \" ##### \", \" ##### \", \"  ###  \", \"       \")\n            .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK)))\n            .build();\n\n    private final Island island;\n    private final BlockPos islandBlockPos;\n    private final Vec3 islandBlockVectored;\n    private final ServerLevel serverLevel;\n    private final IslandEntityEnderDragon entityEnderDragon;\n\n    private byte currentTick = 0;\n\n    public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) {\n        this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null);\n    }\n\n    public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos,\n                                @Nullable IslandEntityEnderDragon islandEntityEnderDragon) {\n        super(serverLevel);\n\n        this.island = island;\n        this.islandBlockPos = islandBlockPos;\n        this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos);\n        this.serverLevel = serverLevel;\n        this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon;\n\n        SCAN_FOR_LEGACY_PORTALS.set(this, false);\n        WAS_DRAGON_KILLED.set(this, false);\n        DRAGON_BATTLE.set(this.entityEnderDragon, this);\n\n        TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE);\n    }\n\n    @Override\n    public void tick() {\n        // doServerTick\n\n        DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick);\n\n        DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase();\n        if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) {\n            LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored);\n        }\n\n        if (++currentTick >= 20) {\n            updateBattlePlayers();\n            currentTick = 0;\n            TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE);\n        }\n    }\n\n    @Nullable\n    @Override\n    public BlockPattern.BlockPatternMatch findExitPortal() {\n        int chunkX = this.islandBlockPos.getX() >> 4;\n        int chunkZ = this.islandBlockPos.getZ() >> 4;\n\n        for (int x = -8; x <= 8; ++x) {\n            for (int z = -8; z <= 8; ++z) {\n                LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z);\n\n                for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) {\n                    if (blockEntity instanceof TheEndPortalBlockEntity) {\n                        BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(\n                                this.serverLevel, blockEntity.getBlockPos());\n\n                        if (blockPatternMatch != null) {\n                            if(getPortalPos() == null)\n                                setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos());\n\n                            return blockPatternMatch;\n                        }\n                    }\n                }\n            }\n        }\n\n        int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY();\n\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos currentPosition = wrapper.getHandle();\n            currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ());\n            for (int y = highestBlock; y >= NMSUtilsVersioned.getMinBuildHeight(this.serverLevel); --y) {\n                currentPosition.setY(y);\n\n                BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition);\n\n                if (blockPatternMatch != null) {\n                    if(getPortalPos() == null)\n                        setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos());\n\n                    return blockPatternMatch;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    @Override\n    public void resetSpikeCrystals() {\n        DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals);\n    }\n\n    public void removeBattlePlayers() {\n        List<ServerPlayer> dragonEventPlayers = new SequentialListBuilder<ServerPlayer>()\n                .build(this.dragonEvent.getPlayers());\n        for (ServerPlayer serverPlayer : dragonEventPlayers)\n            this.dragonEvent.removePlayer(serverPlayer);\n    }\n\n    public IslandEntityEnderDragon getEnderDragon() {\n        return this.entityEnderDragon;\n    }\n\n    private void updateBattlePlayers() {\n        Set<UUID> nearbyPlayers = new HashSet<>();\n\n        WorldInfo worldInfo = WorldInfo.of(this.serverLevel.getWorld());\n\n        try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) {\n            strategy.getPlayers(worldInfo).forEach(player -> {\n                ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                this.dragonEvent.addPlayer(serverPlayer);\n                nearbyPlayers.add(serverPlayer.getUUID());\n            });\n        }\n\n        List<ServerPlayer> dragonEventPlayers = new SequentialListBuilder<ServerPlayer>()\n                .build(this.dragonEvent.getPlayers());\n\n        dragonEventPlayers.stream()\n                .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID()))\n                .forEach(this.dragonEvent::removePlayer);\n    }\n\n    private IslandEntityEnderDragon spawnEnderDragon() {\n        IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos);\n\n        entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN);\n        NMSUtilsVersioned.moveEntity(entityEnderDragon, this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(),\n                this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F);\n\n        NMSUtilsVersioned.addEntity(this.serverLevel, entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL);\n\n        this.dragonUUID = entityEnderDragon.getUUID();\n        this.resetSpikeCrystals();\n\n        return entityEnderDragon;\n    }\n\n    private static ReflectField<${END_DRAGON_FIGHT_CLASS}> initializeDragonBattleField() {\n        ReflectField<${END_DRAGON_FIGHT_CLASS}> dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>(\n                EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n        if(dragonBattleField.isValid()) {\n            dragonBattleField = dragonBattleField.removeFinal();\n        } else {\n            dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>(\n                    EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1);\n        }\n\n        return dragonBattleField;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/dragon/SpikesCache.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon;\n\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.CacheStats;\nimport com.google.common.cache.LoadingCache;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.common.collect.Lists;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.util.Mth;\nimport net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS};\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class SpikesCache implements LoadingCache<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>> {\n\n    private static final SpikesCache INSTANCE = new SpikesCache();\n\n    private final LoadingCache<BlockPos, List<${SPIKE_FEATURE_CLASS}.EndSpike>> cachedSpikes = CacheBuilder.newBuilder()\n            .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader());\n\n    private long worldSeed;\n\n    public static SpikesCache getInstance() {\n        return INSTANCE;\n    }\n\n    private SpikesCache() {\n\n    }\n\n    @Override\n    public @NotNull\n    List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed) throws ExecutionException {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public @NotNull\n    List<${SPIKE_FEATURE_CLASS}.EndSpike> getUnchecked(@NotNull Long worldSeed) {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public @NotNull\n    ImmutableMap<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>> getAll(@NotNull Iterable<? extends Long> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public List<${SPIKE_FEATURE_CLASS}.EndSpike> apply(@NotNull Long worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void refresh(@NotNull Long worldSeed) {\n        try {\n            this.worldSeed = worldSeed;\n            cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public @NotNull\n    ConcurrentMap<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>> asMap() {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Nullable\n    @Override\n    public List<${SPIKE_FEATURE_CLASS}.EndSpike> getIfPresent(@NotNull Object worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public @NotNull\n    List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed,\n                                    @NotNull Callable<? extends List<${SPIKE_FEATURE_CLASS}.EndSpike>> loader) throws ExecutionException {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader);\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public @NotNull\n    ImmutableMap<Long, List<${SPIKE_FEATURE_CLASS}.EndSpike>> getAllPresent(@NotNull Iterable<?> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void put(@NotNull Long worldSeed, @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> spikes) {\n        try {\n            this.worldSeed = worldSeed;\n            cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes);\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public void putAll(Map<? extends Long, ? extends List<${SPIKE_FEATURE_CLASS}.EndSpike>> spikesMap) {\n        spikesMap.forEach(this::put);\n    }\n\n    @Override\n    public void invalidate(@NotNull Object worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void invalidateAll(@NotNull Iterable<?> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void invalidateAll() {\n        this.cachedSpikes.invalidateAll();\n    }\n\n    @Override\n    public long size() {\n        return this.cachedSpikes.size();\n    }\n\n    @Override\n    public @NotNull\n    CacheStats stats() {\n        return this.cachedSpikes.stats();\n    }\n\n    @Override\n    public void cleanUp() {\n        this.cachedSpikes.cleanUp();\n    }\n\n    private class InternalCacheLoader extends CacheLoader<BlockPos, List<${SPIKE_FEATURE_CLASS}.EndSpike>> {\n\n        @Override\n        public @NotNull\n        List<${SPIKE_FEATURE_CLASS}.EndSpike> load(@NotNull BlockPos blockPos) {\n            List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());\n\n            Collections.shuffle(list, new Random(worldSeed));\n            List<${SPIKE_FEATURE_CLASS}.EndSpike> spikesList = Lists.newArrayList();\n\n            for (int i = 0; i < 10; ++i) {\n                int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i)));\n                int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i)));\n                int l = list.get(i);\n                int radius = 2 + l / 3;\n                int height = 76 + l * 3;\n                boolean guarded = l == 1 || l == 2;\n\n                spikesList.add(new ${SPIKE_FEATURE_CLASS}.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded));\n            }\n\n            return spikesList;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/generator/IslandsGeneratorImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.generator.BiomeProvider;\nimport org.bukkit.generator.BlockPopulator;\nimport org.bukkit.generator.WorldInfo;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\npublic class IslandsGeneratorImpl extends IslandsGenerator {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Dimension dimension;\n\n    public IslandsGeneratorImpl(Dimension dimension) {\n        this.dimension = dimension;\n    }\n\n    @Override\n    public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ,\n                                @NotNull ChunkData chunkData) {\n        if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            chunkData.setBlock(0, 99, 0, Material.BEDROCK);\n        }\n    }\n\n    @Override\n    public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {\n        return new BiomeProvider() {\n            @Override\n            public @NotNull\n            Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) {\n                return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension);\n            }\n\n            @Override\n            public @NotNull\n            List<Biome> getBiomes(@NotNull WorldInfo worldInfo) {\n                return IslandUtils.getDefaultWorldBiomes();\n            }\n\n        };\n    }\n\n    @Override\n    public List<BlockPopulator> getDefaultPopulators(World world) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Location getFixedSpawnLocation(World world, Random random) {\n        return new Location(world, 0, 100, 0);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/hologram/AbstractEntityHologram.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram;\n\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.sounds.SoundEvent;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.damagesource.DamageSource;\nimport net.minecraft.world.entity.EquipmentSlot;\nimport net.minecraft.world.entity.decoration.ArmorStand;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.phys.AABB;\nimport net.minecraft.world.phys.Vec3;\nimport org.bukkit.Bukkit;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftServer;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftArmorStand;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftChatMessage;\n\npublic class AbstractEntityHologram extends ArmorStand implements Hologram {\n\n    private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D);\n\n    private CraftEntity bukkitEntity;\n\n    protected AbstractEntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n\n        setInvisible(true);\n        setSmall(true);\n        setShowArms(false);\n        setNoGravity(true);\n        setNoBasePlate(true);\n        setMarker(true);\n        forceSetBoundingBox(EMPTY_BOUND);\n\n        super.collides = false;\n        super.setCustomNameVisible(true);\n    }\n\n    @Override\n    public void setHologramName(String name) {\n        super.setCustomName(CraftChatMessage.fromStringOrNull(name));\n    }\n\n    @Override\n    public void removeHologram() {\n        super.remove(RemovalReason.DISCARDED);\n    }\n\n    @Override\n    public org.bukkit.entity.ArmorStand getHandle() {\n        return this.getBukkitEntity();\n    }\n\n    @Override\n    public void inactiveTick() {\n        // Disable normal ticking for this entity.\n\n        // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n        if (this.onGround) {\n            this.onGround = false;\n        }\n    }\n\n    @Override\n    public boolean repositionEntityAfterLoad() {\n        return false;\n    }\n\n    public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) {\n        // Prevent stand being equipped\n    }\n    public void setSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) {\n        // Prevent stand being equipped\n    }\n\n    @Override\n    public void tick() {\n        // Disable normal ticking for this entity.\n\n        // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n        if (this.onGround) {\n            this.onGround = false;\n        }\n    }\n\n    public void forceSetBoundingBox(AABB boundingBox) {\n        super.setBoundingBox(boundingBox);\n    }\n\n    @Override\n    public CraftArmorStand getBukkitEntity() {\n        if (bukkitEntity == null) {\n            bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this);\n        }\n        return (CraftArmorStand) bukkitEntity;\n    }\n\n    @Override\n    public void remove(RemovalReason removalReason) {\n        // Prevent being killed.\n    }\n\n    @Override\n    public void playSound(SoundEvent soundEvent, float volume, float pitch) {\n        // Remove sounds.\n    }\n\n    /*\n     * The field Entity.invulnerable is private.\n     * It's only used while saving NBTTags, but since the entity would be killed\n     * on chunk unload, we prefer to override isInvulnerable().\n     */\n    public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) {\n        return true;\n    }\n    public boolean isInvulnerableTo(DamageSource damageSource) {\n        return true;\n    }\n\n    @Override\n    public void setCustomName(Component component) {\n        // Locks the custom name.\n    }\n\n    @Override\n    public void setCustomNameVisible(boolean isCustomNameVisible) {\n        // Locks the custom name.\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/menu/MenuBrewingStandBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu;\n\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BrewingStandBlockEntity;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity {\n\n    private final InventoryHolder holder;\n\n    public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) {\n        super(BlockPos.ZERO, Blocks.AIR.defaultBlockState());\n        this.holder = holder;\n        this.name = Component.nullToEmpty(title);\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/menu/MenuDispenserBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu;\n\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.DispenserBlockEntity;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuDispenserBlockEntity extends DispenserBlockEntity {\n\n    private final InventoryHolder holder;\n\n    public MenuDispenserBlockEntity(InventoryHolder holder, String title) {\n        super(BlockPos.ZERO, Blocks.AIR.defaultBlockState());\n        this.holder = holder;\n        this.name = Component.nullToEmpty(title);\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/menu/MenuFurnaceBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu;\n\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.FurnaceBlockEntity;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuFurnaceBlockEntity extends FurnaceBlockEntity {\n\n    private final InventoryHolder holder;\n\n    public MenuFurnaceBlockEntity(InventoryHolder holder, String title) {\n        super(BlockPos.ZERO, Blocks.AIR.defaultBlockState());\n        this.holder = holder;\n        this.name = Component.nullToEmpty(title);\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/menu/MenuHopperBlockEntity.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu;\n\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.HopperBlock;\nimport net.minecraft.world.level.block.entity.HopperBlockEntity;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuHopperBlockEntity extends HopperBlockEntity {\n\n    private final InventoryHolder holder;\n\n    public MenuHopperBlockEntity(InventoryHolder holder, String title) {\n        super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN));\n        this.holder = holder;\n        this.name = Component.nullToEmpty(title);\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.level.Level;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftServer;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic class OfflinePlayerDataImpl implements OfflinePlayerData {\n\n    private static final ObjectsPool<OfflinePlayerDataImpl> POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new);\n    private static final ReflectMethod<Void> ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class);\n\n    private Player fakePlayer;\n\n    public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) {\n        return POOL.obtain().initialize(offlinePlayer);\n    }\n\n    private OfflinePlayerDataImpl() {\n\n    }\n\n    private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) {\n        GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(),\n                Optional.ofNullable(offlinePlayer.getName()).orElse(\"\"));\n\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        ServerLevel serverLevel = server.getLevel(Level.OVERWORLD);\n\n        if (serverLevel == null)\n            return null;\n\n        ServerPlayer serverPlayer = NMSUtilsVersioned.createServerPlayer(serverLevel, profile);\n        NMSUtilsVersioned.loadPlayerData(serverPlayer).ifPresent(playerData -> {\n            ResourceKey<Level> resourceKey;\n            if (playerData.contains(\"WorldUUIDMost\") && playerData.contains(\"WorldUUIDLeast\")) {\n                long worldUUIDMost = NMSUtilsVersioned.getCompoundTagLong(playerData, \"WorldUUIDMost\", 0L);\n                long worldUUIDLeast = NMSUtilsVersioned.getCompoundTagLong(playerData, \"WorldUUIDLeast\", 0L);\n                UUID uid = new UUID(worldUUIDMost, worldUUIDLeast);\n                World bukkitWorld = Bukkit.getServer().getWorld(uid);\n                if (bukkitWorld != null) {\n                    resourceKey = ((CraftWorld) bukkitWorld).getHandle().dimension();\n                } else {\n                    resourceKey = Level.OVERWORLD;\n                }\n            } else {\n                resourceKey = Level.OVERWORLD;\n            }\n\n            ServerLevel worldServer = server.getLevel(resourceKey);\n            if (worldServer == null) {\n                worldServer = server.overworld();\n            }\n\n            serverPlayer.setLevel(worldServer);\n        });\n\n        this.fakePlayer = serverPlayer.getBukkitEntity();\n\n        return this;\n    }\n\n    @Override\n    public Player getFakeOnlinePlayer() {\n        return this.fakePlayer;\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle();\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n        ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel);\n        NMSUtilsVersioned.moveEntity(serverPlayer, location.getX(), location.getY(),\n                location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    @Override\n    public void applyChanges() {\n        this.fakePlayer.saveData();\n    }\n\n    @Override\n    public void release() {\n        this.fakePlayer = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners;\n\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.level.BaseSpawner;\nimport net.minecraft.world.level.block.entity.SpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.TickingBlockEntity;\n\nimport java.util.function.IntFunction;\n\npublic class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity {\n\n    private final SpawnerBlockEntity spawnerBlockEntity;\n    private final TickingBlockEntity tickingBlockEntity;\n    private final IntFunction<Integer> delayChangeCallback;\n\n    public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity,\n                                             IntFunction<Integer> delayChangeCallback) {\n        this.spawnerBlockEntity = spawnerBlockEntity;\n        this.tickingBlockEntity = tickingBlockEntity;\n        this.delayChangeCallback = delayChangeCallback;\n        updateDelay();\n    }\n\n    @Override\n    public void tick() {\n        BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner();\n        int startDelay = baseSpawner.spawnDelay;\n        try {\n            tickingBlockEntity.tick();\n        } finally {\n            int newDelay = baseSpawner.spawnDelay;\n            if (newDelay > startDelay)\n                updateDelay();\n        }\n    }\n\n    @Override\n    public boolean isRemoved() {\n        return tickingBlockEntity.isRemoved();\n    }\n\n    @Override\n    public BlockPos getPos() {\n        return tickingBlockEntity.getPos();\n    }\n\n    @Override\n    public String getType() {\n        return tickingBlockEntity.getType();\n    }\n\n    public void updateDelay() {\n        BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner();\n        baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/utils/SetBlockContext.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.levelgen.Heightmap;\n\nimport java.util.Map;\n\npublic interface SetBlockContext {\n\n    LevelHeightAccessor levelHeightAccessor();\n\n    void prepareChunkAccess(int chunkX, int chunkZ);\n\n    LevelChunkSection getChunkSection(int i);\n\n    Map<Heightmap.Types, Heightmap> getHeightmaps();\n\n    void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState);\n\n    void onPostSetBlock(BlockPos blockPos, BlockState blockState);\n\n    void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty);\n\n    void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag);\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/utils/TickingBlockList.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils;\n\npublic interface TickingBlockList {\n\n    int size();\n\n    int getRaw(int index);\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/BlockEntityCache.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.state.BlockState;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class BlockEntityCache {\n\n    private static final Map<Block, String> BLOCK_TO_ID = new IdentityHashMap<>();\n\n    private BlockEntityCache() {\n\n    }\n\n    public static String getBlockEntityId(BlockState blockState) {\n        return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> {\n            for (BlockEntityType<?> blockEntityType : ${REGISTRY_CLASS}.BLOCK_ENTITY_TYPE) {\n                if (blockEntityType.isValid(blockState)) {\n                    Object resourceLocation = NMSUtilsVersioned.getBlockEntityTypeKey(blockEntityType);\n                    if (resourceLocation != null)\n                        return resourceLocation.toString();\n                }\n            }\n\n            return \"\";\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/ChunkReaderImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.SectionPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.level.LightLayer;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.BooleanProperty;\nimport net.minecraft.world.level.block.state.properties.EnumProperty;\nimport net.minecraft.world.level.block.state.properties.IntegerProperty;\nimport net.minecraft.world.level.chunk.DataLayer;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.InventoryHolder;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ChunkReaderImpl implements ChunkReader {\n\n    private static final PalettedContainer<BlockState> EMPTY_STATES = NMSUtilsVersioned.createEmptyPlattedContainerStates();\n    private static final byte[] FULL_LIGHT = new byte[2048];\n    private static final byte[] EMPTY_LIGHT = new byte[2048];\n\n    static {\n        Arrays.fill(FULL_LIGHT, (byte) 0xFF);\n    }\n\n    private final ServerLevel serverLevel;\n    private final int x;\n    private final int z;\n\n    private final Map<BlockPos, CompoundTag> blockEntities = new HashMap<>();\n    private final List<CachedEntity> entities = new LinkedList<>();\n    private final PalettedContainer<BlockState>[] blockids;\n    private final byte[][] skylight;\n    private final byte[][] emitlight;\n\n    public ChunkReaderImpl(Chunk bukkitChunk) {\n        this.serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle();\n        LevelChunk levelChunk = this.serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ());\n\n        this.x = levelChunk.locX;\n        this.z = levelChunk.locZ;\n\n        LevelChunkSection[] levelChunkSections = levelChunk.getSections();\n        this.blockids = new PalettedContainer[levelChunkSections.length];\n        this.skylight = new byte[levelChunkSections.length][];\n        this.emitlight = new byte[levelChunkSections.length][];\n\n        LevelLightEngine lightEngine = this.serverLevel.getLightEngine();\n\n        for (int i = 0; i < this.blockids.length; ++i) {\n            LevelChunkSection levelChunkSection = levelChunkSections[i];\n\n            this.blockids[i] = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection) ? EMPTY_STATES :\n                    NMSUtilsVersioned.copyPalettedContainer(levelChunkSection.getStates());\n\n            DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY)\n                    .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z));\n            if (skyLightArray == null) {\n                this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT;\n            } else {\n                this.skylight[i] = new byte[2048];\n                System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048);\n            }\n\n            DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK)\n                    .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z));\n            if (emitLightArray == null) {\n                this.emitlight[i] = EMPTY_LIGHT;\n            } else {\n                this.emitlight[i] = new byte[2048];\n                System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048);\n            }\n        }\n\n        levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> {\n            net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveBlockEntity(blockEntity);\n\n            compoundTag.remove(\"x\");\n            compoundTag.remove(\"y\");\n            compoundTag.remove(\"z\");\n\n            InventoryHolder inventoryHolder = blockEntity.getOwner();\n            if (inventoryHolder != null)\n                compoundTag.putString(\"inventoryType\", inventoryHolder.getInventory().getType().name());\n\n            blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag));\n        });\n\n        for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities())\n            entities.add(new CachedEntity(((CraftEntity) entity).getHandle()));\n    }\n\n    @Override\n    public int getX() {\n        return this.x;\n    }\n\n    @Override\n    public int getZ() {\n        return this.z;\n    }\n\n    @Override\n    public Material getType(int x, int y, int z) {\n        return NMSUtilsVersioned.getMaterialFromBlock(getBlockState(x, y, z).getBlock());\n    }\n\n    @Override\n    public short getData(int x, int y, int z) {\n        return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z));\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag getTileEntity(int x, int y, int z) {\n        try (ObjectsPools.Wrapper<BlockPos.MutableBlockPos> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPos.MutableBlockPos blockPos = wrapper.getHandle();\n            blockPos.set((this.x << 4) + x, y, (this.z << 4) + z);\n            return this.blockEntities.get(blockPos);\n        }\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag readBlockStates(int x, int y, int z) {\n        BlockState blockState = getBlockState(x, y, z);\n\n        CompoundTag compoundTag = CompoundTag.of();\n\n        boolean processedAny = NMSUtilsVersioned.forEachProperty(blockState, (property, value) -> {\n            String name = PropertiesMapper.getPropertyName(property);\n\n            if (property instanceof BooleanProperty) {\n                compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0);\n            } else if (property instanceof IntegerProperty integerProperty) {\n                compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max});\n            } else if (property instanceof EnumProperty<?>) {\n                compoundTag.setString(name, ((Enum<?>) value).name());\n            }\n        });\n\n        return processedAny ? compoundTag : null;\n    }\n\n    @Override\n    public byte[] getLightLevels(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        int skyLightLevel = this.skylight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15;\n        int emitLightLevel = this.emitlight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15;\n        return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel};\n    }\n\n    @Override\n    public void forEachEntity(EntityConsumer consumer) {\n        if (entities.isEmpty())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = wrapper.getHandle();\n            for (CachedEntity cachedEntity : entities) {\n                location.setX(cachedEntity.x);\n                location.setY(cachedEntity.y);\n                location.setZ(cachedEntity.z);\n                location.setYaw(cachedEntity.yaw);\n                location.setPitch(cachedEntity.pitch);\n                consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location);\n            }\n        }\n    }\n\n    private BlockState getBlockState(int x, int y, int z) {\n        return this.blockids[this.serverLevel.getSectionIndex(y)].get(x, y & 15, z);\n    }\n\n    private static class CachedEntity {\n\n        private final double x;\n        private final double y;\n        private final double z;\n        private final float yaw;\n        private final float pitch;\n        private final EntityType entityType;\n        private final CompoundTag entityTag;\n\n        CachedEntity(Entity entity) {\n            this.x = entity.getX();\n            this.y = entity.getY();\n            this.z = entity.getZ();\n            this.yaw = entity.getBukkitYaw();\n            this.pitch = entity.getXRot();\n            this.entityType = entity.getBukkitEntity().getType();\n\n            net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveEntity(entity);\n\n            compoundTag.putFloat(\"Yaw\", entity.getYRot());\n            compoundTag.putFloat(\"Pitch\", entity.getXRot());\n\n            this.entityTag = CompoundTag.fromNBT(compoundTag);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/KeyBlocksCache.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport net.minecraft.world.level.block.Block;\nimport org.bukkit.Material;\nimport ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class KeyBlocksCache {\n\n    private static final Map<Block, Key> BLOCK_TO_KEY = new IdentityHashMap<>();\n\n    private KeyBlocksCache() {\n\n    }\n\n    public static Key getBlockKey(Block block) {\n        return BLOCK_TO_KEY.computeIfAbsent(block, unused -> {\n            Material blockType = CraftMagicNumbers.getMaterial(block);\n            return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType);\n        });\n    }\n\n    public static void cacheAllBlocks() {\n        ${REGISTRY_CLASS}.BLOCK.forEach(KeyBlocksCache::getBlockKey);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/PropertiesMapper.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\nimport net.minecraft.world.level.block.state.properties.Property;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class PropertiesMapper {\n\n    private static final Map<String, Property<?>> nameToProperty = new HashMap<>();\n    private static final Map<Property<?>, String> propertyToName = new HashMap<>();\n\n    static {\n        Map<Object, String> fieldsToNames = new IdentityHashMap<>();\n\n        fieldsToNames.put(BlockStateProperties.AXIS, \"axis-empty\");\n        fieldsToNames.put(BlockStateProperties.FACING_HOPPER, \"facing-notup\");\n        fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, \"facing-horizontal\");\n        fieldsToNames.put(BlockStateProperties.EAST_WALL, \"wall-east\");\n        fieldsToNames.put(BlockStateProperties.NORTH_WALL, \"wall-north\");\n        fieldsToNames.put(BlockStateProperties.SOUTH_WALL, \"wall-south\");\n        fieldsToNames.put(BlockStateProperties.WEST_WALL, \"wall-west\");\n        fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, \"redstone-east\");\n        fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, \"redstone-north\");\n        fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, \"redstone-south\");\n        fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, \"redstone-west\");\n        fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, \"double-half\");\n        fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, \"track-shape-empty\");\n        fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, \"track-shape\");\n        fieldsToNames.put(BlockStateProperties.AGE_1, \"age1\");\n        fieldsToNames.put(BlockStateProperties.AGE_2, \"age2\");\n        fieldsToNames.put(BlockStateProperties.AGE_3, \"age3\");\n        fieldsToNames.put(BlockStateProperties.AGE_5, \"age5\");\n        fieldsToNames.put(BlockStateProperties.AGE_7, \"age7\");\n        fieldsToNames.put(BlockStateProperties.AGE_15, \"age15\");\n        fieldsToNames.put(BlockStateProperties.AGE_25, \"age25\");\n        fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, \"level3\");\n        fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, \"level8\");\n        fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, \"level1-8\");\n        fieldsToNames.put(BlockStateProperties.LEVEL, \"level15\");\n        fieldsToNames.put(BlockStateProperties.DISTANCE, \"distance1-7\");\n        fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, \"distance7\");\n        fieldsToNames.put(BlockStateProperties.CHEST_TYPE, \"chest-type\");\n        fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, \"comparator-mode\");\n        fieldsToNames.put(BlockStateProperties.PISTON_TYPE, \"piston-type\");\n        fieldsToNames.put(BlockStateProperties.SLAB_TYPE, \"slab-type\");\n\n        PropertiesMapperVersioned.initializeFields(fieldsToNames);\n\n        try {\n            for (Field field : BlockStateProperties.class.getFields()) {\n                field.setAccessible(true);\n                Object value = field.get(null);\n                if (value instanceof Property) {\n                    Property<?> property = (Property<?>) value;\n                    register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property);\n                }\n            }\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while loading properties mapper:\");\n        }\n\n    }\n\n    private static void register(String key, String fieldName, Property<?> property) {\n        if (nameToProperty.containsKey(key)) {\n            Log.error(\"Block state \", key, \"(\", fieldName, \") already exists. Contact Ome_R!\");\n        } else {\n            nameToProperty.put(key, property);\n            propertyToName.put(property, key);\n        }\n    }\n\n    public static Property<?> getProperty(String name) {\n        return nameToProperty.get(name);\n    }\n\n    public static String getPropertyName(Property<?> property) {\n        return propertyToName.get(property);\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.levelgen.Heightmap;\nimport net.minecraft.world.phys.Vec2;\nimport org.bukkit.Location;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class WorldEditSessionDataImpl implements WorldEditSession.Data {\n\n    private static final boolean isStarLightInterface = ((Supplier<Boolean>) () -> {\n        try {\n            Class.forName(\"ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }).get();\n\n    private final List<PositionedObject<PositionedChunkData>> chunks = new LinkedList<>();\n    private final List<PositionedObject<BlockState>> blocksToUpdate = new LinkedList<>();\n    private final List<PositionedObject<CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<PositionedObject<Void>> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList();\n\n    public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks,\n                                    List<Pair<BlockPos, BlockState>> blocksToUpdate,\n                                    List<Pair<BlockPos, CompoundTag>> blockEntities,\n                                    Set<Vec2> lightenChunks) {\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // Convert chunk data\n        Iterator<Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData>> chunksIterator = chunks.entryIterator();\n        while (chunksIterator.hasNext()) {\n            Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData> entry = chunksIterator.next();\n            int currChunkPosXAxis = ChunkPos.getX(entry.getKey());\n            int currChunkPosZAxis = ChunkPos.getZ(entry.getKey());\n            WorldEditSessionImpl.ChunkData chunkData = entry.getValue();\n\n            List<PositionedObject<Void>> lights;\n            if (isStarLightInterface || chunkData.lights().isEmpty()) {\n                lights = Collections.emptyList();\n            } else {\n                lights = new LinkedList<>();\n                chunkData.lights().forEach(lightPosition -> {\n                    lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis,\n                            lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis,\n                            null));\n                });\n            }\n\n            PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(),\n                    chunkData.heightmaps(), lights);\n\n            this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis,\n                    currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData));\n        }\n\n        // Convert blocksToUpdate\n        blocksToUpdate.forEach(blockToUpdate -> {\n            BlockPos blockPos = blockToUpdate.getKey();\n            this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis,\n                    blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis,\n                    blockToUpdate.getValue()));\n        });\n\n        // Convert blockEntities\n        blockEntities.forEach(blockEntity -> {\n            BlockPos blockPos = blockEntity.getKey();\n            this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis,\n                    blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis,\n                    blockEntity.getValue()));\n        });\n\n        // Convert lights\n        lightenChunks.forEach(lightPosition -> {\n            this.lightenChunks.add(new PositionedObject<>((int)lightPosition.x - baseChunkPosXAxis,\n                    (int)lightPosition.y - baseChunkPosZAxis, null));\n        });\n    }\n\n    public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis,\n                           int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession,\n                           Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks) {\n        this.chunks.forEach(chunkDataPositioned -> {\n            long newPos = NMSUtils.getChunkPackedPos(baseChunkPosXAxis + chunkDataPositioned.xOffset,\n                    baseChunkPosZAxis + chunkDataPositioned.zOffset);\n\n            List<BlockPos> lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>();\n            chunkDataPositioned.object.lights.forEach(lightPositioned -> {\n                lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset,\n                        baseBlockPosYAxis + lightPositioned.yOffset,\n                        baseBlockPosZAxis + lightPositioned.zOffset));\n            });\n\n            chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections,\n                    chunkDataPositioned.object.heightmaps, lights));\n        });\n    }\n\n    public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPos, BlockState>> blocksToUpdate) {\n        this.blocksToUpdate.forEach(blockToUpdatePositioned -> {\n            BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset,\n                    baseBlockPosYAxis + blockToUpdatePositioned.yOffset,\n                    baseBlockPosZAxis + blockToUpdatePositioned.zOffset);\n            blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object));\n        });\n    }\n\n    public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPos, CompoundTag>> blockEntities) {\n        this.blockEntities.forEach(blockEntityPositioned -> {\n            BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset,\n                    baseBlockPosYAxis + blockEntityPositioned.yOffset,\n                    baseBlockPosZAxis + blockEntityPositioned.zOffset);\n            blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object));\n        });\n    }\n\n    public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set<ChunkPos> lightenChunks) {\n        this.lightenChunks.forEach(lightPositioned -> {\n            ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset,\n                    baseChunkPosZAxis + lightPositioned.zOffset);\n            lightenChunks.add(newPos);\n        });\n    }\n\n    private static class PositionedObject<V> {\n\n        private final int xOffset;\n        private final int yOffset;\n        private final int zOffset;\n        private final V object;\n\n        PositionedObject(int xOffset, int zOffset, V object) {\n            this(xOffset, 0, zOffset, object);\n        }\n\n        PositionedObject(int xOffset, int yOffset, int zOffset, V object) {\n            this.xOffset = xOffset;\n            this.yOffset = yOffset;\n            this.zOffset = zOffset;\n            this.object = object;\n        }\n\n    }\n\n    private record PositionedChunkData(LevelChunkSection[] chunkSections, Map<Heightmap.Types, Heightmap> heightmaps,\n                                       List<PositionedObject<Void>> lights) {\n    }\n\n}\n"
  },
  {
    "path": "NMS/src/main/templates/world/WorldEditSessionImpl.java.template",
    "content": "package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.google.common.base.Preconditions;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.levelgen.Heightmap;\nimport net.minecraft.world.phys.Vec2;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport ${CRAFTBUKKIT_PACKAGE}.CraftWorld;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class WorldEditSessionImpl implements WorldEditSession {\n\n    private static final ObjectsPool<WorldEditSessionImpl> POOL = new ObjectsPool<>(WorldEditSessionImpl::new);\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final boolean isStarLightInterface = ((Supplier<Boolean>) () -> {\n        try {\n            Class.forName(\"${STAR_LIGHT_INTERFACE_CLASS}\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }).get();\n\n    private final Long2ObjectMapView<ChunkData> chunks = CollectionsFactory.createLong2ObjectArrayMap();\n    private final List<Pair<BlockPos, BlockState>> blocksToUpdate = new LinkedList<>();\n    private final List<Pair<BlockPos, CompoundTag>> blockEntities = new LinkedList<>();\n    private final Set<Vec2> lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet();\n    private final Set<ChunkPos> lightenChunksPositions = isStarLightInterface ? new HashSet<>() : Collections.emptySet();\n\n    private Dimension dimension;\n    private LevelHeightAccessor levelHeightAccessor;\n\n    @Nullable\n    private ServerLevel serverLevel;\n\n    private final SetBlockContext SET_BLOCK_CONTEXT = new SetBlockContext() {\n\n        ChunkData chunkData;\n\n        @Override\n        public LevelHeightAccessor levelHeightAccessor() {\n            return levelHeightAccessor;\n        }\n\n        @Override\n        public void prepareChunkAccess(int chunkX, int chunkZ) {\n            long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ);\n            chunkData = chunks.computeIfAbsent(packedPos, pos -> new ChunkData(new ChunkPos(chunkX, chunkZ)));\n        }\n\n        @Override\n        public LevelChunkSection getChunkSection(int i) {\n            return chunkData.chunkSections[i];\n        }\n\n        @Override\n        public Map<Heightmap.Types, Heightmap> getHeightmaps() {\n            return chunkData.heightmaps;\n        }\n\n        @Override\n        public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) {\n            blocksToUpdate.add(new Pair<>(blockPos, blockState));\n        }\n\n        @Override\n        public void onPostSetBlock(BlockPos blockPos, BlockState blockState) {\n            // Do nothing\n        }\n\n        @Override\n        public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) {\n            if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0)\n                chunkData.lights.add(blockPos);\n        }\n\n        @Override\n        public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) {\n            blockEntities.add(new Pair<>(blockPos, blockEntityTag));\n        }\n\n    };\n\n    public static WorldEditSessionImpl obtain(ServerLevel serverLevel) {\n        return POOL.obtain().initialize(serverLevel);\n    }\n\n    public static WorldEditSessionImpl obtain(Dimension dimension) {\n        return POOL.obtain().initialize(dimension);\n    }\n\n    private WorldEditSessionImpl() {\n    }\n\n    private WorldEditSessionImpl initialize(ServerLevel serverLevel) {\n        this.serverLevel = serverLevel;\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld());\n        this.levelHeightAccessor = serverLevel;\n        return this;\n    }\n\n    private WorldEditSessionImpl initialize(Dimension dimension) {\n        DimensionType dimensionType = NMSUtilsVersioned.getDimensionTypeFromDimension(dimension);\n        this.serverLevel = null;\n        this.dimension = dimension;\n        this.levelHeightAccessor = createLevelHeightAccessor(dimensionType.minY(), dimensionType.height());\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag,\n                         @Nullable CompoundTag blockEntityData) {\n        BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n        NMSUtils.setBlock(SET_BLOCK_CONTEXT, blockPos, combinedId, statesTag, blockEntityData);\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        Preconditions.checkState(this.serverLevel != null, \"Cannot call WorldEditSession#getAffectedChunks on partial initialized session\");\n\n        if (chunks.isEmpty())\n            return Collections.emptyList();\n\n        List<ChunkPosition> chunkPositions = new LinkedList<>();\n        World bukkitWorld = serverLevel.getWorld();\n        LongIterator iterator = chunks.keyIterator();\n        while (iterator.hasNext()) {\n            long chunkKey = iterator.next();\n            int chunkX = (int) chunkKey;\n            int chunkZ = (int) (chunkKey >> 32);\n            chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false));\n        }\n        return chunkPositions;\n    }\n\n    @Override\n    public void applyBlocks(Chunk bukkitChunk) {\n        Preconditions.checkState(this.serverLevel != null, \"Cannot call WorldEditSession#applyBlocks on partial initialized session\");\n\n        int chunkX = bukkitChunk.getX();\n        int chunkZ = bukkitChunk.getZ();\n\n        ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle();\n        LevelChunk levelChunk = serverLevel.getChunk(chunkX, chunkZ);\n\n        long chunkKey = NMSUtils.getChunkPackedPos(chunkX, chunkZ);\n        ChunkData chunkData = this.chunks.remove(chunkKey);\n\n        if (chunkData == null)\n            return;\n\n        int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length);\n        for (int i = 0; i < chunkSectionsCount; ++i) {\n            levelChunk.getSections()[i] = chunkData.chunkSections[i];\n        }\n\n        chunkData.heightmaps.forEach(((type, heightmap) -> {\n            levelChunk.setHeightmap(type, heightmap.getRawData());\n        }));\n\n        if (plugin.getSettings().isLightsUpdate()) {\n            if (isStarLightInterface) {\n                this.lightenChunks.add(new Vec2(chunkX, chunkZ));\n                this.lightenChunksPositions.add(levelChunk.getPos());\n            } else {\n                ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine();\n                chunkData.lights.forEach(threadedLevelLightEngine::checkBlock);\n                // Queues chunk light for this chunk.\n                threadedLevelLightEngine.lightChunk(levelChunk, false);\n            }\n        }\n\n        NMSUtilsVersioned.markUnsaved(levelChunk);\n    }\n\n    @Override\n    public void finish(Island island) {\n        Preconditions.checkState(this.serverLevel != null, \"Cannot call WorldEditSession#finish on partial initialized session\");\n\n        // Update blocks\n        blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3));\n\n        // Update block entities\n        blockEntities.forEach(data -> {\n            net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT();\n            if (blockEntityCompound != null) {\n                BlockPos blockPos = data.getKey();\n                blockEntityCompound.putInt(\"x\", blockPos.getX());\n                blockEntityCompound.putInt(\"y\", blockPos.getY());\n                blockEntityCompound.putInt(\"z\", blockPos.getZ());\n\n                NMSUtilsVersioned.rewriteSignLines(blockEntityCompound);\n\n                BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos);\n                if (worldBlockEntity != null) {\n                    NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, blockEntityCompound);\n                }\n            }\n        });\n\n        if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) {\n            ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine();\n            NMSUtilsVersioned.relightChunks(threadedLevelLightEngine, lightenChunksPositions);\n            this.lightenChunks.clear();\n            this.lightenChunksPositions.clear();\n        }\n\n        release();\n    }\n\n    @Override\n    public Data readData(Location baseLocation) {\n        return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks);\n    }\n\n    @Override\n    public void applyData(Data data, Location baseLocation) {\n        WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data;\n\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // We need to transform all data to the new base location values\n\n        dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis,\n                baseBlockPosZAxis, this, this.chunks);\n        dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate);\n        dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities);\n        dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunksPositions);\n    }\n\n    @Override\n    public void release() {\n        this.chunks.clear();\n        this.blocksToUpdate.clear();\n        this.blockEntities.clear();\n        this.lightenChunks.clear();\n        this.lightenChunksPositions.clear();\n        this.serverLevel = null;\n        this.dimension = null;\n        this.levelHeightAccessor = null;\n        POOL.release(this);\n    }\n\n    public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map<Heightmap.Types, Heightmap> heightmaps, List<BlockPos> lights) {\n        return new ChunkData(chunkSections, heightmaps, lights);\n    }\n\n    private boolean isValidPosition(BlockPos blockPos) {\n        return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 &&\n                blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 &&\n                !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY());\n    }\n\n    private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) {\n        return new LevelHeightAccessor() {\n            @Override\n            public int getHeight() {\n                return height;\n            }\n\n            public int getMinBuildHeight() {\n                return minY;\n            }\n\n            public int getMinY() {\n                return minY;\n            }\n        };\n    }\n\n    public class ChunkData {\n\n        private final LevelChunkSection[] chunkSections;\n        private final Map<Heightmap.Types, Heightmap> heightmaps;\n        private final List<BlockPos> lights;\n\n        private ChunkData(ChunkPos chunkPos) {\n            this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class),\n                    isStarLightInterface ? Collections.emptyList() : new LinkedList<>());\n\n            NMSUtilsVersioned.createChunkSections(serverLevel, levelHeightAccessor, this.chunkSections, dimension);\n\n            ProtoChunk tempChunk = NMSUtilsVersioned.createProtoChunk(\n                    chunkPos, this.chunkSections, levelHeightAccessor, serverLevel);\n\n            createHeightmaps(tempChunk);\n            if (serverLevel != null)\n                runCustomWorldGenerator(tempChunk);\n        }\n\n        private ChunkData(LevelChunkSection[] chunkSections, Map<Heightmap.Types, Heightmap> heightmaps, List<BlockPos> lights) {\n            this.chunkSections = chunkSections;\n            this.heightmaps = heightmaps;\n            this.lights = lights;\n        }\n\n        public LevelChunkSection[] chunkSections() {\n            return this.chunkSections;\n        }\n\n        public Map<Heightmap.Types, Heightmap> heightmaps() {\n            return this.heightmaps;\n        }\n\n        public List<BlockPos> lights() {\n            return this.lights;\n        }\n\n        private void runCustomWorldGenerator(ProtoChunk tempChunk) {\n            ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n            if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n                return;\n\n            NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, tempChunk);\n\n            // We want to copy the level chunk sections back\n            LevelChunkSection[] tempChunkSections = tempChunk.getSections();\n            for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) {\n                LevelChunkSection chunkSection = tempChunkSections[i];\n                if (chunkSection != null)\n                    this.chunkSections[i] = chunkSection;\n            }\n        }\n\n        private void createHeightmaps(ProtoChunk tempChunk) {\n            for (Heightmap.Types heightmapType : Heightmap.Types.values()) {\n                if (${CHUNK_STATUS_CLASS}.FULL.heightmapsAfter().contains(heightmapType)) {\n                    this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType));\n                }\n            }\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/build.gradle",
    "content": "group 'NMS:v1_12_R1'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_12_R1-Paper:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('nms.compile_v1_12') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_12\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.BlockEntityCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.EntityFallingBlock;\nimport net.minecraft.server.v1_12_R1.EntityMinecartAbstract;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.IChatBaseComponent;\nimport net.minecraft.server.v1_12_R1.Item;\nimport net.minecraft.server.v1_12_R1.MinecraftKey;\nimport net.minecraft.server.v1_12_R1.MinecraftServer;\nimport net.minecraft.server.v1_12_R1.World;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftServer;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftFallingBlock;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecart;\nimport org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.enchantments.EnchantmentTarget;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.PotionEffect;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class NMSAlgorithmsImpl implements NMSAlgorithms {\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void registerCommand(BukkitCommand command) {\n        ((CraftServer) plugin.getServer()).getCommandMap().register(\"superiorskyblock2\", command);\n    }\n\n    @Override\n    public String parseSignLine(String original) {\n        return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public int getCombinedId(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        IBlockData blockData;\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            blockData = world.getType(wrapper.getHandle());\n        }\n        return Block.getCombinedId(blockData);\n    }\n\n    @Override\n    public int getCombinedId(Material material, byte data) {\n        //noinspection deprecation\n        return material.getId() + (data << 12);\n    }\n\n    @Override\n    public Optional<String> getTileEntityIdFromCombinedId(int combinedId) {\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (!blockData.getBlock().isTileEntity())\n            return Optional.empty();\n\n        String id = BlockEntityCache.getTileEntityId(blockData);\n\n        return Text.isBlank(id) ? Optional.empty() : Optional.of(id);\n    }\n\n    @Override\n    public int compareMaterials(Material o1, Material o2) {\n        return Integer.compare(o1.ordinal(), o2.ordinal());\n    }\n\n    @Override\n    public short getBlockDataValue(BlockState blockState) {\n        return blockState.getRawData();\n    }\n\n    @Override\n    public short getBlockDataValue(org.bukkit.block.Block block) {\n        return block.getData();\n    }\n\n    @Override\n    public short getMaxBlockDataValue(Material material) {\n        return 0;\n    }\n\n    @Override\n    public Key getBlockKey(int combinedId) {\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n        return KeyBlocksCache.getBlockKey(blockData);\n    }\n\n    @Override\n    public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) {\n        EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle();\n        return KeyBlocksCache.getBlockKey(minecart.getDisplayBlock());\n    }\n\n    @Override\n    public Key getFallingBlockType(FallingBlock bukkitFallingBlock) {\n        EntityFallingBlock fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle();\n        return Optional.ofNullable(fallingBlock.getBlock()).map(KeyBlocksCache::getBlockKey).orElse(ConstantKeys.AIR);\n    }\n\n    @Override\n    public void setCustomModel(ItemMeta itemMeta, int customModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) {\n        if (!potionMeta.hasCustomEffects())\n            potionMeta.setColor(potionEffect.getType().getColor());\n        potionMeta.addCustomEffect(potionEffect, true);\n    }\n\n    @Override\n    public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) {\n        MinecraftKey minecraftKey = Item.REGISTRY.b(CraftItemStack.asNMSCopy(itemStack).getItem());\n        return minecraftKey == null ? \"minecraft:air\" : minecraftKey.toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public int getMaxWorldSize() {\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        return server.getPropertyManager().getInt(\"max-world-size\", 29999984);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public int getDataVersion() {\n        return -1;\n    }\n\n    @Override\n    public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) {\n        return defaultHolder;\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        try {\n            return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH));\n        } catch (IllegalArgumentException e) {\n            return null;\n        }\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        int enchantId = 100;\n        while (Enchantment.getById(enchantId) != null)\n            ++enchantId;\n\n        Enchantment glowEnchant = new Enchantment(enchantId) {\n            @Override\n            public String getName() {\n                return \"WildBusterGlow\";\n            }\n\n            @Override\n            public int getMaxLevel() {\n                return 1;\n            }\n\n            @Override\n            public int getStartLevel() {\n                return 0;\n            }\n\n            @Override\n            public EnchantmentTarget getItemTarget() {\n                return null;\n            }\n\n            @Override\n            public boolean isTreasure() {\n                return false;\n            }\n\n            @Override\n            public boolean isCursed() {\n                return false;\n            }\n\n            @Override\n            public boolean conflictsWith(Enchantment enchantment) {\n                return false;\n            }\n\n            @Override\n            public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) {\n                return true;\n            }\n        };\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\n\npublic class NMSCachedBlock implements ICachedBlock {\n\n    private static final ObjectsPool<NMSCachedBlock> POOL = new ObjectsPool<>(NMSCachedBlock::new);\n\n    private Material blockType;\n    private byte blockData;\n\n    public static NMSCachedBlock obtain(Block block) {\n        return POOL.obtain().initialize(block);\n    }\n\n    private NMSCachedBlock() {\n\n    }\n\n    private NMSCachedBlock initialize(Block block) {\n        this.blockType = block.getType();\n        this.blockData = block.getData();\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location) {\n        Block block = location.getWorld().getBlockAt(location);\n        block.setType(blockType);\n        block.setData(blockData);\n    }\n\n    @Override\n    public void release() {\n        this.blockType = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.NMSChunks;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.CropsTickingTileEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.EmptyCounterChunkSection;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_12_R1.BiomeBase;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockDoubleStep;\nimport net.minecraft.server.v1_12_R1.BlockDoubleStepAbstract;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Blocks;\nimport net.minecraft.server.v1_12_R1.Chunk;\nimport net.minecraft.server.v1_12_R1.ChunkCoordIntPair;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.EntityHuman;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.MinecraftKey;\nimport net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk;\nimport net.minecraft.server.v1_12_R1.PacketPlayOutUnloadChunk;\nimport net.minecraft.server.v1_12_R1.PlayerConnection;\nimport net.minecraft.server.v1_12_R1.TileEntity;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftChunk;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;\nimport org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_12_R1.util.UnsafeList;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl implements NMSChunks {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        KeyBlocksCache.cacheAllBlocks();\n        CropsTickingTileEntity.register();\n    }\n\n    @Override\n    public void setBiome(List<ChunkPosition> chunkPositions, Biome biome, Collection<Player> playersToUpdate) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        byte biomeBase = (byte) BiomeBase.REGISTRY_ID.a(CraftBlock.biomeToBiomeBase(biome));\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                Arrays.fill(chunk.getBiomeIndex(), biomeBase);\n                chunk.markDirty();\n            }\n\n            @Override\n            public void onUpdateChunk(Chunk chunk) {\n                PacketPlayOutUnloadChunk unloadChunkPacket = new PacketPlayOutUnloadChunk(chunk.locX, chunk.locZ);\n                PacketPlayOutMapChunk mapChunkPacket = new PacketPlayOutMapChunk(chunk, 65535);\n\n                playersToUpdate.forEach(player -> {\n                    PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection;\n                    playerConnection.sendPacket(unloadChunkPacket);\n                    playerConnection.sendPacket(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        });\n    }\n\n    @Override\n    public void deleteChunks(Island island, List<ChunkPosition> chunkPositions, @Nullable Runnable onFinish) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(),\n                chunkPosition.getX(), chunkPosition.getZ(), false));\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                Arrays.fill(chunk.getSections(), Chunk.a);\n\n                removeEntities(chunk);\n                removeTileEntities(chunk);\n                removeBlocks(chunk);\n            }\n\n            @Override\n            public void onUpdateChunk(Chunk chunk) {\n                // Do nothing.\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        });\n    }\n\n    private static boolean isChunkSectionEmpty(ChunkSection chunkSection) {\n        return chunkSection instanceof EmptyCounterChunkSection && ((EmptyCounterChunkSection) chunkSection).isEmpty();\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Blocks>> calculateChunks(List<ChunkPosition> chunkPositions,\n                                                                           Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache) {\n        List<CalculatedChunk.Blocks> allCalculatedChunks = new LinkedList<>();\n        List<ChunkPosition> chunkPositionsToCalculate = new LinkedList<>();\n\n        Iterator<ChunkPosition> chunkPositionsIterator = chunkPositions.iterator();\n        while (chunkPositionsIterator.hasNext()) {\n            ChunkPosition chunkPosition = chunkPositionsIterator.next();\n            CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition));\n            if (cachedCalculatedChunk != null) {\n                allCalculatedChunks.add(cachedCalculatedChunk);\n                chunkPositionsIterator.remove();\n            } else {\n                chunkPositionsToCalculate.add(chunkPosition);\n            }\n        }\n\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(allCalculatedChunks);\n\n        CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture = new CompletableFuture<>();\n\n        NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                World bukkitWorld = chunk.world.getWorld();\n                ChunkPosition chunkPosition = ChunkPosition.of(bukkitWorld, chunk.locX, chunk.locZ, false);\n\n                KeyMap<Counter> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n                List<Location> spawnersLocations = new LinkedList<>();\n\n                for (ChunkSection chunkSection : chunk.getSections()) {\n                    if (chunkSection != null && chunkSection != Chunk.a && !isChunkSectionEmpty(chunkSection)) {\n                        for (BlockPosition bp : BlockPosition.b(0, 0, 0, 15, 15, 15)) {\n                            IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ());\n                            Block block = blockData.getBlock();\n                            if (block != Blocks.AIR) {\n                                Location location = new Location(bukkitWorld,\n                                        (chunkPosition.getX() << 4) + bp.getX(),\n                                        chunkSection.getYPosition() + bp.getY(),\n                                        (chunkPosition.getZ() << 4) + bp.getZ());\n                                int blockAmount = 1;\n\n                                if (block instanceof BlockDoubleStep) {\n                                    blockAmount = 2;\n                                    // Converts the block data to a regular slab\n                                    MinecraftKey blockKey = Block.REGISTRY.b(block);\n                                    blockData = Block.REGISTRY.get(new MinecraftKey(blockKey.getKey()\n                                                    .replace(\"double_\", \"\"))).getBlockData()\n                                            .set(BlockDoubleStepAbstract.VARIANT, blockData.get(BlockDoubleStepAbstract.VARIANT));\n                                }\n\n                                Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData), location);\n                                blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount);\n                                if (block == Blocks.MOB_SPAWNER) {\n                                    spawnersLocations.add(location);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations);\n                allCalculatedChunks.add(calculatedChunk);\n                if (!isLoaded)\n                    unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n            }\n\n            @Override\n            public void onUpdateChunk(Chunk chunk) {\n                // Do nothing.\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Entities>> calculateChunkEntities(Collection<ChunkPosition> chunkPositions) {\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(Collections.emptyList());\n\n        CompletableFuture<List<CalculatedChunk.Entities>> completableFuture = new CompletableFuture<>();\n\n        List<CalculatedChunk.Entities> allCalculatedChunks = new LinkedList<>();\n\n        NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() {\n\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n                for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) {\n                    if (!BukkitEntities.canBypassEntityLimit(bukkitEntity))\n                        chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1);\n                }\n\n                ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false);\n                CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities);\n                allCalculatedChunks.add(calculatedChunk);\n            }\n\n            @Override\n            public void onUpdateChunk(Chunk chunk) {\n                // Do nothing\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public void injectChunkSections(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        for (int i = 0; i < 16; i++)\n            chunk.getSections()[i] = EmptyCounterChunkSection.of(chunk.getSections()[i]);\n    }\n\n    @Override\n    public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.a());\n    }\n\n    @Override\n    public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) {\n        Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().getChunkProviderServer()\n                .getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n        return chunk == null ? null : chunk.bukkitChunk;\n    }\n\n    @Override\n    public void updateCropsTicker(List<ChunkPosition> chunkPositions, double newCropGrowthMultiplier) {\n        if (chunkPositions.isEmpty()) return;\n        CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity ->\n                cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier));\n    }\n\n    @Override\n    public void shutdown() {\n        List<CompletableFuture<Void>> pendingTasks = NMSUtils.getPendingChunkActions();\n\n        if (pendingTasks.isEmpty())\n            return;\n\n        Log.info(\"Waiting for chunk tasks to complete.\");\n\n        CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join();\n    }\n\n    @Override\n    public List<Location> getBlockEntities(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        List<Location> blockEntities = new LinkedList<>();\n\n        World bukkitWorld = bukkitChunk.getWorld();\n\n        chunk.getTileEntities().keySet().forEach(blockPosition ->\n                blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ())));\n\n        return blockEntities;\n    }\n\n    @Override\n    public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) {\n        if (plugin.getSettings().getCropsInterval() <= 0)\n            return;\n\n        if (stop) {\n            CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove(\n                    chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ()));\n            if (cropsTickingTileEntity != null)\n                cropsTickingTileEntity.getWorld().tileEntityListTick.remove(cropsTickingTileEntity);\n        } else {\n            CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle());\n        }\n    }\n\n    private static void removeEntities(Chunk chunk) {\n        for (int i = 0; i < chunk.entitySlices.length; i++) {\n            chunk.entitySlices[i].forEach(entity -> {\n                if (!(entity instanceof EntityHuman))\n                    entity.dead = true;\n            });\n            chunk.entitySlices[i] = new UnsafeList<>();\n        }\n    }\n\n    private static void removeTileEntities(Chunk chunk) {\n        chunk.tileEntities.forEach(((blockPosition, tileEntity) -> {\n            chunk.world.tileEntityListTick.remove(tileEntity);\n            chunk.world.capturedTileEntities.remove(blockPosition);\n        }));\n\n        chunk.tileEntities.clear();\n    }\n\n    private static void removeBlocks(Chunk chunk) {\n        WorldServer worldServer = (WorldServer) chunk.world;\n\n        if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) {\n            CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, 0L, worldServer.generator);\n            Chunk generatedChunk = customChunkGenerator.getOrCreateChunk(chunk.locX, chunk.locZ);\n\n            for (int i = 0; i < 16; i++)\n                chunk.getSections()[i] = generatedChunk.getSections()[i];\n\n            for (Map.Entry<BlockPosition, TileEntity> entry : generatedChunk.getTileEntities().entrySet())\n                worldServer.setTileEntity(entry.getKey(), entry.getValue());\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.nms.NMSDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.EndWorldEnderDragonBattleHandler;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.IslandEnderDragonBattle;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.IslandEntityEnderDragon;\nimport net.minecraft.server.v1_12_R1.EnderDragonBattle;\nimport net.minecraft.server.v1_12_R1.EntityTypes;\nimport net.minecraft.server.v1_12_R1.MinecraftKey;\nimport net.minecraft.server.v1_12_R1.WorldProviderTheEnd;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.World;\nimport org.bukkit.advancement.Advancement;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.entity.EnderDragon;\nimport org.bukkit.entity.Player;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSDragonFightImpl implements NMSDragonFight {\n\n    private static final ReflectField<EnderDragonBattle> WORLD_DRAGON_BATTLE = new ReflectField<>(\n            WorldProviderTheEnd.class, EnderDragonBattle.class, Modifier.PRIVATE, 1);\n\n    static {\n        EntityTypes.b.a(63, new MinecraftKey(\"ender_dragon\"), IslandEntityEnderDragon.class);\n    }\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n        WORLD_DRAGON_BATTLE.set(worldServer.worldProvider, new EndWorldEnderDragonBattleHandler(worldServer));\n    }\n\n    @Nullable\n    @Override\n    public EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        WorldServer worldServer = ((CraftWorld) island.getCenter(dimension).getWorld()).getHandle();\n\n        EnderDragonBattle worldEnderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t();\n\n        if (!(worldEnderDragonBattle instanceof EndWorldEnderDragonBattleHandler))\n            return null;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle;\n        IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache());\n\n        return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity();\n    }\n\n    @Override\n    public void startDragonBattle(Island island, Location location) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(worldServer.worldProvider instanceof WorldProviderTheEnd))\n            return;\n\n        EnderDragonBattle enderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t();\n\n        if (!(enderDragonBattle instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle;\n        dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location));\n    }\n\n    @Override\n    public void removeDragonBattle(Island island, Dimension dimension) {\n        World bukkitWorld = island.getCenter(dimension).getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(worldServer.worldProvider instanceof WorldProviderTheEnd))\n            return;\n\n        EnderDragonBattle worldEnderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t();\n\n        if (!(worldEnderDragonBattle instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle;\n        IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache());\n        if (enderDragonBattle != null) {\n            enderDragonBattle.removeBattlePlayers();\n            enderDragonBattle.getEnderDragon().die();\n        }\n    }\n\n    @Override\n    public void awardTheEndAchievement(Player player) {\n        Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft(\"end/root\"));\n        if (advancement != null)\n            player.getAdvancementProgress(advancement).awardCriteria(\"\");\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.nms.NMSEntities;\nimport net.minecraft.server.v1_12_R1.Entity;\nimport net.minecraft.server.v1_12_R1.EntityMinecartFurnace;\nimport net.minecraft.server.v1_12_R1.Items;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftAnimals;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.inventory.EntityEquipment;\nimport org.bukkit.inventory.ItemStack;\n\npublic class NMSEntitiesImpl implements NMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, \"al\");\n    private static final ReflectField<Integer> MINECART_FURNACE_FUEL = new ReflectField<>(\n            EntityMinecartFurnace.class, int.class, \"d\");\n\n    @Override\n    public ItemStack[] getEquipment(EntityEquipment entityEquipment) {\n        ItemStack[] itemStacks = new ItemStack[7];\n\n        itemStacks[0] = new ItemStack(Material.ARMOR_STAND);\n        itemStacks[1] = entityEquipment.getItemInMainHand();\n        itemStacks[2] = entityEquipment.getItemInOffHand();\n        itemStacks[3] = entityEquipment.getHelmet();\n        itemStacks[4] = entityEquipment.getChestplate();\n        itemStacks[5] = entityEquipment.getLeggings();\n        itemStacks[6] = entityEquipment.getBoots();\n\n        return itemStacks;\n    }\n\n    @Override\n    public boolean isAnimalFood(ItemStack itemStack, Animals animals) {\n        return ((CraftAnimals) animals).getHandle().e(CraftItemStack.asNMSCopy(itemStack));\n    }\n\n    @Override\n    public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) {\n        EntityMinecartFurnace minecartFurnace = (EntityMinecartFurnace) ((CraftMinecartFurnace) minecart).getHandle();\n        return MINECART_FURNACE_FUEL.get(minecartFurnace) + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL;\n    }\n\n    @Override\n    public int getPortalTicks(org.bukkit.entity.Entity entity) {\n        return PORTAL_TICKS.get(((CraftEntity) entity).getHandle());\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSHologramsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.nms.NMSHolograms;\nimport net.minecraft.server.v1_12_R1.AxisAlignedBB;\nimport net.minecraft.server.v1_12_R1.DamageSource;\nimport net.minecraft.server.v1_12_R1.EntityArmorStand;\nimport net.minecraft.server.v1_12_R1.EntityHuman;\nimport net.minecraft.server.v1_12_R1.EnumHand;\nimport net.minecraft.server.v1_12_R1.EnumInteractionResult;\nimport net.minecraft.server.v1_12_R1.EnumItemSlot;\nimport net.minecraft.server.v1_12_R1.ItemStack;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.SoundEffect;\nimport net.minecraft.server.v1_12_R1.Vec3D;\nimport net.minecraft.server.v1_12_R1.World;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftArmorStand;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\n\n@SuppressWarnings(\"unused\")\npublic class NMSHologramsImpl implements NMSHolograms {\n\n    @Override\n    public Hologram createHologram(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ());\n        world.addEntity(entityHologram);\n        return entityHologram;\n    }\n\n    @Override\n    public boolean isHologram(Entity entity) {\n        return ((CraftEntity) entity).getHandle() instanceof Hologram;\n    }\n\n    public static class EntityHologram extends EntityArmorStand implements Hologram {\n\n        EntityHologram(World world, double x, double y, double z) {\n            super(world, x, y, z);\n            setInvisible(true);\n            setSmall(true);\n            setArms(false);\n            setNoGravity(true);\n            setBasePlate(true);\n            setMarker(true);\n            super.collides = false;\n            super.setCustomNameVisible(true);\n            super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));\n        }\n\n        @Override\n        public void setHologramName(String name) {\n            super.setCustomName(name);\n        }\n\n        @Override\n        public void removeHologram() {\n            super.die();\n        }\n\n        @Override\n        public ArmorStand getHandle() {\n            return this.getBukkitEntity();\n        }\n\n        @Override\n        public void inactiveTick() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        @Override\n        public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) {\n            // Prevent stand being equipped\n        }\n\n        @Override\n        public boolean c(int i, ItemStack item) {\n            // Prevent stand being equipped\n            return false;\n        }\n\n        @Override\n        public void b(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n        }\n\n        @Override\n        public void a(NBTTagCompound nbttagcompound) {\n            // Do not load NBT.\n        }\n\n        @Override\n        public boolean isCollidable() {\n            return false;\n        }\n\n        @Override\n        public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) {\n            // Prevent stand being equipped\n            return EnumInteractionResult.PASS;\n        }\n\n        @Override\n        public void B_() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        public void forceSetBoundingBox(AxisAlignedBB boundingBox) {\n            super.a(boundingBox);\n        }\n\n        @Override\n        public CraftArmorStand getBukkitEntity() {\n            if (super.bukkitEntity == null) {\n                super.bukkitEntity = new CraftArmorStand(super.world.getServer(), this);\n            }\n            return (CraftArmorStand) super.bukkitEntity;\n        }\n\n        @Override\n        public void die() {\n            // Prevent being killed.\n        }\n\n        @Override\n        public void a(SoundEffect soundeffect, float f, float f1) {\n            // Remove sounds.\n        }\n\n        @Override\n        public boolean c(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public boolean d(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public NBTTagCompound save(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return nbttagcompound;\n        }\n\n        @Override\n        public void f(NBTTagCompound nbttagcompound) {\n            // Do not load NBT.\n        }\n\n        @Override\n        public boolean isInvulnerable(DamageSource source) {\n            /*\n             * The field Entity.invulnerable is private.\n             * It's only used while saving NBTTags, but since the entity would be killed\n             * on chunk unload, we prefer to override isInvulnerable().\n             */\n            return true;\n        }\n\n        @Override\n        public void setCustomName(String customName) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void setCustomNameVisible(boolean visible) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void a(AxisAlignedBB boundingBox) {\n            // Do not change it!\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.NMSPlayers;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.player.OfflinePlayerDataImpl;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask;\nimport com.mojang.authlib.properties.Property;\nimport net.md_5.bungee.api.ChatMessageType;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport net.minecraft.server.v1_12_R1.Entity;\nimport net.minecraft.server.v1_12_R1.EntityItem;\nimport net.minecraft.server.v1_12_R1.EntityPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.boss.BarColor;\nimport org.bukkit.boss.BarStyle;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftItem;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class NMSPlayersImpl implements NMSPlayers {\n\n    @Override\n    public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) {\n        return OfflinePlayerDataImpl.create(offlinePlayer);\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        superiorPlayer.runIfOnline(player -> {\n            EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();\n            Optional<Property> optional = entityPlayer.getProfile().getProperties().get(\"textures\").stream().findFirst();\n            optional.ifPresent(property -> setSkinTexture(superiorPlayer, property));\n        });\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) {\n        superiorPlayer.setTextureValue(property.getValue());\n    }\n\n    @Override\n    public void sendActionBar(Player player, String message) {\n        //noinspection deprecation\n        player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));\n    }\n\n    @Override\n    public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) {\n        BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun);\n        bossBar.addPlayer(player);\n        return bossBar;\n    }\n\n    @Override\n    public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) {\n        player.sendTitle(title, subtitle, fadeIn, duration, fadeOut);\n    }\n\n    @Override\n    public boolean wasThrownByPlayer(org.bukkit.entity.Item item, SuperiorPlayer superiorPlayer) {\n        Entity entity = ((CraftItem) item).getHandle();\n        return entity instanceof EntityItem && superiorPlayer.getName().equals(((EntityItem) entity).n());\n    }\n\n    @Nullable\n    @Override\n    public Locale getPlayerLocale(Player player) {\n        try {\n            return PlayerLocales.getLocale(player.getLocale());\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }\n\n    private static class BossBarImpl implements BossBar {\n\n        private final org.bukkit.boss.BossBar bossBar;\n        private final BossBarTask bossBarTask;\n\n        public BossBarImpl(String message, BarColor color, double ticksToRun) {\n            bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID);\n            this.bossBarTask = BossBarTask.create(this, ticksToRun);\n        }\n\n        @Override\n        public void addPlayer(Player player) {\n            this.bossBar.addPlayer(player);\n            this.bossBarTask.registerTask(player);\n        }\n\n        @Override\n        public void removeAll() {\n            this.bossBar.removeAll();\n            this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask);\n        }\n\n        @Override\n        public void setProgress(double progress) {\n            this.bossBar.setProgress(progress);\n        }\n\n        @Override\n        public double getProgress() {\n            return this.bossBar.getProgress();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.nms.NMSTags;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport net.minecraft.server.v1_12_R1.ChunkRegionLoader;\nimport net.minecraft.server.v1_12_R1.ItemStack;\nimport net.minecraft.server.v1_12_R1.MinecraftKey;\nimport net.minecraft.server.v1_12_R1.NBTBase;\nimport net.minecraft.server.v1_12_R1.NBTTagByte;\nimport net.minecraft.server.v1_12_R1.NBTTagByteArray;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.NBTTagDouble;\nimport net.minecraft.server.v1_12_R1.NBTTagFloat;\nimport net.minecraft.server.v1_12_R1.NBTTagInt;\nimport net.minecraft.server.v1_12_R1.NBTTagIntArray;\nimport net.minecraft.server.v1_12_R1.NBTTagList;\nimport net.minecraft.server.v1_12_R1.NBTTagLong;\nimport net.minecraft.server.v1_12_R1.NBTTagShort;\nimport net.minecraft.server.v1_12_R1.NBTTagString;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\n\nimport java.util.Set;\n\n@SuppressWarnings({\"unused\"})\npublic class NMSTagsImpl implements NMSTags {\n\n    @Override\n    public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound());\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) {\n        if (compoundTag.containsKey(\"NBT\")) {\n            // Old compound version, deserialize it accordingly\n            return deserializeItemOld(compoundTag);\n        }\n\n        NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT();\n        ItemStack itemStack = new ItemStack(tagCompound);\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) {\n        String typeName = Materials.patchOldMaterialName(compoundTag.getString(\"type\").orElse(null));\n        Material type = Material.valueOf(typeName);\n        int amount = compoundTag.getInt(\"amount\").orElse(0);\n        short data = (short) compoundTag.getShort(\"data\").orElse(0);\n        CompoundTag nbtData = compoundTag.getCompound(\"NBT\").orElse(null);\n\n        org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data);\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n        if (nbtData != null)\n            itemStack.setTag((NBTTagCompound) nbtData.toNBT());\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    @Override\n    public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) {\n        CraftWorld craftWorld = (CraftWorld) location.getWorld();\n        NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT();\n\n        if (nbtTagCompound == null)\n            nbtTagCompound = new NBTTagCompound();\n\n        if (!nbtTagCompound.hasKey(\"id\"))\n            //noinspection deprecation\n            nbtTagCompound.setString(\"id\", new MinecraftKey(entityType.getName()).getKey());\n\n        ChunkRegionLoader.spawnEntity(nbtTagCompound, craftWorld.getHandle(),\n                location.getX(), location.getY(), location.getZ(), true, CreatureSpawnEvent.SpawnReason.CUSTOM);\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((NBTTagByteArray) object).c();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NBTTagByte) object).g();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((NBTTagCompound) object).c();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NBTTagDouble) object).asDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NBTTagFloat) object).i();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((NBTTagIntArray) object).d();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NBTTagInt) object).e();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((NBTTagList) object).i(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NBTTagLong) object).d();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NBTTagShort) object).f();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((NBTTagString) object).c_();\n    }\n\n    @Override\n    public Object parseList(ListTag listTag) {\n        NBTTagList nbtTagList = new NBTTagList();\n\n        for (Tag<?> tag : listTag)\n            nbtTagList.add((NBTBase) tag.toNBT());\n\n        return nbtTagList;\n    }\n\n    @Override\n    public Object getNBTCompoundTag(Object object, String key) {\n        return ((NBTTagCompound) object).get(key);\n    }\n\n    @Override\n    public void setNBTCompoundTagValue(Object object, String key, Object value) {\n        ((NBTTagCompound) object).set(key, (NBTBase) value);\n    }\n\n    @Override\n    public int getNBTTagListSize(Object object) {\n        return ((NBTTagList) object).size();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.google.common.collect.Maps;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Chunk;\nimport net.minecraft.server.v1_12_R1.ChunkProviderServer;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.EntityHuman;\nimport net.minecraft.server.v1_12_R1.EntityPlayer;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.IChunkLoader;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.Packet;\nimport net.minecraft.server.v1_12_R1.PlayerChunkMap;\nimport net.minecraft.server.v1_12_R1.TileEntity;\nimport net.minecraft.server.v1_12_R1.World;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic class NMSUtils {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ReflectField<IChunkLoader> CHUNK_LOADER = new ReflectField<>(\n            ChunkProviderServer.class, IChunkLoader.class, \"chunkLoader\");\n    private static final ReflectMethod<Void> SAVE_CHUNK = new ReflectMethod<>(\n            IChunkLoader.class, \"a\", World.class, Chunk.class);\n    private static final ReflectMethod<Void> TILE_ENTITY_LOAD = new ReflectMethod<>(\n            TileEntity.class, \"a\", NBTTagCompound.class);\n\n    private static final Map<UUID, IChunkLoader> chunkLoadersMap = Maps.newConcurrentMap();\n\n    private static final List<CompletableFuture<Void>> PENDING_CHUNK_ACTIONS = new LinkedList<>();\n\n    public static final ObjectsPool<ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition>> BLOCK_POS_POOL =\n            ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0));\n\n    private NMSUtils() {\n\n    }\n\n    @Nullable\n    public static <T extends TileEntity> T getTileEntityAt(Location location, Class<T> type) {\n        org.bukkit.World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return null;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            TileEntity tileEntity = worldServer.getTileEntity(blockPosition);\n            return !type.isInstance(tileEntity) ? null : type.cast(tileEntity);\n        }\n    }\n\n    public static void runActionOnEntityChunks(Collection<ChunkPosition> chunksCoords,\n                                               ChunkCallback chunkCallback) {\n        runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks ->\n                runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback));\n    }\n\n    public static void runActionOnChunks(Collection<ChunkPosition> chunksCoords,\n                                         boolean saveChunks, ChunkCallback chunkCallback) {\n        runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks ->\n                runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback));\n    }\n\n    private static void runActionOnChunksInternal(Collection<ChunkPosition> chunksCoords,\n                                                  ChunkCallback chunkCallback,\n                                                  Consumer<List<ChunkPosition>> onUnloadChunkAction) {\n        List<ChunkPosition> unloadedChunks = new LinkedList<>();\n        List<Chunk> loadedChunks = new LinkedList<>();\n\n        chunksCoords.forEach(chunkPosition -> {\n            WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n            Chunk chunk = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n\n            if (chunk != null) {\n                loadedChunks.add(chunk);\n            } else {\n                unloadedChunks.add(chunkPosition.copy());\n            }\n        });\n\n        boolean hasUnloadedChunks = !unloadedChunks.isEmpty();\n\n        loadedChunks.forEach(loadedChunk -> {\n            chunkCallback.onChunk(loadedChunk, true);\n            chunkCallback.onUpdateChunk(loadedChunk);\n        });\n\n        if (hasUnloadedChunks) {\n            onUnloadChunkAction.accept(unloadedChunks);\n        } else {\n            chunkCallback.onFinish();\n        }\n    }\n\n    public static void runActionOnUnloadedChunks(Collection<ChunkPosition> chunks,\n                                                 boolean saveChunks, ChunkCallback chunkCallback) {\n        CompletableFuture<Void> pendingTask = new CompletableFuture<>();\n        PENDING_CHUNK_ACTIONS.add(pendingTask);\n\n        BukkitExecutor.createTask().runAsync(v -> {\n            chunks.forEach(chunkPosition -> {\n                WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                IChunkLoader chunkLoader = chunkLoadersMap.computeIfAbsent(worldServer.getDataManager().getUUID(),\n                        uuid -> CHUNK_LOADER.get(worldServer.getChunkProvider()));\n\n                if (!chunkLoader.chunkExists(chunkPosition.getX(), chunkPosition.getZ()))\n                    return;\n\n                try {\n                    Chunk loadedChunk = chunkLoader.a(worldServer, chunkPosition.getX(), chunkPosition.getZ());\n\n                    if (loadedChunk != null) {\n                        chunkCallback.onChunk(loadedChunk, false);\n\n                        if (saveChunks) {\n                            if (SAVE_CHUNK.isValid())\n                                SAVE_CHUNK.invoke(chunkLoader, worldServer, loadedChunk);\n                            else {\n                                chunkLoader.saveChunk(worldServer, loadedChunk, false);\n                            }\n                        }\n                    }\n                } catch (Exception error) {\n                    Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                }\n            });\n        }).runSync(v -> {\n            chunkCallback.onFinish();\n\n            pendingTask.complete(null);\n            PENDING_CHUNK_ACTIONS.remove(pendingTask);\n        });\n    }\n\n    private static void runActionOnUnloadedEntityChunks(Collection<ChunkPosition> chunks,\n                                                        ChunkCallback chunkCallback) {\n\n    }\n\n    public static List<CompletableFuture<Void>> getPendingChunkActions() {\n        return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS);\n    }\n\n    public static void sendPacketToRelevantPlayers(WorldServer worldServer, int chunkX, int chunkZ, Packet<?> packet) {\n        PlayerChunkMap playerChunkMap = worldServer.getPlayerChunkMap();\n        for (EntityHuman entityHuman : worldServer.players) {\n            if (entityHuman instanceof EntityPlayer && playerChunkMap.a((EntityPlayer) entityHuman, chunkX, chunkZ))\n                ((EntityPlayer) entityHuman).playerConnection.sendPacket(packet);\n        }\n    }\n\n    public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag tileEntity) {\n        if (!isValidPosition(chunk.world, blockPosition))\n            return;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) {\n            chunk.world.setTypeAndData(blockPosition, blockData, 3);\n            return;\n        }\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        int highestBlockLight = chunk.b(blockX, blockZ);\n        boolean initLight = false;\n\n        int indexY = blockY >> 4;\n\n        ChunkSection chunkSection = chunk.getSections()[indexY];\n\n        if (chunkSection == null) {\n            chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, chunk.world.worldProvider.m());\n            initLight = blockY > highestBlockLight;\n        }\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData);\n\n        chunk.markDirty();\n\n        if (initLight)\n            chunk.initLighting();\n\n        if (tileEntity != null) {\n            NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT();\n            if (tileEntityCompound != null) {\n                tileEntityCompound.setInt(\"x\", blockPosition.getX());\n                tileEntityCompound.setInt(\"y\", blockPosition.getY());\n                tileEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition);\n                if (worldTileEntity != null) {\n                    if (TILE_ENTITY_LOAD.isValid())\n                        TILE_ENTITY_LOAD.invoke(worldTileEntity, tileEntityCompound);\n                    else\n                        worldTileEntity.load(tileEntityCompound);\n                }\n            }\n        }\n    }\n\n    private static boolean isValidPosition(World world, BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight();\n    }\n\n    public interface ChunkCallback {\n\n        void onChunk(Chunk chunk, boolean isLoaded);\n\n        void onUpdateChunk(Chunk chunk);\n\n        void onFinish();\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.signs.IslandSigns;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.NMSWorld;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.generator.IslandsGeneratorImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.spawners.MobSpawnerAbstractNotifier;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.ChunkReaderImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.WorldEditSessionImpl;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockDoubleStep;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.EnumParticle;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.IChatBaseComponent;\nimport net.minecraft.server.v1_12_R1.MobSpawnerAbstract;\nimport net.minecraft.server.v1_12_R1.PacketPlayOutBlockChange;\nimport net.minecraft.server.v1_12_R1.PacketPlayOutWorldBorder;\nimport net.minecraft.server.v1_12_R1.SoundCategory;\nimport net.minecraft.server.v1_12_R1.SoundEffectType;\nimport net.minecraft.server.v1_12_R1.SoundEffects;\nimport net.minecraft.server.v1_12_R1.TileEntityMobSpawner;\nimport net.minecraft.server.v1_12_R1.TileEntitySign;\nimport net.minecraft.server.v1_12_R1.WorldBorder;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.block.CraftSign;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.material.MaterialData;\n\nimport java.lang.reflect.Modifier;\nimport java.util.function.IntFunction;\n\npublic class NMSWorldImpl implements NMSWorld {\n\n    private static final ReflectField<MobSpawnerAbstract> MOB_SPAWNER_ABSTRACT = new ReflectField<MobSpawnerAbstract>(\n            TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    private static boolean alreadyWarned = false;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return getBlockKeyInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return ConstantKeys.AIR;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        int blockId = chunkSnapshot.getBlockTypeId(x, y, z);\n        int blockData = chunkSnapshot.getBlockData(x, y, z);\n        int combinedId = blockId + (blockData << 12);\n\n        Location location = new Location(\n                Bukkit.getWorld(chunkSnapshot.getWorldName()),\n                (chunkSnapshot.getX() << 4) + x,\n                y,\n                (chunkSnapshot.getZ() << 4) + z\n        );\n\n        return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location);\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return canPlayerSuffocateInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return true;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        int blockId = chunkSnapshot.getBlockTypeId(x, y, z);\n        int blockData = chunkSnapshot.getBlockData(x, y, z);\n        int combinedId = blockId + (blockData << 12);\n        return Block.getByCombinedId(combinedId).r();\n    }\n\n    @Override\n    public void listenSpawner(Location location, IntFunction<Integer> delayChangeCallback) {\n        TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class);\n        if (mobSpawner == null)\n            return;\n\n        MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner();\n        if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier)\n            return;\n\n        MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback);\n        MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier);\n        mobSpawnerAbstractNotifier.updateDelay();\n    }\n\n    @Override\n    public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) {\n        if (!plugin.getSettings().isWorldBorders())\n            return;\n\n        Player player = superiorPlayer.asPlayer();\n        World world = superiorPlayer.getWorld();\n\n        if (world == null || player == null)\n            return;\n\n        int islandSize = island == null ? 0 : island.getIslandSize();\n\n        boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0;\n\n        WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle();\n\n        WorldBorder worldBorder;\n\n        if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) {\n            worldBorder = worldServer.getWorldBorder();\n        } else {\n            Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n            if (dimension == null)\n                return;\n\n            Location center = island.getCenter(dimension);\n\n            worldBorder = new WorldBorder();\n            worldBorder.world = worldServer;\n            worldBorder.setWarningDistance(0);\n            worldBorder.setCenter(center.getX(), center.getZ());\n\n            switch (superiorPlayer.getBorderColor()) {\n                case BLUE: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    break;\n                }\n                case GREEN: {\n                    worldBorder.setSize((islandSize * 2) + 1.001D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE);\n                    break;\n                }\n                case RED: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE);\n                    break;\n                }\n            }\n        }\n\n        PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder, PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE);\n        ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder);\n    }\n\n    @Override\n    public Object getBlockData(org.bukkit.block.Block block) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId) {\n        WorldServer world = ((CraftWorld) location.getWorld()).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n            NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null);\n            NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4,\n                    new PacketPlayOutBlockChange(world, blockPosition));\n        }\n    }\n\n    @Override\n    public ICachedBlock cacheBlock(org.bukkit.block.Block block) {\n        return NMSCachedBlock.obtain(block);\n    }\n\n    @Override\n    public boolean isWaterLogged(org.bukkit.block.Block block) {\n        Material blockType = block.getType();\n        return blockType == Material.WATER || blockType == Material.STATIONARY_WATER;\n    }\n\n    @Override\n    public SignType getSignType(org.bukkit.block.Block block) {\n        Material blockType = block.getType();\n        return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN :\n                blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN;\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        throw new UnsupportedOperationException(\"Not supported\");\n    }\n\n    @Override\n    public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) {\n        WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();\n        BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ());\n        IBlockData blockData = worldServer.getType(blockPosition);\n        return PistonPushReaction.values()[blockData.o().ordinal()];\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.Block block) {\n        WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();\n        IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ()));\n        return getDefaultAmount(blockData);\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) {\n        MaterialData materialData = bukkitBlockState.getData();\n        // noinspection deprecation\n        int combinedId = materialData.getItemType().getId() + (materialData.getData() << 12);\n        return getDefaultAmount(Block.getByCombinedId(combinedId));\n    }\n\n    private int getDefaultAmount(IBlockData blockData) {\n        Block nmsBlock = blockData.getBlock();\n\n        // Checks for double slabs\n        if (nmsBlock instanceof BlockDoubleStep) {\n            return 2;\n        }\n\n        return 1;\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) {\n        WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());\n            return worldServer.getType(blockPosition).r();\n        }\n    }\n\n    @Override\n    public void placeSign(Island island, Location location) {\n        TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class);\n        if (tileEntitySign == null)\n            return;\n\n        String[] lines = new String[4];\n        System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length);\n        String[] strippedLines = new String[4];\n        for (int i = 0; i < 4; i++)\n            strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]);\n\n        IChatBaseComponent[] newLines;\n\n        IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false);\n        if (result.isCancelEvent()) {\n            newLines = CraftSign.sanitizeLines(strippedLines);\n        } else {\n            newLines = CraftSign.sanitizeLines(lines);\n        }\n\n        System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4);\n    }\n\n    @Override\n    public void playGeneratorSound(Location location) {\n        WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n\n            double x = location.getX();\n            double y = location.getY();\n            double z = location.getZ();\n\n            blockPosition.c(x, y, z);\n\n            worldServer.a(null, blockPosition, SoundEffects.dE, SoundCategory.BLOCKS, 0.5F,\n                    2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F);\n\n            for (int i = 0; i < 8; i++) {\n                worldServer.addParticle(EnumParticle.SMOKE_LARGE,\n                        x + Math.random(), y + 1.2D, z + Math.random(),\n                        0.0D, 0.0D, 0.0D);\n            }\n        }\n    }\n\n    @Override\n    public void playBreakAnimation(org.bukkit.block.Block block) {\n        WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(block.getX(), block.getY(), block.getZ());\n            worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition)));\n        }\n    }\n\n    @Override\n    public void playPlaceSound(Location location) {\n        WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            SoundEffectType soundEffectType = worldServer.getType(blockPosition).getBlock().getStepSound();\n\n            worldServer.a(null, blockPosition, soundEffectType.e(), SoundCategory.BLOCKS,\n                    (soundEffectType.a() + 1.0F) / 2.0F, soundEffectType.b() * 0.8F);\n        }\n    }\n\n    @Override\n    public int getMinHeight(World world) {\n        return 0;\n    }\n\n    @Override\n    public void removeAntiXray(World world) {\n        // Doesn't exist in this version.\n    }\n\n    @Override\n    public void setOceanLevel(World world) {\n        ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight());\n    }\n\n    @Override\n    public IslandsGenerator createGenerator(Dimension dimension) {\n        return new IslandsGeneratorImpl(dimension);\n    }\n\n    @Override\n    public WorldEditSession createEditSession(World world) {\n        return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle());\n    }\n\n    @Override\n    public WorldEditSession createPartialEditSession(Dimension dimension) {\n        return WorldEditSessionImpl.obtain(dimension);\n    }\n\n    @Override\n    public ChunkReader createChunkReader(Chunk chunk) {\n        return new ChunkReaderImpl(chunk);\n    }\n\n    @Override\n    public void listenBlockStateChanges(org.bukkit.World world) {\n        if (!alreadyWarned) {\n            Log.warn(\"This version is old and you may experience issues with block changes detection\");\n            alreadyWarned = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Chunk;\nimport net.minecraft.server.v1_12_R1.ChunkCoordIntPair;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.ITickable;\nimport net.minecraft.server.v1_12_R1.TileEntity;\nimport org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.function.Consumer;\n\npublic class CropsTickingTileEntity extends TileEntity implements ITickable {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static Set<Block> CROPS_TO_GROW_CACHE;\n\n    static {\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate);\n    }\n\n    private static final Chunk2ObjectMap<CropsTickingTileEntity> tickingChunks = new Chunk2ObjectMap<>();\n    private static int random = ThreadLocalRandom.current().nextInt();\n\n    private final WeakReference<Island> island;\n    private final WeakReference<Chunk> chunk;\n    private final int chunkX;\n    private final int chunkZ;\n\n    private int currentTick = 0;\n\n    private double cachedCropGrowthMultiplier;\n\n    public static void register() {\n        // Calls the static initializer which registers the callback.\n    }\n\n    public static void create(Island island, String worldName, Chunk chunk) {\n        long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ);\n        tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk));\n    }\n\n    public static CropsTickingTileEntity remove(String worldName, long chunkCoords) {\n        return tickingChunks.remove(worldName, chunkCoords);\n    }\n\n    public static void forEachChunk(List<ChunkPosition> chunkPositions, Consumer<CropsTickingTileEntity> cropsTickingTileEntityConsumer) {\n        if (tickingChunks.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> {\n            long chunkKey = chunkPosition.asPair();\n            CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey);\n            if (cropsTickingTileEntity != null)\n                cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity);\n        });\n    }\n\n    private CropsTickingTileEntity(Island island, Chunk chunk) {\n        this.island = new WeakReference<>(island);\n        this.chunk = new WeakReference<>(chunk);\n        this.chunkX = chunk.locX;\n        this.chunkZ = chunk.locZ;\n        a(chunk.getWorld());\n        setPosition(new BlockPosition(chunkX << 4, 1, chunkZ << 4));\n        world.tileEntityListTick.add(this);\n        this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1;\n    }\n\n    @Override\n    public void e() {\n        if (++currentTick <= plugin.getSettings().getCropsInterval())\n            return;\n\n        Chunk chunk = this.chunk.get();\n        Island island = this.island.get();\n\n        if (chunk == null || island == null) {\n            world.tileEntityListTick.remove(this);\n            return;\n        }\n\n        currentTick = 0;\n\n        int worldRandomTick = world.getGameRules().c(\"randomTickSpeed\");\n\n        int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval());\n\n        if (chunkRandomTickSpeed > 0) {\n            for (ChunkSection chunkSection : chunk.getSections()) {\n                if (chunkSection != Chunk.a && chunkSection.shouldTick()) {\n                    for (int i = 0; i < chunkRandomTickSpeed; i++) {\n                        random = random * 3 + 1013904223;\n                        int factor = random >> 2;\n                        int x = factor & 15;\n                        int z = factor >> 8 & 15;\n                        int y = factor >> 16 & 15;\n                        IBlockData blockData = chunkSection.getType(x, y, z);\n                        Block block = blockData.getBlock();\n                        if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) {\n                            block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)),\n                                    blockData, ThreadLocalRandom.current());\n                        }\n                    }\n                }\n            }\n        }\n\n    }\n\n    public void setCropGrowthMultiplier(double cropGrowthMultiplier) {\n        this.cachedCropGrowthMultiplier = cropGrowthMultiplier;\n    }\n\n    private static void onSettingsUpdate() {\n        CROPS_TO_GROW_CACHE = new HashSet<>();\n        plugin.getSettings().getCropsToGrow().forEach(cropName -> {\n            Key key = Keys.ofMaterialAndData(cropName);\n            if (key instanceof MaterialKey) {\n                Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial());\n                if (block != null && block.isTicking())\n                    CROPS_TO_GROW_CACHE.add(block);\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/EmptyCounterChunkSection.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.Blocks;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.DataPaletteBlock;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.NibbleArray;\n\npublic class EmptyCounterChunkSection extends ChunkSection {\n\n    private static final ReflectField<Integer> NON_EMPTY_BLOCK_COUNT = new ReflectField<>(ChunkSection.class, int.class, \"nonEmptyBlockCount\");\n    private static final ReflectField<Integer> TICKING_BLOCK_COUNT = new ReflectField<>(ChunkSection.class, int.class, \"tickingBlockCount\");\n    private static final ReflectField<DataPaletteBlock> BLOCK_IDS = new ReflectField<DataPaletteBlock>(\n            ChunkSection.class, DataPaletteBlock.class, \"blockIds\").removeFinal();\n    private static final ReflectField<NibbleArray> EMITTED_LIGHT = new ReflectField<>(ChunkSection.class, NibbleArray.class, \"emittedLight\");\n    private static final ReflectField<NibbleArray> SKY_LIGHT = new ReflectField<>(ChunkSection.class, NibbleArray.class, \"skyLight\");\n\n    private int nonEmptyBlockCount;\n    private int tickingBlockCount;\n\n    private EmptyCounterChunkSection(ChunkSection chunkSection) {\n        super(chunkSection.getYPosition(), chunkSection.getSkyLightArray() != null);\n\n        nonEmptyBlockCount = NON_EMPTY_BLOCK_COUNT.get(chunkSection, 0);\n        tickingBlockCount = TICKING_BLOCK_COUNT.get(chunkSection, 0);\n        BLOCK_IDS.set(this, chunkSection.getBlocks());\n        EMITTED_LIGHT.set(this, chunkSection.getEmittedLightArray());\n        SKY_LIGHT.set(this, chunkSection.getSkyLightArray());\n    }\n\n    public static EmptyCounterChunkSection of(ChunkSection chunkSection) {\n        return chunkSection == null ? null : new EmptyCounterChunkSection(chunkSection);\n    }\n\n    @Override\n    public void setType(int i, int j, int k, IBlockData iblockdata) {\n        Block currentBlock = getType(i, j, k).getBlock();\n        Block placedBlock = iblockdata.getBlock();\n\n        if (currentBlock != Blocks.AIR) {\n            nonEmptyBlockCount--;\n            if (currentBlock.isTicking()) {\n                tickingBlockCount--;\n            }\n        }\n\n        if (placedBlock != Blocks.AIR) {\n            nonEmptyBlockCount++;\n            if (placedBlock.isTicking()) {\n                tickingBlockCount++;\n            }\n        }\n\n        super.setType(i, j, k, iblockdata);\n    }\n\n    @Override\n    public boolean a() {\n        return this.isEmpty();\n    }\n\n    public boolean isEmpty() {\n        return nonEmptyBlockCount == 0;\n    }\n\n    @Override\n    public boolean shouldTick() {\n        return tickingBlockCount > 0;\n    }\n\n    public void recalcBlockCounts() {\n        nonEmptyBlockCount = 0;\n        tickingBlockCount = 0;\n\n        for (int i = 0; i < 16; ++i) {\n            for (int j = 0; j < 16; ++j) {\n                for (int k = 0; k < 16; ++k) {\n                    Block block = getType(i, j, k).getBlock();\n                    if (block != Blocks.AIR) {\n                        nonEmptyBlockCount++;\n                        if (block.isTicking()) {\n                            tickingBlockCount++;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/DragonUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.WorldGenEndTrophy;\n\nimport java.lang.reflect.Modifier;\n\npublic class DragonUtils {\n\n    private static final ReflectField<BlockPosition> END_PODIUM_LOCATION = new ReflectField<BlockPosition>(\n            WorldGenEndTrophy.class, BlockPosition.class,\n            Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static BlockPosition currentPodiumPosition = BlockPosition.ZERO;\n\n    private DragonUtils() {\n\n    }\n\n    public static void runWithPodiumPosition(BlockPosition podiumPosition, Runnable runnable) {\n        try {\n            END_PODIUM_LOCATION.set(null, podiumPosition);\n            currentPodiumPosition = podiumPosition;\n            runnable.run();\n        } finally {\n            END_PODIUM_LOCATION.set(null, BlockPosition.ZERO);\n            currentPodiumPosition = BlockPosition.ZERO;\n        }\n    }\n\n    public static BlockPosition getCurrentPodiumPosition() {\n        return currentPodiumPosition;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys;\nimport net.minecraft.server.v1_12_R1.EnderDragonBattle;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.WorldServer;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class EndWorldEnderDragonBattleHandler extends EnderDragonBattle {\n\n    private static final IslandCacheKey<IslandEnderDragonBattle> CACHE_KEY = IslandCacheKeys.register(\"DRAGON_BATTLE\", IslandEnderDragonBattle.class);\n\n    private final List<IslandEnderDragonBattle> worldDragonBattlesList = new LinkedList<>();\n\n    public EndWorldEnderDragonBattleHandler(WorldServer worldServer) {\n        super(worldServer, new NBTTagCompound());\n    }\n\n    @Override\n    public void b() {\n        this.worldDragonBattlesList.forEach(EnderDragonBattle::b);\n    }\n\n    public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) {\n        IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle);\n        if (oldBattle != null)\n            this.worldDragonBattlesList.remove(oldBattle);\n        this.worldDragonBattlesList.add(enderDragonBattle);\n    }\n\n    @Nullable\n    public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) {\n        return islandCache.get(CACHE_KEY);\n    }\n\n    @Nullable\n    public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) {\n        IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY);\n        if (enderDragonBattle != null)\n            this.worldDragonBattlesList.remove(enderDragonBattle);\n        return enderDragonBattle;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.google.common.collect.Sets;\nimport net.minecraft.server.v1_12_R1.AxisAlignedBB;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Blocks;\nimport net.minecraft.server.v1_12_R1.BossBattleServer;\nimport net.minecraft.server.v1_12_R1.CriterionTriggers;\nimport net.minecraft.server.v1_12_R1.DamageSource;\nimport net.minecraft.server.v1_12_R1.DragonControllerPhase;\nimport net.minecraft.server.v1_12_R1.EnderDragonBattle;\nimport net.minecraft.server.v1_12_R1.Entity;\nimport net.minecraft.server.v1_12_R1.EntityEnderCrystal;\nimport net.minecraft.server.v1_12_R1.EntityEnderDragon;\nimport net.minecraft.server.v1_12_R1.EntityPlayer;\nimport net.minecraft.server.v1_12_R1.EnumDragonRespawn;\nimport net.minecraft.server.v1_12_R1.GameProfileSerializer;\nimport net.minecraft.server.v1_12_R1.IDragonController;\nimport net.minecraft.server.v1_12_R1.MathHelper;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.NBTTagInt;\nimport net.minecraft.server.v1_12_R1.NBTTagList;\nimport net.minecraft.server.v1_12_R1.Vec3D;\nimport net.minecraft.server.v1_12_R1.WorldGenEndGateway;\nimport net.minecraft.server.v1_12_R1.WorldGenEndTrophy;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\n\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class IslandEnderDragonBattle extends EnderDragonBattle {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ReflectField<EnderDragonBattle> DRAGON_BATTLE = new ReflectField<EnderDragonBattle>(\n            EntityEnderDragon.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static final ReflectField<BossBattleServer> BATTLE_BOSS_SERVER = new ReflectField<>(\n            EnderDragonBattle.class, BossBattleServer.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    private static final ReflectField<Boolean> SCAN_FOR_LEGACY_PORTALS = new ReflectField<>(\n            EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 3);\n\n    private static final ReflectField<Boolean> WAS_DRAGON_KILLED = new ReflectField<>(\n            EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 1);\n\n    private static final Vec3D ORIGINAL_END_PODIUM = new Vec3D(0.5, 0, 0.5);\n\n    private final Island island;\n    private final BlockPosition islandBlockPosition;\n    private final WorldServer worldServer;\n    private final IslandEntityEnderDragon entityEnderDragon;\n    private final BossBattleServer bossBattleServer;\n    private final AxisAlignedBB borderArea;\n\n    private final LinkedList<Integer> gateways = new LinkedList<>();\n\n    private UUID dragonUUID;\n    private BlockPosition exitPortalLocation;\n    private EnumDragonRespawn respawnPhase;\n    private List<EntityEnderCrystal> crystalsList;\n    private int currentTick = 0;\n    private int crystalsCountTick = 0;\n    private int respawnTick = 0;\n    private int crystalsCount = 0;\n    private boolean dragonKilled = false;\n    private boolean previouslyKilled = false;\n\n    public IslandEnderDragonBattle(Island island, WorldServer worldServer, Location location) {\n        this(island, worldServer, new BlockPosition(location.getX(), location.getY(), location.getZ()),\n                null);\n    }\n\n    public IslandEnderDragonBattle(Island island, WorldServer worldServer, BlockPosition islandBlockPosition,\n                                   @Nullable IslandEntityEnderDragon islandEntityEnderDragon) {\n        super(worldServer, new NBTTagCompound());\n        SCAN_FOR_LEGACY_PORTALS.set(this, false);\n        WAS_DRAGON_KILLED.set(this, false);\n        this.island = island;\n        this.islandBlockPosition = islandBlockPosition;\n        this.worldServer = worldServer;\n        this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon;\n        this.bossBattleServer = BATTLE_BOSS_SERVER.get(this);\n\n        int radius = plugin.getSettings().getMaxIslandSize();\n        this.borderArea = new AxisAlignedBB(islandBlockPosition.a(-radius, -radius, -radius), islandBlockPosition.a(radius, radius, radius));\n\n        DRAGON_BATTLE.set(this.entityEnderDragon, this);\n    }\n\n    @Override\n    public NBTTagCompound a() {\n        NBTTagCompound nbtTagCompound = new NBTTagCompound();\n\n        if (dragonUUID != null) {\n            nbtTagCompound.a(\"Dragon\", dragonUUID);\n        }\n\n        nbtTagCompound.setBoolean(\"DragonKilled\", this.dragonKilled);\n        nbtTagCompound.setBoolean(\"PreviouslyKilled\", this.previouslyKilled);\n\n        if (exitPortalLocation != null) {\n            nbtTagCompound.set(\"ExitPortalLocation\", GameProfileSerializer.a(exitPortalLocation));\n        }\n\n        NBTTagList nbtTagList = new NBTTagList();\n        for (int gateway : this.gateways)\n            nbtTagList.add(new NBTTagInt(gateway));\n\n        nbtTagCompound.set(\"Gateways\", nbtTagList);\n\n        return nbtTagCompound;\n    }\n\n    @Override\n    public void b() {\n        DragonUtils.runWithPodiumPosition(this.islandBlockPosition, this::doTick);\n\n        IDragonController currentController = this.entityEnderDragon.getDragonControllerManager().a();\n        if (currentController != null && ORIGINAL_END_PODIUM.equals(currentController.g())) {\n            currentController.d();\n        }\n    }\n\n    @Override\n    public void a(EnumDragonRespawn dragonRespawn) {\n        if (respawnPhase == null)\n            throw new IllegalStateException(\"Dragon respawn isn't in progress, can't skip ahead in the animation.\");\n\n        respawnTick = 0;\n\n        if (dragonRespawn != EnumDragonRespawn.END) {\n            respawnPhase = dragonRespawn;\n        } else {\n            respawnPhase = null;\n            dragonKilled = false;\n            EntityEnderDragon entityEnderDragon = spawnEnderDragon();\n            for (EntityPlayer entityPlayer : this.bossBattleServer.getPlayers())\n                CriterionTriggers.m.a(entityPlayer, entityEnderDragon);\n        }\n    }\n\n    @Override\n    public void a(EntityEnderDragon entityEnderDragon) {\n        if (!entityEnderDragon.getUniqueID().equals(dragonUUID))\n            return;\n\n        this.bossBattleServer.setProgress(0.0F);\n        this.bossBattleServer.setVisible(false);\n        this.generateExitPortal(true);\n\n        if (!gateways.isEmpty()) {\n            int i = gateways.removeLast();\n            int j = MathHelper.floor(96.0D * Math.cos(2.0D * (-3.141592653589793D + 0.15707963267948966D * (double) i)));\n            int k = MathHelper.floor(96.0D * Math.sin(2.0D * (-3.141592653589793D + 0.15707963267948966D * (double) i)));\n            BlockPosition blockPosition = new BlockPosition(j, 75, k);\n            this.worldServer.triggerEffect(3000, blockPosition, 0);\n            new WorldGenEndGateway().generate(this.worldServer, new Random(), blockPosition);\n        }\n\n        if (!previouslyKilled) {\n            this.worldServer.setTypeUpdate(this.worldServer.getHighestBlockYAt(islandBlockPosition), Blocks.DRAGON_EGG.getBlockData());\n        }\n\n        previouslyKilled = true;\n        dragonKilled = true;\n    }\n\n    @Override\n    public void b(EntityEnderDragon entityEnderDragon) {\n        if (!entityEnderDragon.getUniqueID().equals(dragonUUID))\n            return;\n\n        this.bossBattleServer.setProgress(entityEnderDragon.getHealth() / entityEnderDragon.getMaxHealth());\n\n        if (entityEnderDragon.hasCustomName())\n            this.bossBattleServer.a(entityEnderDragon.getScoreboardDisplayName());\n    }\n\n    @Override\n    public int c() {\n        return this.crystalsCount;\n    }\n\n    @Override\n    public void a(EntityEnderCrystal entityEnderCrystal, DamageSource damageSource) {\n        if (respawnPhase != null && crystalsList.contains(entityEnderCrystal)) {\n            respawnPhase = null;\n            respawnTick = 0;\n            f();\n            generateExitPortal(true);\n        } else {\n            this.countCrystals();\n            Entity entity = this.worldServer.getEntity(dragonUUID);\n            if (entity instanceof EntityEnderDragon)\n                ((EntityEnderDragon) entity).a(entityEnderCrystal, entityEnderCrystal.getChunkCoordinates(), damageSource);\n        }\n    }\n\n    @Override\n    public boolean d() {\n        return previouslyKilled;\n    }\n\n    @Override\n    public void e() {\n        if (!dragonKilled || respawnPhase != null)\n            return;\n\n        crystalsList = this.worldServer.a(EntityEnderCrystal.class, borderArea);\n\n        respawnPhase = EnumDragonRespawn.START;\n        respawnTick = 0;\n        this.generateExitPortal(false);\n    }\n\n    @Override\n    public void f() {\n        for (EntityEnderCrystal entityEnderCrystal : this.worldServer.a(EntityEnderCrystal.class, borderArea)) {\n            entityEnderCrystal.setInvulnerable(false);\n            entityEnderCrystal.setBeamTarget(null);\n        }\n    }\n\n    public void removeBattlePlayers() {\n        this.bossBattleServer.getPlayers().forEach(this.bossBattleServer::removePlayer);\n    }\n\n    public IslandEntityEnderDragon getEnderDragon() {\n        return this.entityEnderDragon;\n    }\n\n    private IslandEntityEnderDragon spawnEnderDragon() {\n        IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.worldServer, islandBlockPosition);\n        entityEnderDragon.getDragonControllerManager().setControllerPhase(DragonControllerPhase.a);\n        entityEnderDragon.setPositionRotation(islandBlockPosition.getX(), 128,\n                islandBlockPosition.getZ(), this.worldServer.random.nextFloat() * 360.0F, 0.0F);\n\n        this.worldServer.addEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL);\n\n        this.dragonUUID = entityEnderDragon.getUniqueID();\n        //this.f(); // scan for crystals\n\n        return entityEnderDragon;\n    }\n\n    private void doTick() {\n        this.bossBattleServer.setVisible(!dragonKilled);\n\n        // Update battle players\n        if (++currentTick >= 20) {\n            updateBattlePlayers();\n            currentTick = 0;\n        }\n\n        if (this.bossBattleServer.getPlayers().isEmpty()) {\n            return;\n        }\n\n        if (respawnPhase != null) {\n            if (crystalsList == null) {\n                respawnPhase = null;\n                e();\n            }\n\n            if (++crystalsCountTick >= 100) {\n                this.countCrystals();\n                crystalsCountTick = 0;\n            }\n\n            respawnPhase.a(this.worldServer, this, crystalsList, respawnTick++, exitPortalLocation);\n        }\n    }\n\n    private void countCrystals() {\n        this.crystalsCount = this.worldServer.a(EntityEnderCrystal.class, borderArea).size();\n    }\n\n    private void generateExitPortal(boolean flag) {\n        WorldGenEndTrophy worldGenEndTrophy = new WorldGenEndTrophy(flag);\n\n        if (exitPortalLocation == null) {\n            exitPortalLocation = this.worldServer.q(islandBlockPosition).down();\n            while (this.worldServer.getType(exitPortalLocation).getBlock() == Blocks.BEDROCK && exitPortalLocation.getY() > this.worldServer.getSeaLevel())\n                exitPortalLocation = exitPortalLocation.down();\n        }\n\n        worldGenEndTrophy.generate(this.worldServer, new Random(), exitPortalLocation.up(2));\n    }\n\n    private void updateBattlePlayers() {\n        Set<EntityPlayer> nearbyPlayers = Sets.newHashSet();\n\n        WorldInfo worldInfo = WorldInfo.of(this.worldServer.getWorld());\n\n        try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) {\n            strategy.getPlayers(worldInfo).forEach(player -> {\n                EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();\n                this.bossBattleServer.addPlayer(entityPlayer);\n                nearbyPlayers.add(entityPlayer);\n            });\n        }\n\n        new HashSet<>(this.bossBattleServer.getPlayers()).stream()\n                .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer))\n                .forEach(this.bossBattleServer::removePlayer);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.DifficultyDamageScaler;\nimport net.minecraft.server.v1_12_R1.EnderDragonBattle;\nimport net.minecraft.server.v1_12_R1.EntityEnderDragon;\nimport net.minecraft.server.v1_12_R1.GroupDataEntity;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.World;\nimport net.minecraft.server.v1_12_R1.WorldProviderTheEnd;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderDragon;\n\npublic class IslandEntityEnderDragon extends EntityEnderDragon {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Dimension dimension;\n\n    private BlockPosition islandBlockPosition;\n\n    public IslandEntityEnderDragon(World world) {\n        // Used when loading entities to the world.\n        super(world);\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld());\n    }\n\n    public IslandEntityEnderDragon(WorldServer worldServer, BlockPosition islandBlockPosition) {\n        this(worldServer);\n        this.islandBlockPosition = islandBlockPosition;\n    }\n\n    @Nullable\n    @Override\n    public GroupDataEntity prepare(DifficultyDamageScaler difficultydamagescaler,\n                                   @Nullable GroupDataEntity groupdataentity) {\n        if (this.islandBlockPosition == null)\n            finalizeIslandEnderDragon();\n\n        return super.prepare(difficultydamagescaler, groupdataentity);\n    }\n\n    @Override\n    public void a(NBTTagCompound nbtTagCompound) {\n        super.a(nbtTagCompound);\n        finalizeIslandEnderDragon();\n    }\n\n    @Override\n    public void n() {\n        DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::n);\n    }\n\n    @Override\n    public CraftEnderDragon getBukkitEntity() {\n        return (CraftEnderDragon) super.getBukkitEntity();\n    }\n\n    private void finalizeIslandEnderDragon() {\n        if (!(world.worldProvider instanceof WorldProviderTheEnd) || !plugin.getGrid().isIslandsWorld(world.getWorld()))\n            return;\n\n        EnderDragonBattle enderDragonBattle = ((WorldProviderTheEnd) world.worldProvider).t();\n\n        if (!(enderDragonBattle instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null)\n            return;\n\n        Location middleBlock = island.getCenter(dimension);\n\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        if (dimensionConfig instanceof SettingsManager.Worlds.End) {\n            middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock);\n        }\n\n        this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ());\n\n        IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this);\n        dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/generator/IslandsGeneratorImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.generator;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_12_R1.BiomeBase;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock;\nimport org.bukkit.generator.BlockPopulator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\n@SuppressWarnings(\"unused\")\npublic class IslandsGeneratorImpl extends IslandsGenerator {\n\n    private static final ReflectField<BiomeBase[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            new ClassInfo(\"generator.CustomChunkGenerator$CustomBiomeGrid\", ClassInfo.PackageType.CRAFTBUKKIT),\n            BiomeBase[].class, \"biome\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Dimension dimension;\n\n    public IslandsGeneratorImpl(Dimension dimension) {\n        this.dimension = dimension;\n    }\n\n    @Override\n    public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) {\n        ChunkData chunkData = createChunkData(world);\n\n        Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension);\n\n        setBiome(biomeGrid, targetBiome);\n\n        if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            chunkData.setBlock(0, 99, 0, Material.BEDROCK);\n        }\n\n        return chunkData;\n    }\n\n    @Override\n    public List<BlockPopulator> getDefaultPopulators(World world) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Location getFixedSpawnLocation(World world, Random random) {\n        return new Location(world, 0, 100, 0);\n    }\n\n    private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) {\n        BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biome);\n\n        BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeGrid);\n\n        if (biomeBases == null)\n            return;\n\n        Arrays.fill(biomeBases, biomeBase);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.player;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.mojang.authlib.GameProfile;\nimport net.minecraft.server.v1_12_R1.EntityPlayer;\nimport net.minecraft.server.v1_12_R1.MinecraftServer;\nimport net.minecraft.server.v1_12_R1.PlayerInteractManager;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftServer;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.Optional;\n\npublic class OfflinePlayerDataImpl implements OfflinePlayerData {\n\n    private static final ObjectsPool<OfflinePlayerDataImpl> POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new);\n\n    private Player fakePlayer;\n\n    public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) {\n        return POOL.obtain().initialize(offlinePlayer);\n    }\n\n    private OfflinePlayerDataImpl() {\n\n    }\n\n    private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) {\n        GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(),\n                Optional.ofNullable(offlinePlayer.getName()).orElse(\"\"));\n\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        WorldServer worldServer = server.getWorldServer(0);\n        EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));\n        this.fakePlayer = entityPlayer.getBukkitEntity();\n        this.fakePlayer.loadData();\n\n        return this;\n    }\n\n    @Override\n    public Player getFakeOnlinePlayer() {\n        return this.fakePlayer;\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle();\n        entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle();\n        entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    @Override\n    public void applyChanges() {\n        this.fakePlayer.saveData();\n    }\n\n    @Override\n    public void release() {\n        this.fakePlayer = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/spawners/MobSpawnerAbstractNotifier.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.spawners;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.MinecraftKey;\nimport net.minecraft.server.v1_12_R1.MobSpawnerAbstract;\nimport net.minecraft.server.v1_12_R1.MobSpawnerData;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.World;\n\nimport java.util.function.IntFunction;\n\npublic class MobSpawnerAbstractNotifier extends MobSpawnerAbstract {\n\n    private final MobSpawnerAbstract mobSpawnerAbstract;\n    private final IntFunction<Integer> delayChangeCallback;\n\n    public MobSpawnerAbstractNotifier(MobSpawnerAbstract mobSpawnerAbstract, IntFunction<Integer> delayChangeCallback) {\n        this.mobSpawnerAbstract = mobSpawnerAbstract;\n        this.delayChangeCallback = delayChangeCallback;\n\n        // Copy data from original spawner to this\n        NBTTagCompound spawnerCompound = mobSpawnerAbstract.b(new NBTTagCompound());\n        this.a(spawnerCompound);\n    }\n\n    @Nullable\n    @Override\n    public MinecraftKey getMobName() {\n        return mobSpawnerAbstract.getMobName();\n    }\n\n    @Override\n    public void setMobName(@Nullable MinecraftKey minecraftkey) {\n        mobSpawnerAbstract.setMobName(minecraftkey);\n    }\n\n    @Override\n    public void c() {\n        int startDelay = mobSpawnerAbstract.spawnDelay;\n        try {\n            mobSpawnerAbstract.c();\n        } finally {\n            int newDelay = mobSpawnerAbstract.spawnDelay;\n            if (newDelay > startDelay)\n                updateDelay();\n        }\n    }\n\n    @Override\n    public void a(NBTTagCompound nbttagcompound) {\n        mobSpawnerAbstract.a(nbttagcompound);\n    }\n\n    @Override\n    public NBTTagCompound b(NBTTagCompound nbttagcompound) {\n        return mobSpawnerAbstract.b(nbttagcompound);\n    }\n\n    @Override\n    public boolean b(int i) {\n        return mobSpawnerAbstract.b(i);\n    }\n\n    @Override\n    public void a(MobSpawnerData mobspawnerdata) {\n        mobSpawnerAbstract.a(mobspawnerdata);\n    }\n\n    @Override\n    public void a(int i) {\n        mobSpawnerAbstract.a(i);\n    }\n\n    @Override\n    public World a() {\n        return mobSpawnerAbstract.a();\n    }\n\n    @Override\n    public BlockPosition b() {\n        return mobSpawnerAbstract.b();\n    }\n\n    public void updateDelay() {\n        mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world;\n\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.ITileEntity;\nimport net.minecraft.server.v1_12_R1.MinecraftServer;\nimport net.minecraft.server.v1_12_R1.TileEntity;\nimport net.minecraft.server.v1_12_R1.World;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class BlockEntityCache {\n\n    private static final Map<Block, String> BLOCK_TO_ID = new IdentityHashMap<>();\n\n    private BlockEntityCache() {\n\n    }\n\n    public static String getTileEntityId(IBlockData blockData) {\n        return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> {\n            if (block instanceof ITileEntity) {\n                World world = MinecraftServer.getServer().getWorld();\n                TileEntity tileEntity = ((ITileEntity) block).a(world, block.toLegacyData(blockData));\n                if (tileEntity != null)\n                    return tileEntity.getMinecraftKeyString();\n            }\n\n            return \"\";\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Chunk;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.DataPaletteBlock;\nimport net.minecraft.server.v1_12_R1.Entity;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.NBTTagFloat;\nimport net.minecraft.server.v1_12_R1.NibbleArray;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftChunk;\nimport org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.InventoryHolder;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ChunkReaderImpl implements ChunkReader {\n\n    private static final short[] EMPTY_BLOCKS = new short[4096];\n    private static final byte[] EMPTY_DATA = new byte[2048];\n    private static final byte[] EMPTY_LIGHT = new byte[2048];\n\n    private final int x;\n    private final int z;\n\n    private final Map<BlockPosition, CompoundTag> tileEntities = new HashMap<>();\n    private final List<CachedEntity> entities = new LinkedList<>();\n    private final short[][] blockids;\n    private final byte[][] blockdata;\n    private final byte[][] skylight;\n    private final byte[][] emitlight;\n\n    public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n\n        this.x = chunk.locX;\n        this.z = chunk.locZ;\n\n        ChunkSection[] chunkSections = chunk.getSections();\n        this.blockids = new short[chunkSections.length][];\n        this.blockdata = new byte[chunkSections.length][];\n        this.skylight = new byte[chunkSections.length][];\n        this.emitlight = new byte[chunkSections.length][];\n\n        for (int i = 0; i < this.blockids.length; ++i) {\n            ChunkSection chunkSection = chunkSections[i];\n\n            if (chunkSection == null) {\n                this.blockids[i] = EMPTY_BLOCKS;\n                this.blockdata[i] = EMPTY_DATA;\n                this.skylight[i] = EMPTY_LIGHT;\n                this.emitlight[i] = EMPTY_LIGHT;\n            } else {\n                copyBlockIds(chunkSection.getBlocks(), i);\n\n                if (chunkSection.getSkyLightArray() == null) {\n                    skylight[i] = EMPTY_LIGHT;\n                } else {\n                    skylight[i] = new byte[2048];\n                    System.arraycopy(chunkSection.getSkyLightArray().asBytes(), 0, skylight[i], 0, 2048);\n                }\n\n                emitlight[i] = new byte[2048];\n                System.arraycopy(chunkSection.getEmittedLightArray().asBytes(), 0, emitlight[i], 0, 2048);\n            }\n        }\n\n        chunk.getTileEntities().forEach((blockPosition, tileEntity) -> {\n            NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound());\n\n            tileEntityCompound.remove(\"x\");\n            tileEntityCompound.remove(\"y\");\n            tileEntityCompound.remove(\"z\");\n\n            InventoryHolder inventoryHolder = tileEntity.getOwner();\n            if (inventoryHolder != null)\n                tileEntityCompound.setString(\"inventoryType\", inventoryHolder.getInventory().getType().name());\n\n            tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound));\n        });\n\n        for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities())\n            entities.add(new CachedEntity(((CraftEntity) entity).getHandle()));\n    }\n\n    @Override\n    public int getX() {\n        return this.x;\n    }\n\n    @Override\n    public int getZ() {\n        return this.z;\n    }\n\n    @Override\n    public Material getType(int x, int y, int z) {\n        return Material.getMaterial(this.getBlockId(x, y, z));\n    }\n\n    @Override\n    public short getData(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15);\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag getTileEntity(int x, int y, int z) {\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z);\n            return this.tileEntities.get(blockPosition);\n        }\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag readBlockStates(int x, int y, int z) {\n        // Doesn't exist\n        return null;\n    }\n\n    @Override\n    public byte[] getLightLevels(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel};\n    }\n\n    @Override\n    public void forEachEntity(EntityConsumer consumer) {\n        if (entities.isEmpty())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = wrapper.getHandle();\n            for (CachedEntity cachedEntity : entities) {\n                location.setX(cachedEntity.x);\n                location.setY(cachedEntity.y);\n                location.setZ(cachedEntity.z);\n                location.setYaw(cachedEntity.yaw);\n                location.setPitch(cachedEntity.pitch);\n                consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location);\n            }\n        }\n    }\n\n    private int getBlockId(int x, int y, int z) {\n        return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x];\n    }\n\n    private void copyBlockIds(DataPaletteBlock palette, int i) {\n        byte[] rawIds = new byte[4096];\n        NibbleArray data = new NibbleArray();\n        palette.exportData(rawIds, data);\n\n        short[] blockids = this.blockids[i] = new short[4096];\n        this.blockdata[i] = data.asBytes();\n\n        for (int j = 0; j < 4096; ++j) {\n            blockids[j] = (short) (rawIds[j] & 255);\n        }\n    }\n\n    private static class CachedEntity {\n\n        private final double x;\n        private final double y;\n        private final double z;\n        private final float yaw;\n        private final float pitch;\n        private final EntityType entityType;\n        private final CompoundTag entityTag;\n\n        CachedEntity(Entity entity) {\n            this.x = entity.locX;\n            this.y = entity.locY;\n            this.z = entity.locZ;\n            this.yaw = entity.yaw;\n            this.pitch = entity.pitch;\n            this.entityType = entity.getBukkitEntity().getType();\n\n            NBTTagCompound nbtTagCompound = new NBTTagCompound();\n            entity.c(nbtTagCompound);\n            nbtTagCompound.set(\"Yaw\", new NBTTagFloat(entity.yaw));\n            nbtTagCompound.set(\"Pitch\", new NBTTagFloat(entity.pitch));\n\n            this.entityTag = CompoundTag.fromNBT(nbtTagCompound);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class KeyBlocksCache {\n\n    private static final Map<IBlockData, Key> BLOCK_TO_KEY = new IdentityHashMap<>();\n\n    private KeyBlocksCache() {\n\n    }\n\n    public static Key getBlockKey(IBlockData blockData) {\n        return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> {\n            Block block = blockData.getBlock();\n            Material blockType = CraftMagicNumbers.getMaterial(block);\n            if (blockType == null)\n                return null;\n            byte data = (byte) block.toLegacyData(blockData);\n            return Keys.of(blockType, data);\n        });\n    }\n\n    public static void cacheAllBlocks() {\n        Block.REGISTRY_ID.forEach(KeyBlocksCache::getBlockKey);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.ChunkCoordIntPair;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport org.bukkit.Location;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class WorldEditSessionDataImpl implements WorldEditSession.Data {\n\n    private final List<PositionedObject<WorldEditSessionImpl.ChunkData>> chunks = new LinkedList<>();\n    private final List<PositionedObject<IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<PositionedObject<CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<PositionedObject<Void>> lights = new LinkedList<>();\n\n    public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks,\n                                    List<Pair<BlockPosition, IBlockData>> blocksToUpdate,\n                                    List<Pair<BlockPosition, CompoundTag>> blockEntities,\n                                    List<BlockPosition> lights) {\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // Convert chunk data\n        Iterator<Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData>> chunksIterator = chunks.entryIterator();\n        while (chunksIterator.hasNext()) {\n            Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData> entry = chunksIterator.next();\n            int currChunkPosXAxis = getChunkCoordX(entry.getKey());\n            int currChunkPosZAxis = getChunkCoordZ(entry.getKey());\n            this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis,\n                    currChunkPosZAxis - baseChunkPosZAxis, entry.getValue()));\n        }\n\n        // Convert blocksToUpdate\n        blocksToUpdate.forEach(blockToUpdate -> {\n            BlockPosition blockPosition = blockToUpdate.getKey();\n            this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis,\n                    blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis,\n                    blockToUpdate.getValue()));\n        });\n\n        // Convert blockEntities\n        blockEntities.forEach(blockEntity -> {\n            BlockPosition blockPosition = blockEntity.getKey();\n            this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis,\n                    blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis,\n                    blockEntity.getValue()));\n        });\n\n        // Convert lights\n        lights.forEach(lightPosition -> {\n            this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis,\n                    lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis,\n                    null));\n        });\n    }\n\n    public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks) {\n        this.chunks.forEach(chunkDataPositioned -> {\n            long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset,\n                    baseChunkPosZAxis + chunkDataPositioned.zOffset);\n            chunks.put(newPos, chunkDataPositioned.object);\n        });\n    }\n\n    public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, IBlockData>> blocksToUpdate) {\n        this.blocksToUpdate.forEach(blockToUpdatePositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset,\n                    baseBlockPosYAxis + blockToUpdatePositioned.yOffset,\n                    baseBlockPosZAxis + blockToUpdatePositioned.zOffset);\n            blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object));\n        });\n    }\n\n    public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, CompoundTag>> blockEntities) {\n        this.blockEntities.forEach(blockEntityPositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset,\n                    baseBlockPosYAxis + blockEntityPositioned.yOffset,\n                    baseBlockPosZAxis + blockEntityPositioned.zOffset);\n            blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object));\n        });\n    }\n\n    public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<BlockPosition> lights) {\n        this.lights.forEach(lightPositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset,\n                    baseBlockPosYAxis + lightPositioned.yOffset,\n                    baseBlockPosZAxis + lightPositioned.zOffset);\n            lights.add(newPos);\n        });\n    }\n\n    private static int getChunkCoordX(long i) {\n        return (int) (i & 4294967295L);\n    }\n\n    private static int getChunkCoordZ(long i) {\n        return (int) (i >>> 32 & 4294967295L);\n    }\n\n    private static class PositionedObject<V> {\n\n        private final int xOffset;\n        private final int yOffset;\n        private final int zOffset;\n        private final V object;\n\n        PositionedObject(int xOffset, int zOffset, V object) {\n            this(xOffset, 0, zOffset, object);\n        }\n\n        PositionedObject(int xOffset, int yOffset, int zOffset, V object) {\n            this.xOffset = xOffset;\n            this.yOffset = yOffset;\n            this.zOffset = zOffset;\n            this.object = object;\n        }\n\n    }\n\n}"
  },
  {
    "path": "NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.EmptyCounterChunkSection;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.google.common.base.Preconditions;\nimport net.minecraft.server.v1_12_R1.BiomeBase;\nimport net.minecraft.server.v1_12_R1.Block;\nimport net.minecraft.server.v1_12_R1.BlockBed;\nimport net.minecraft.server.v1_12_R1.BlockPosition;\nimport net.minecraft.server.v1_12_R1.Chunk;\nimport net.minecraft.server.v1_12_R1.ChunkCoordIntPair;\nimport net.minecraft.server.v1_12_R1.ChunkSection;\nimport net.minecraft.server.v1_12_R1.EnumSkyBlock;\nimport net.minecraft.server.v1_12_R1.IBlockData;\nimport net.minecraft.server.v1_12_R1.NBTTagCompound;\nimport net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk;\nimport net.minecraft.server.v1_12_R1.TileEntity;\nimport net.minecraft.server.v1_12_R1.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_12_R1.CraftChunk;\nimport org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class WorldEditSessionImpl implements WorldEditSession {\n\n    private static final ObjectsPool<WorldEditSessionImpl> POOL = new ObjectsPool<>(WorldEditSessionImpl::new);\n\n    private static final ReflectMethod<Void> TILE_ENTITY_LOAD = new ReflectMethod<>(TileEntity.class, \"a\", NBTTagCompound.class);\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Long2ObjectMapView<ChunkData> chunks = CollectionsFactory.createLong2ObjectArrayMap();\n    private final List<Pair<BlockPosition, IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<Pair<BlockPosition, CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<BlockPosition> lights = new LinkedList<>();\n\n    private Dimension dimension;\n\n    @Nullable\n    private WorldServer worldServer;\n\n    public static WorldEditSessionImpl obtain(WorldServer worldServer) {\n        return POOL.obtain().initialize(worldServer);\n    }\n\n    public static WorldEditSessionImpl obtain(Dimension dimension) {\n        return POOL.obtain().initialize(dimension);\n    }\n\n    private WorldEditSessionImpl() {\n    }\n\n    private WorldEditSessionImpl initialize(WorldServer worldServer) {\n        this.worldServer = worldServer;\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld());\n        return this;\n    }\n\n    private WorldEditSessionImpl initialize(Dimension dimension) {\n        this.worldServer = null;\n        this.dimension = dimension;\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag,\n                         @Nullable CompoundTag blockEntityData) {\n        BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n        if (!isValidPosition(blockPosition))\n            return;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) ||\n                blockData.getBlock() instanceof BlockBed) {\n            blocksToUpdate.add(new Pair<>(blockPosition, blockData));\n            return;\n        }\n\n        ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(blockPosition);\n\n        if (blockEntityData != null)\n            blockEntities.add(new Pair<>(blockPosition, blockEntityData));\n\n        if (plugin.getSettings().isLightsUpdate() && blockData.d() > 0)\n            lights.add(blockPosition);\n\n        ChunkData chunkData = this.chunks.computeIfAbsent(ChunkCoordIntPair.a(chunkCoord.x, chunkCoord.z), ChunkData::new);\n\n        ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4];\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData);\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#getAffectedChunks on partial initialized session\");\n\n        if (chunks.isEmpty())\n            return Collections.emptyList();\n\n        List<ChunkPosition> chunkPositions = new LinkedList<>();\n        World bukkitWorld = worldServer.getWorld();\n        LongIterator iterator = chunks.keyIterator();\n        while (iterator.hasNext()) {\n            long chunkKey = iterator.next();\n            int chunkX = (int) chunkKey;\n            int chunkZ = (int) (chunkKey >> 32);\n            chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false));\n        }\n        return chunkPositions;\n    }\n\n    @Override\n    public void applyBlocks(org.bukkit.Chunk bukkitChunk) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#applyBlocks on partial initialized session\");\n\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n\n        ChunkData chunkData = this.chunks.get(chunk.chunkKey);\n\n        if (chunkData == null)\n            return;\n\n        int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length);\n        for (int i = 0; i < chunkSectionsCount; ++i) {\n            chunk.getSections()[i] = chunkData.chunkSections[i];\n        }\n\n        // Update the biome for the chunk\n        BiomeBase biome = CraftBlock.biomeToBiomeBase(IslandUtils.getDefaultWorldBiome(this.dimension));\n        Arrays.fill(chunk.getBiomeIndex(), (byte) BiomeBase.REGISTRY_ID.a(biome));\n\n        if (plugin.getSettings().isLightsUpdate()) {\n            // initLightning calculates the light emitted from sky to the chunk.\n            chunk.initLighting();\n        }\n\n        chunk.markDirty();\n    }\n\n    @Override\n    public void finish(Island island) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#finish on partial initialized session\");\n\n        // Update blocks\n        blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3));\n\n        // Update block entities\n        blockEntities.forEach(data -> {\n            NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT();\n            if (blockEntityCompound != null) {\n                BlockPosition blockPosition = data.getKey();\n                blockEntityCompound.setInt(\"x\", blockPosition.getX());\n                blockEntityCompound.setInt(\"y\", blockPosition.getY());\n                blockEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition);\n                if (worldTileEntity != null) {\n                    if (TILE_ENTITY_LOAD.isValid()) {\n                        TILE_ENTITY_LOAD.invoke(worldTileEntity, blockEntityCompound);\n                    } else {\n                        worldTileEntity.load(blockEntityCompound);\n                    }\n                }\n            }\n        });\n\n        if (plugin.getSettings().isLightsUpdate() && !lights.isEmpty()) {\n            // For each light block, we calculate its light\n            // We only update the lights after all the chunks were loaded.\n            BukkitExecutor.sync(() -> {\n                lights.forEach(blockPosition -> worldServer.c(EnumSkyBlock.BLOCK, blockPosition));\n\n                LongIterator iterator = this.chunks.keyIterator();\n                while (iterator.hasNext()) {\n                    long chunkKey = iterator.next();\n                    ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32));\n                    NMSUtils.sendPacketToRelevantPlayers(worldServer, chunkCoord.x, chunkCoord.z,\n                            new PacketPlayOutMapChunk(worldServer.getChunkAt(chunkCoord.x, chunkCoord.z), 65535));\n                }\n            }, 5L);\n        }\n\n        release();\n    }\n\n    @Override\n    public Data readData(Location baseLocation) {\n        return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights);\n    }\n\n    @Override\n    public void applyData(Data data, Location baseLocation) {\n        WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data;\n\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // We need to transform all data to the new base location values\n\n        dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks);\n        dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate);\n        dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities);\n        dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights);\n    }\n\n    @Override\n    public void release() {\n        this.chunks.clear();\n        this.blocksToUpdate.clear();\n        this.blockEntities.clear();\n        this.lights.clear();\n        this.worldServer = null;\n        this.dimension = null;\n        POOL.release(this);\n    }\n\n    private boolean isValidPosition(BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < 256;\n    }\n\n    public class ChunkData {\n\n        private final ChunkSection[] chunkSections = new ChunkSection[16];\n\n        private ChunkData(long chunkKey) {\n            ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32));\n            createChunkSections();\n            if (worldServer != null)\n                runCustomWorldGenerator(chunkCoord);\n        }\n\n        private void createChunkSections() {\n            boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END;\n\n            for (int i = 0; i < this.chunkSections.length; ++i) {\n                int chunkSectionPos = i << 4;\n                this.chunkSections[i] = EmptyCounterChunkSection.of(new ChunkSection(chunkSectionPos, hasSkyLight));\n            }\n        }\n\n        private void runCustomWorldGenerator(ChunkCoordIntPair chunkCoord) {\n            ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator();\n\n            if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n                return;\n\n            CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getSeed(), bukkitGenerator);\n            Chunk generatedChunk = chunkGenerator.getOrCreateChunk(chunkCoord.x, chunkCoord.z);\n\n            for (int i = 0; i < this.chunkSections.length; ++i) {\n                ChunkSection generatorChunkSection = generatedChunk.getSections()[i];\n                if (generatorChunkSection != null && generatorChunkSection != Chunk.a)\n                    this.chunkSections[i] = generatorChunkSection;\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/build.gradle",
    "content": "group 'NMS:v1_16_R3'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_16_R3-Tuinity:latest\"\n    compileOnly project(\":NMS:Spigot\")\n    compileOnly project(\":NMS:Paper\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('nms.compile_v1_16') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_16\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter;\nimport com.bgsoftware.superiorskyblock.core.io.ClassProcessor;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityBrewing;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityDispenser;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityFurnace;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityHopper;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockEntityCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache;\nimport io.papermc.paper.chat.ChatComposer;\nimport io.papermc.paper.event.player.AsyncChatEvent;\nimport net.kyori.adventure.text.Component;\nimport net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.EntityFallingBlock;\nimport net.minecraft.server.v1_16_R3.EntityMinecartAbstract;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IChatBaseComponent;\nimport net.minecraft.server.v1_16_R3.IInventory;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport net.minecraft.server.v1_16_R3.MinecraftServer;\nimport net.minecraft.server.v1_16_R3.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.data.Ageable;\nimport org.bukkit.block.data.BlockData;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftServer;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftFallingBlock;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftMinecart;\nimport org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.PotionEffect;\nimport org.jetbrains.annotations.NotNull;\n\nimport java.lang.reflect.Field;\nimport java.util.EnumMap;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.function.BiFunction;\n\npublic class NMSAlgorithmsImpl implements NMSAlgorithms {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    private static final EnumMap<InventoryType, MenuCreator> MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class);\n\n    static {\n        MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuTileEntityDispenser::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuTileEntityDispenser::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuTileEntityFurnace::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuTileEntityBrewing::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuTileEntityHopper::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuTileEntityFurnace::new);\n        MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuTileEntityFurnace::new);\n    }\n\n    private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() {\n        @Override\n        public byte[] processClass(byte[] classBytes, String path) {\n            return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes);\n        }\n    };\n\n    @Override\n    public void registerCommand(BukkitCommand command) {\n        ((CraftServer) plugin.getServer()).getCommandMap().register(\"superiorskyblock2\", command);\n    }\n\n    @Override\n    public String parseSignLine(String original) {\n        return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public int getCombinedId(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        IBlockData blockData;\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            wrapper.getHandle().d(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            blockData = world.getType(wrapper.getHandle());\n        }\n        return Block.getCombinedId(blockData);\n    }\n\n    @Override\n    public int getCombinedId(Material material, byte data) {\n        IBlockData blockData;\n\n        if (data == 0) {\n            Block block = CraftMagicNumbers.getBlock(material);\n            if (block == null)\n                return -1;\n            blockData = block.getBlockData();\n        } else {\n            blockData = CraftMagicNumbers.getBlock(material, data);\n        }\n\n        return blockData == null ? -1 : Block.getCombinedId(blockData);\n    }\n\n    @Override\n    public Optional<String> getTileEntityIdFromCombinedId(int combinedId) {\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (!blockData.getBlock().isTileEntity())\n            return Optional.empty();\n\n        String id = BlockEntityCache.getTileEntityId(blockData);\n\n        return Text.isBlank(id) ? Optional.empty() : Optional.of(id);\n    }\n\n    @Override\n    public int compareMaterials(Material o1, Material o2) {\n        int firstMaterial = o1.isBlock() ? Block.getCombinedId(CraftMagicNumbers.getBlock(o1).getBlockData()) : o1.ordinal();\n        int secondMaterial = o2.isBlock() ? Block.getCombinedId(CraftMagicNumbers.getBlock(o2).getBlockData()) : o2.ordinal();\n        return Integer.compare(firstMaterial, secondMaterial);\n    }\n\n    @Override\n    public short getBlockDataValue(BlockState blockState) {\n        BlockData blockData = blockState.getBlockData();\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0);\n    }\n\n    @Override\n    public short getBlockDataValue(org.bukkit.block.Block block) {\n        BlockData blockData = block.getBlockData();\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0);\n    }\n\n    @Override\n    public short getMaxBlockDataValue(Material material) {\n        if (!material.isBlock())\n            return 0;\n\n        BlockData blockData = Bukkit.createBlockData(material);\n        return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0);\n    }\n\n    @Override\n    public Key getBlockKey(int combinedId) {\n        Block block = Block.getByCombinedId(combinedId).getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) {\n        EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle();\n        Block block = minecart.getDisplayBlock().getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public Key getFallingBlockType(FallingBlock bukkitFallingBlock) {\n        EntityFallingBlock fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle();\n        Block block = fallingBlock.getBlock().getBlock();\n        return KeyBlocksCache.getBlockKey(block);\n    }\n\n    @Override\n    public void setCustomModel(ItemMeta itemMeta, int customModel) {\n        itemMeta.setCustomModelData(customModel);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) {\n        if (!potionMeta.hasCustomEffects())\n            potionMeta.setColor(potionEffect.getType().getColor());\n        potionMeta.addCustomEffect(potionEffect, true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return IRegistry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public int getMaxWorldSize() {\n        return Bukkit.getMaxWorldSize();\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public int getDataVersion() {\n        return CraftMagicNumbers.INSTANCE.getDataVersion();\n    }\n\n    @Override\n    public ClassProcessor getClassProcessor() {\n        return CLASS_PROCESSOR;\n    }\n\n    @Override\n    public void handlePaperChatRenderer(Object event) {\n        if (!(event instanceof AsyncChatEvent))\n            return;\n\n        ChatComposer originalComposer = ((AsyncChatEvent) event).composer();\n        ((AsyncChatEvent) event).composer(new ChatComposerWrapper(originalComposer).composer);\n    }\n\n    @Override\n    public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) {\n        MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType);\n        return menuCreator == null ? null : menuCreator.apply(defaultHolder, title);\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        try {\n            return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH));\n        } catch (IllegalArgumentException e) {\n            return null;\n        }\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        Enchantment glowEnchant;\n\n        try {\n            glowEnchant = new PaperGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        } catch (Throwable error) {\n            glowEnchant = new SpigotGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        }\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n    private interface MenuCreator extends BiFunction<InventoryHolder, String, IInventory> {\n\n    }\n\n    private static class ChatComposerWrapper {\n\n        private final ChatComposer composer = new ChatComposer() {\n\n            @Override\n            public @NotNull Component composeChat(@NotNull Player source,\n                                                  @NotNull Component sourceDisplayName,\n                                                  @NotNull Component message) {\n                String originalFormat = LegacyComponentSerializer.legacyAmpersand().serialize(\n                        originalComposer.composeChat(source, sourceDisplayName, message));\n\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source);\n                Island island = superiorPlayer.getIsland();\n\n                return LegacyComponentSerializer.legacyAmpersand().deserialize(\n                        Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island)));\n            }\n\n        };\n\n        private final ChatComposer originalComposer;\n\n        public ChatComposerWrapper(ChatComposer originalComposer) {\n            this.originalComposer = originalComposer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.NMSChunks;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingMethod;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingTileEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_16_R3.BiomeBase;\nimport net.minecraft.server.v1_16_R3.BiomeStorage;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.BlockPropertySlabType;\nimport net.minecraft.server.v1_16_R3.BlockStepAbstract;\nimport net.minecraft.server.v1_16_R3.Blocks;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.Entity;\nimport net.minecraft.server.v1_16_R3.EntityHuman;\nimport net.minecraft.server.v1_16_R3.EntityTypes;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport net.minecraft.server.v1_16_R3.LightEngineThreaded;\nimport net.minecraft.server.v1_16_R3.NBTBase;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.NBTTagList;\nimport net.minecraft.server.v1_16_R3.PacketPlayOutLightUpdate;\nimport net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;\nimport net.minecraft.server.v1_16_R3.PacketPlayOutUnloadChunk;\nimport net.minecraft.server.v1_16_R3.PlayerConnection;\nimport net.minecraft.server.v1_16_R3.ProtoChunk;\nimport net.minecraft.server.v1_16_R3.TagsBlock;\nimport net.minecraft.server.v1_16_R3.TileEntity;\nimport net.minecraft.server.v1_16_R3.World;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;\nimport org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftNamespacedKey;\nimport org.bukkit.craftbukkit.v1_16_R3.util.UnsafeList;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Function;\n\npublic class NMSChunksImpl implements NMSChunks {\n\n    private static final ReflectField<BiomeBase[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            BiomeStorage.class, BiomeBase[].class, \"h\");\n    private static final ReflectField<Collection<Entity>[]> ENTITY_SLICE_ARRAY = new ReflectField<>(\n            Chunk.class, null, \"entitySlices\");\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        KeyBlocksCache.cacheAllBlocks();\n        CropsTickingMethod.register();\n    }\n\n    @Override\n    public void setBiome(List<ChunkPosition> chunkPositions, Biome biome, Collection<Player> playersToUpdate) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback(\n                ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(Chunk chunk) {\n                ChunkCoordIntPair chunkCoords = chunk.getPos();\n                BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(chunk.getBiomeIndex());\n\n                if (biomeBases == null)\n                    throw new RuntimeException(\"Error while receiving biome bases of chunk (\" + chunkCoords.x + \",\" + chunkCoords.z + \").\");\n\n                IRegistry<BiomeBase> biomeBaseRegistry = chunk.world.r().b(IRegistry.ay);\n                BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biomeBaseRegistry, biome);\n\n                Arrays.fill(biomeBases, biomeBase);\n                chunk.markDirty();\n\n                LightEngineThreaded lightEngineThreaded = (LightEngineThreaded) chunk.world.e();\n\n                PacketPlayOutUnloadChunk unloadChunkPacket = new PacketPlayOutUnloadChunk(chunkCoords.x, chunkCoords.z);\n                //noinspection deprecation\n                PacketPlayOutMapChunk mapChunkPacket = new PacketPlayOutMapChunk(chunk, 65535);\n\n                PacketPlayOutLightUpdate lightUpdatePacket = new PacketPlayOutLightUpdate(chunkCoords, lightEngineThreaded, true);\n\n                playersToUpdate.forEach(player -> {\n                    PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection;\n                    playerConnection.sendPacket(unloadChunkPacket);\n                    playerConnection.sendPacket(lightUpdatePacket);\n                    playerConnection.sendPacket(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) {\n                WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                IRegistry<BiomeBase> biomeBaseRegistry = worldServer.r().b(IRegistry.ay);\n                BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biomeBaseRegistry, biome);\n\n                int[] biomes = unloadedChunk.hasKeyOfType(\"Biomes\", 11) ? unloadedChunk.getIntArray(\"Biomes\") : new int[256];\n                Arrays.fill(biomes, biomeBaseRegistry.a(biomeBase));\n                unloadedChunk.setIntArray(\"Biomes\", biomes);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        });\n    }\n\n    @Override\n    public void deleteChunks(Island island, List<ChunkPosition> chunkPositions, Runnable onFinish) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(),\n                chunkPosition.getX(), chunkPosition.getZ(), false));\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback(\n                ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(Chunk chunk) {\n                Arrays.fill(chunk.getSections(), Chunk.a);\n\n                removeEntities(chunk);\n                removeTileEntities(chunk);\n                removeBlocks(chunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) {\n                WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                NBTTagList sectionsList = new NBTTagList();\n                NBTTagList tileEntities = new NBTTagList();\n\n                unloadedChunk.set(\"Sections\", sectionsList);\n                unloadedChunk.set(\"TileEntities\", tileEntities);\n                unloadedChunk.set(\"Entities\", new NBTTagList());\n\n                if (!(worldServer.generator instanceof IslandsGenerator)) {\n                    ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunkPosition.getX(), chunkPosition.getZ());\n\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkCoords, worldServer);\n\n                    try {\n                        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer,\n                                worldServer.getChunkProvider().chunkGenerator, worldServer.generator);\n                        customChunkGenerator.buildBase(null, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    ChunkSection[] chunkSections = protoChunk.getSections();\n\n                    for (int i = -1; i < 17; ++i) {\n                        int chunkSectionIndex = i;\n                        ChunkSection chunkSection = Arrays.stream(chunkSections).filter(_chunkPosition ->\n                                        _chunkPosition != null && _chunkPosition.getYPosition() >> 4 == chunkSectionIndex)\n                                .findFirst().orElse(Chunk.a);\n\n                        if (chunkSection != Chunk.a) {\n                            NBTTagCompound sectionCompound = new NBTTagCompound();\n                            sectionCompound.setByte(\"Y\", (byte) (i & 255));\n                            chunkSection.getBlocks().a(sectionCompound, \"Palette\", \"BlockStates\");\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPosition tilePosition : protoChunk.c()) {\n                        NBTTagCompound tileCompound = protoChunk.i(tilePosition);\n                        if (tileCompound != null)\n                            tileEntities.add(tileCompound);\n                    }\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        });\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Blocks>> calculateChunks(List<ChunkPosition> chunkPositions,\n                                                                           Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache) {\n        List<CalculatedChunk.Blocks> allCalculatedChunks = new LinkedList<>();\n        List<ChunkPosition> chunkPositionsToCalculate = new LinkedList<>();\n\n        Iterator<ChunkPosition> chunkPositionsIterator = chunkPositions.iterator();\n        while (chunkPositionsIterator.hasNext()) {\n            ChunkPosition chunkPosition = chunkPositionsIterator.next();\n            CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition));\n            if (cachedCalculatedChunk != null) {\n                allCalculatedChunks.add(cachedCalculatedChunk);\n                chunkPositionsIterator.remove();\n            } else {\n                chunkPositionsToCalculate.add(chunkPosition);\n            }\n        }\n\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(allCalculatedChunks);\n\n        CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture = new CompletableFuture<>();\n\n        NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback(\n                ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(Chunk chunk) {\n                ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(),\n                        chunk.getPos().x, chunk.getPos().z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, chunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) {\n                NBTTagList sectionsList = unloadedChunk.getList(\"Sections\", 10);\n                ChunkSection[] chunkSections = new ChunkSection[sectionsList.size()];\n\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    NBTTagCompound sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    if (sectionCompound.hasKeyOfType(\"Palette\", 9) && sectionCompound.hasKeyOfType(\"BlockStates\", 12)) {\n                        //noinspection deprecation\n                        ChunkSection chunkSection = chunkSections[i] = new ChunkSection(yPosition << 4);\n                        chunkSection.getBlocks().a(sectionCompound.getList(\"Palette\", 10), sectionCompound.getLongArray(\"BlockStates\"));\n                        chunkSection.recalcBlockCounts();\n                    }\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Entities>> calculateChunkEntities(Collection<ChunkPosition> chunkPositions) {\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(Collections.emptyList());\n\n        CompletableFuture<List<CalculatedChunk.Entities>> completableFuture = new CompletableFuture<>();\n\n        List<CalculatedChunk.Entities> allCalculatedChunks = new LinkedList<>();\n        List<Pair<ChunkPosition, NBTTagList>> unloadedEntityTags = new LinkedList<>();\n\n        NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback(\n                ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(Chunk chunk) {\n                KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n                for (org.bukkit.entity.Entity bukkitEntity : chunk.getBukkitChunk().getEntities()) {\n                    if (!BukkitEntities.canBypassEntityLimit(bukkitEntity))\n                        chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1);\n                }\n\n                ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false);\n                CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities);\n                allCalculatedChunks.add(calculatedChunk);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound entityData) {\n                unloadedEntityTags.add(new Pair<>(chunkPosition, entityData.getList(\"Entities\", 10)));\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.sync(() -> {\n                    for (Pair<ChunkPosition, NBTTagList> worldUnloadedEntityTagsPair : unloadedEntityTags) {\n                        WorldServer worldServer = ((CraftWorld) worldUnloadedEntityTagsPair.getKey().getWorld()).getHandle();\n                        KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n                        for (NBTBase entityTag : worldUnloadedEntityTagsPair.getValue()) {\n                            EntityTypes<?> entityType = EntityTypes.a((NBTTagCompound) entityTag).orElse(null);\n                            if (entityType == null)\n                                continue;\n\n                            Entity fakeEntity = EntityTypes.a((NBTTagCompound) entityTag, worldServer).orElse(null);\n                            if (fakeEntity != null) {\n                                fakeEntity.valid = false;\n                                if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity()))\n                                    continue;\n                            }\n\n                            Key entityKey = Keys.of(Registry.ENTITY_TYPE.get(\n                                    CraftNamespacedKey.fromMinecraft(EntityTypes.getName(entityType))));\n\n\n                            chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1);\n                        }\n\n                        CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(worldUnloadedEntityTagsPair.getKey(), chunkEntities);\n                        allCalculatedChunks.add(calculatedChunk);\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public void injectChunkSections(org.bukkit.Chunk chunk) {\n        // No implementation\n    }\n\n    @Override\n    public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.c());\n    }\n\n    @Override\n    public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) {\n        Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().getChunkProvider()\n                .getChunkAt(chunkPosition.getX(), chunkPosition.getZ(), false);\n        return chunk == null ? null : chunk.bukkitChunk;\n    }\n\n    @Override\n    public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) {\n        if (plugin.getSettings().getCropsInterval() <= 0)\n            return;\n\n        if (stop) {\n            CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove(\n                    chunk.getWorld().getName(), ChunkCoordIntPair.pair(chunk.getX(), chunk.getZ()));\n            World world = cropsTickingTileEntity == null ? null : cropsTickingTileEntity.getWorld();\n            if (cropsTickingTileEntity != null && world != null)\n                world.tileEntityListTick.remove(cropsTickingTileEntity);\n        } else {\n            CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle());\n        }\n    }\n\n    @Override\n    public void updateCropsTicker(List<ChunkPosition> chunkPositions, double newCropGrowthMultiplier) {\n        if (chunkPositions.isEmpty()) return;\n        CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity ->\n                cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier));\n    }\n\n    @Override\n    public void shutdown() {\n        List<CompletableFuture<Void>> pendingTasks = NMSUtils.getPendingChunkActions();\n\n        if (pendingTasks.isEmpty())\n            return;\n\n        Log.info(\"Waiting for chunk tasks to complete.\");\n\n        CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join();\n    }\n\n    @Override\n    public List<Location> getBlockEntities(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        List<Location> blockEntities = new LinkedList<>();\n\n        org.bukkit.World bukkitWorld = bukkitChunk.getWorld();\n\n        chunk.getTileEntities().keySet().forEach(blockPosition ->\n                blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ())));\n\n        return blockEntities;\n    }\n\n    private static CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, ChunkSection[] chunkSections) {\n        KeyMap<Counter> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        List<Location> spawnersLocations = new LinkedList<>();\n\n        for (ChunkSection chunkSection : chunkSections) {\n            if (chunkSection != null && !chunkSection.c()) {\n                for (BlockPosition bp : BlockPosition.b(0, 0, 0, 15, 15, 15)) {\n                    IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ());\n                    Block block = blockData.getBlock();\n                    if (block != Blocks.AIR) {\n                        Location location = new Location(chunkPosition.getWorld(),\n                                (chunkPosition.getX() << 4) + bp.getX(),\n                                chunkSection.getYPosition() + bp.getY(),\n                                (chunkPosition.getZ() << 4) + bp.getZ());\n\n                        int blockAmount = 1;\n\n                        if ((blockData.getBlock().a(TagsBlock.SLABS) || blockData.getBlock().a(TagsBlock.WOODEN_SLABS)) &&\n                                blockData.get(BlockStepAbstract.a) == BlockPropertySlabType.DOUBLE) {\n                            blockAmount = 2;\n                            blockData = blockData.set(BlockStepAbstract.a, BlockPropertySlabType.BOTTOM);\n                        }\n\n                        Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData.getBlock()), location);\n                        blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount);\n                        if (block == Blocks.SPAWNER) {\n                            spawnersLocations.add(location);\n                        }\n                    }\n                }\n            }\n        }\n\n        return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations);\n    }\n\n    private static void removeEntities(Chunk chunk) {\n        Collection<Entity>[] entitySlices = null;\n        Function<Void, Collection<Entity>> entitySliceCreationFunction = null;\n\n        try {\n            entitySlices = chunk.entitySlices;\n            entitySliceCreationFunction = v -> new UnsafeList<>();\n        } catch (Throwable ex) {\n            try {\n                entitySlices = ENTITY_SLICE_ARRAY.get(chunk);\n                entitySliceCreationFunction = v -> new net.minecraft.server.v1_16_R3.EntitySlice<>(Entity.class);\n            } catch (Exception error) {\n                Log.error(error, \"An unexpected error occurred while removing entities from chunk \", chunk.getPos(), \":\");\n            }\n        }\n\n        if (entitySlices != null) {\n            for (int i = 0; i < entitySlices.length; i++) {\n                entitySlices[i].forEach(entity -> {\n                    if (!(entity instanceof EntityHuman))\n                        entity.dead = true;\n                });\n                entitySlices[i] = entitySliceCreationFunction.apply(null);\n            }\n        }\n    }\n\n    private static void removeTileEntities(Chunk chunk) {\n        new LinkedList<>(chunk.tileEntities.keySet()).forEach(chunk.world::removeTileEntity);\n        chunk.tileEntities.clear();\n    }\n\n    private static void removeBlocks(Chunk chunk) {\n        ChunkCoordIntPair chunkCoords = chunk.getPos();\n        WorldServer worldServer = chunk.world;\n\n        if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) {\n            CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer,\n                    worldServer.getChunkProvider().chunkGenerator, worldServer.generator);\n            ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkCoords, worldServer);\n            customChunkGenerator.buildBase(null, protoChunk);\n\n            for (int i = 0; i < 16; i++)\n                chunk.getSections()[i] = protoChunk.getSections()[i];\n\n            for (Map.Entry<BlockPosition, TileEntity> entry : protoChunk.x().entrySet())\n                worldServer.setTileEntity(entry.getKey(), entry.getValue());\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.nms.NMSDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.EndWorldEnderDragonBattleHandler;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.IslandEnderDragonBattle;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.IslandEntityEnderDragon;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.SpikesCache;\nimport com.google.common.cache.LoadingCache;\nimport net.minecraft.server.v1_16_R3.EnderDragonBattle;\nimport net.minecraft.server.v1_16_R3.EntityEnderDragon;\nimport net.minecraft.server.v1_16_R3.EntityTypes;\nimport net.minecraft.server.v1_16_R3.WorldGenEnder;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.World;\nimport org.bukkit.advancement.Advancement;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.entity.EnderDragon;\nimport org.bukkit.entity.Player;\n\nimport java.lang.reflect.Modifier;\nimport java.util.List;\n\npublic class NMSDragonFightImpl implements NMSDragonFight {\n\n    private static final ReflectField<EntityTypes.b<?>> ENTITY_TYPES_BUILDER = new ReflectField<EntityTypes.b<?>>(\n            EntityTypes.class, EntityTypes.b.class, Modifier.PRIVATE | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static final ReflectField<EnderDragonBattle> WORLD_DRAGON_BATTLE = new ReflectField<EnderDragonBattle>(\n            WorldServer.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static final ReflectField<LoadingCache<Long, List<WorldGenEnder.Spike>>> SPIKE_CACHE = new ReflectField<LoadingCache<Long, List<WorldGenEnder.Spike>>>(\n            WorldGenEnder.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static boolean firstWorldPreparation = true;\n\n    static {\n        ENTITY_TYPES_BUILDER.set(EntityTypes.ENDER_DRAGON, (EntityTypes.b<EntityEnderDragon>) IslandEntityEnderDragon::fromEntityTypes);\n    }\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n        WORLD_DRAGON_BATTLE.set(worldServer, new EndWorldEnderDragonBattleHandler(worldServer));\n\n        if (firstWorldPreparation) {\n            firstWorldPreparation = false;\n            SPIKE_CACHE.set(null, SpikesCache.getInstance());\n        }\n    }\n\n    @Nullable\n    @Override\n    public EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        WorldServer worldServer = ((CraftWorld) island.getCenter(dimension).getWorld()).getHandle();\n\n        if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler))\n            return null;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle();\n        IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache());\n\n        return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity();\n    }\n\n    @Override\n    public void startDragonBattle(Island island, Location location) {\n        World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle();\n        dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location));\n    }\n\n    @Override\n    public void removeDragonBattle(Island island, Dimension dimension) {\n        World bukkitWorld = island.getCenter(dimension).getWorld();\n\n        if (bukkitWorld == null)\n            return;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle();\n        IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache());\n        if (enderDragonBattle != null) {\n            enderDragonBattle.removeBattlePlayers();\n            enderDragonBattle.getEnderDragon().die();\n        }\n    }\n\n    @Override\n    public void awardTheEndAchievement(Player player) {\n        Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft(\"end/root\"));\n        if (advancement != null)\n            player.getAdvancementProgress(advancement).awardCriteria(\"\");\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.nms.NMSEntities;\nimport net.minecraft.server.v1_16_R3.Entity;\nimport net.minecraft.server.v1_16_R3.EntityMinecartFurnace;\nimport net.minecraft.server.v1_16_R3.IMaterial;\nimport net.minecraft.server.v1_16_R3.Items;\nimport net.minecraft.server.v1_16_R3.RecipeItemStack;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftAnimals;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.inventory.EntityEquipment;\nimport org.bukkit.inventory.ItemStack;\n\npublic class NMSEntitiesImpl implements NMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, \"portalTicks\");\n    private static final RecipeItemStack MINECART_FURNACE_FUEL_RECIPE = RecipeItemStack.a(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public ItemStack[] getEquipment(EntityEquipment entityEquipment) {\n        ItemStack[] itemStacks = new ItemStack[7];\n\n        itemStacks[0] = new ItemStack(Material.ARMOR_STAND);\n        itemStacks[1] = entityEquipment.getItemInMainHand();\n        itemStacks[2] = entityEquipment.getItemInOffHand();\n        itemStacks[3] = entityEquipment.getHelmet();\n        itemStacks[4] = entityEquipment.getChestplate();\n        itemStacks[5] = entityEquipment.getLeggings();\n        itemStacks[6] = entityEquipment.getBoots();\n\n        return itemStacks;\n    }\n\n    @Override\n    public boolean isAnimalFood(ItemStack itemStack, Animals animals) {\n        return ((CraftAnimals) animals).getHandle().k(CraftItemStack.asNMSCopy(itemStack));\n    }\n\n    @Override\n    public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_FUEL_RECIPE.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    public int getPortalTicks(org.bukkit.entity.Entity entity) {\n        return PORTAL_TICKS.get(((CraftEntity) entity).getHandle());\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSHologramsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.nms.NMSHolograms;\nimport net.minecraft.server.v1_16_R3.AxisAlignedBB;\nimport net.minecraft.server.v1_16_R3.DamageSource;\nimport net.minecraft.server.v1_16_R3.EntityArmorStand;\nimport net.minecraft.server.v1_16_R3.EntityHuman;\nimport net.minecraft.server.v1_16_R3.EnumHand;\nimport net.minecraft.server.v1_16_R3.EnumInteractionResult;\nimport net.minecraft.server.v1_16_R3.EnumItemSlot;\nimport net.minecraft.server.v1_16_R3.IChatBaseComponent;\nimport net.minecraft.server.v1_16_R3.ItemStack;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.SoundEffect;\nimport net.minecraft.server.v1_16_R3.Vec3D;\nimport net.minecraft.server.v1_16_R3.World;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftArmorStand;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\n\npublic class NMSHologramsImpl implements NMSHolograms {\n\n    @Override\n    public Hologram createHologram(Location location) {\n        assert location.getWorld() != null;\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ());\n        world.addEntity(entityHologram);\n        return entityHologram;\n    }\n\n    @Override\n    public boolean isHologram(Entity entity) {\n        return ((CraftEntity) entity).getHandle() instanceof Hologram;\n    }\n\n    public static class EntityHologram extends EntityArmorStand implements Hologram {\n\n        private CraftEntity bukkitEntity;\n\n        EntityHologram(World world, double x, double y, double z) {\n            super(world, x, y, z);\n            setInvisible(true);\n            setSmall(true);\n            setArms(false);\n            setNoGravity(true);\n            setBasePlate(true);\n            setMarker(true);\n            super.collides = false;\n            super.setCustomNameVisible(true);\n            super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));\n        }\n\n        @Override\n        public void setHologramName(String name) {\n            super.setCustomName(CraftChatMessage.fromString(name)[0]);\n        }\n\n        @Override\n        public void removeHologram() {\n            super.die();\n        }\n\n        @Override\n        public ArmorStand getHandle() {\n            return this.getBukkitEntity();\n        }\n\n        @Override\n        public void inactiveTick() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        @Override\n        public boolean isCollidable() {\n            return false;\n        }\n\n        @Override\n        public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) {\n            // Prevent stand being equipped\n        }\n\n        @Override\n        public boolean a_(int i, ItemStack item) {\n            // Prevent stand being equipped\n            return false;\n        }\n\n        @Override\n        public void saveData(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n        }\n\n        @Override\n        public void loadData(NBTTagCompound nbttagcompound) {\n            // Do not load NBT.\n        }\n\n        @Override\n        public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) {\n            // Prevent stand being equipped\n            return EnumInteractionResult.PASS;\n        }\n\n        @Override\n        public void tick() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        public void forceSetBoundingBox(AxisAlignedBB boundingBox) {\n            super.a(boundingBox);\n        }\n\n        @Override\n        public CraftArmorStand getBukkitEntity() {\n            if (bukkitEntity == null) {\n                bukkitEntity = new CraftArmorStand(super.world.getServer(), this);\n            }\n            return (CraftArmorStand) bukkitEntity;\n        }\n\n        @Override\n        public void die() {\n            // Prevent being killed.\n        }\n\n        @Override\n        public void playSound(SoundEffect soundeffect, float f, float f1) {\n            // Remove sounds.\n        }\n\n        @Override\n        public boolean a_(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public boolean d(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public NBTTagCompound save(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return nbttagcompound;\n        }\n\n        @Override\n        public void load(NBTTagCompound nbttagcompound) {\n            // Do not load NBT.\n        }\n\n        @Override\n        public boolean isInvulnerable(DamageSource source) {\n            /*\n             * The field Entity.invulnerable is private.\n             * It's only used while saving NBTTags, but since the entity would be killed\n             * on chunk unload, we prefer to override isInvulnerable().\n             */\n            return true;\n        }\n\n        @Override\n        public void setCustomName(@Nullable IChatBaseComponent ichatbasecomponent) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void setCustomNameVisible(boolean flag) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void a(AxisAlignedBB boundingBox) {\n            // Do not change it!\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.NMSPlayers;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.player.OfflinePlayerDataImpl;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask;\nimport com.mojang.authlib.properties.Property;\nimport net.md_5.bungee.api.ChatMessageType;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport net.minecraft.server.v1_16_R3.EntityPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.boss.BarColor;\nimport org.bukkit.boss.BarStyle;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class NMSPlayersImpl implements NMSPlayers {\n\n    private static final ReflectMethod<Locale> PLAYER_LOCALE = new ReflectMethod<>(Player.class, \"locale\");\n\n    @Override\n    public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) {\n        return OfflinePlayerDataImpl.create(offlinePlayer);\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        Player player = superiorPlayer.asPlayer();\n        if (player != null) {\n            EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();\n            Optional<Property> optional = entityPlayer.getProfile().getProperties().get(\"textures\").stream().findFirst();\n            optional.ifPresent(property -> setSkinTexture(superiorPlayer, property));\n        }\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) {\n        superiorPlayer.setTextureValue(property.getValue());\n    }\n\n    @Override\n    public void sendActionBar(Player player, String message) {\n        //noinspection deprecation\n        player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));\n    }\n\n    @Override\n    public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) {\n        BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun);\n        bossBar.addPlayer(player);\n        return bossBar;\n    }\n\n    @Override\n    public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) {\n        player.sendTitle(title, subtitle, fadeIn, duration, fadeOut);\n    }\n\n    @Override\n    public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) {\n        return superiorPlayer.getUniqueId().equals(item.getThrower());\n    }\n\n    @Nullable\n    @Override\n    public Locale getPlayerLocale(Player player) {\n        if (PLAYER_LOCALE.isValid()) {\n            return player.locale();\n        } else try {\n            //noinspection deprecation\n            return PlayerLocales.getLocale(player.getLocale());\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }\n\n    private static class BossBarImpl implements BossBar {\n\n        private final org.bukkit.boss.BossBar bossBar;\n        private final BossBarTask bossBarTask;\n\n        public BossBarImpl(String message, BarColor color, double ticksToRun) {\n            bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID);\n            this.bossBarTask = BossBarTask.create(this, ticksToRun);\n        }\n\n        @Override\n        public void addPlayer(Player player) {\n            this.bossBar.addPlayer(player);\n            this.bossBarTask.registerTask(player);\n        }\n\n        @Override\n        public void removeAll() {\n            this.bossBar.removeAll();\n            this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask);\n        }\n\n        @Override\n        public void setProgress(double progress) {\n            this.bossBar.setProgress(progress);\n        }\n\n        @Override\n        public double getProgress() {\n            return this.bossBar.getProgress();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.nms.NMSTags;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.server.v1_16_R3.DataConverterRegistry;\nimport net.minecraft.server.v1_16_R3.DataConverterTypes;\nimport net.minecraft.server.v1_16_R3.DynamicOpsNBT;\nimport net.minecraft.server.v1_16_R3.Entity;\nimport net.minecraft.server.v1_16_R3.EntityTypes;\nimport net.minecraft.server.v1_16_R3.ItemStack;\nimport net.minecraft.server.v1_16_R3.MinecraftKey;\nimport net.minecraft.server.v1_16_R3.NBTBase;\nimport net.minecraft.server.v1_16_R3.NBTTagByte;\nimport net.minecraft.server.v1_16_R3.NBTTagByteArray;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.NBTTagDouble;\nimport net.minecraft.server.v1_16_R3.NBTTagFloat;\nimport net.minecraft.server.v1_16_R3.NBTTagInt;\nimport net.minecraft.server.v1_16_R3.NBTTagIntArray;\nimport net.minecraft.server.v1_16_R3.NBTTagList;\nimport net.minecraft.server.v1_16_R3.NBTTagLong;\nimport net.minecraft.server.v1_16_R3.NBTTagShort;\nimport net.minecraft.server.v1_16_R3.NBTTagString;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.Set;\n\n@SuppressWarnings({\"unused\"})\npublic class NMSTagsImpl implements NMSTags {\n\n    @Override\n    public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound());\n        tagCompound.setInt(\"DataVersion\", CraftMagicNumbers.INSTANCE.getDataVersion());\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) {\n        if (compoundTag.containsKey(\"NBT\")) {\n            // Old compound version, deserialize it accordingly\n            return deserializeItemOld(compoundTag);\n        }\n\n        NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT();\n\n        int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion();\n        int itemVersion = tagCompound.getInt(\"DataVersion\");\n        if (itemVersion < currentVersion) {\n            tagCompound = (NBTTagCompound) DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK,\n                    new Dynamic<>(DynamicOpsNBT.a, tagCompound), itemVersion, currentVersion).getValue();\n        }\n\n        ItemStack itemStack = ItemStack.a(tagCompound);\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) {\n        String typeName = Materials.patchOldMaterialName(compoundTag.getString(\"type\").orElse(null));\n        Material type = Material.valueOf(typeName);\n        int amount = compoundTag.getInt(\"amount\").orElse(0);\n        short data = (short) compoundTag.getShort(\"data\").orElse(0);\n        CompoundTag nbtData = compoundTag.getCompound(\"NBT\").orElse(null);\n\n        org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data);\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n        if (nbtData != null)\n            itemStack.setTag((NBTTagCompound) nbtData.toNBT());\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    @Override\n    @SuppressWarnings(\"ConstantConditions\")\n    public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) {\n        CraftWorld craftWorld = (CraftWorld) location.getWorld();\n        NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT();\n\n        if (nbtTagCompound == null)\n            nbtTagCompound = new NBTTagCompound();\n\n        if (!nbtTagCompound.hasKey(\"id\"))\n            //noinspection deprecation\n            nbtTagCompound.setString(\"id\", new MinecraftKey(entityType.getName()).getKey());\n\n        Entity entity = EntityTypes.a(nbtTagCompound, craftWorld.getHandle(), (_entity) -> {\n            _entity.setPositionRotation(location.getX(), location.getY(), location.getZ(), _entity.yaw, _entity.pitch);\n            return !craftWorld.getHandle().addEntitySerialized(_entity) ? null : _entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((NBTTagByteArray) object).getBytes();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NBTTagByte) object).asByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((NBTTagCompound) object).getKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NBTTagDouble) object).asDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NBTTagFloat) object).asFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((NBTTagIntArray) object).getInts();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NBTTagInt) object).asInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((NBTTagList) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NBTTagLong) object).asLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NBTTagShort) object).asShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((NBTTagString) object).asString();\n    }\n\n    @Override\n    public Object parseList(ListTag listTag) {\n        NBTTagList nbtTagList = new NBTTagList();\n\n        for (Tag<?> tag : listTag)\n            nbtTagList.add((NBTBase) tag.toNBT());\n\n        return nbtTagList;\n    }\n\n    @Override\n    public Object getNBTCompoundTag(Object object, String key) {\n        return ((NBTTagCompound) object).get(key);\n    }\n\n    @Override\n    public void setNBTCompoundTagValue(Object object, String key, Object value) {\n        ((NBTTagCompound) object).set(key, (NBTBase) value);\n    }\n\n    @Override\n    public int getNBTTagListSize(Object object) {\n        return ((NBTTagList) object).size();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockStatesMapper;\nimport com.bgsoftware.superiorskyblock.tag.ByteTag;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.IntArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport com.google.common.base.Suppliers;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockBed;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkConverter;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkProviderServer;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.HeightMap;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IBlockState;\nimport net.minecraft.server.v1_16_R3.IChunkAccess;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.PlayerChunkMap;\nimport net.minecraft.server.v1_16_R3.ProtoChunk;\nimport net.minecraft.server.v1_16_R3.TileEntity;\nimport net.minecraft.server.v1_16_R3.World;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\n\npublic class NMSUtils {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ReflectMethod<Chunk> CHUNK_PROVIDER_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>(\n            ChunkProviderServer.class, \"getChunkAtIfCachedImmediately\", int.class, int.class);\n\n    private static final List<CompletableFuture<Void>> PENDING_CHUNK_ACTIONS = new LinkedList<>();\n\n    public static final ObjectsPool<ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition>> BLOCK_POS_POOL =\n            ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0));\n\n    private NMSUtils() {\n\n    }\n\n    @Nullable\n    public static <T extends TileEntity> T getTileEntityAt(Location location, Class<T> type) {\n        org.bukkit.World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return null;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            TileEntity tileEntity = worldServer.getTileEntity(blockPosition);\n            return !type.isInstance(tileEntity) ? null : type.cast(tileEntity);\n        }\n    }\n\n    public static void runActionOnChunks(Collection<ChunkPosition> chunksCoords,\n                                         boolean saveChunks, ChunkCallback chunkCallback) {\n        runActionOnChunksInternal(chunksCoords, saveChunks, chunkCallback);\n    }\n\n    private static void runActionOnChunksInternal(Collection<ChunkPosition> chunksCoords,\n                                                  boolean saveChunks, ChunkCallback chunkCallback) {\n        List<ChunkPosition> unloadedChunks = new LinkedList<>();\n        List<Chunk> loadedChunks = new LinkedList<>();\n\n        chunksCoords.forEach(chunkPosition -> {\n            WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n            IChunkAccess chunkAccess;\n\n            try {\n                chunkAccess = worldServer.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ());\n            } catch (Throwable ex) {\n                chunkAccess = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n            }\n\n            if (chunkAccess instanceof Chunk) {\n                loadedChunks.add((Chunk) chunkAccess);\n            } else {\n                unloadedChunks.add(chunkPosition.copy());\n            }\n        });\n\n        boolean hasUnloadedChunks = !unloadedChunks.isEmpty();\n\n        if (!loadedChunks.isEmpty())\n            runActionOnLoadedChunks(loadedChunks, chunkCallback);\n\n        if (hasUnloadedChunks) {\n            runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback);\n        } else {\n            chunkCallback.onFinish();\n        }\n    }\n\n    private static void runActionOnLoadedChunks(Collection<Chunk> chunks, ChunkCallback chunkCallback) {\n        chunks.forEach(chunkCallback::onLoadedChunk);\n    }\n\n    private static void runActionOnUnloadedChunks(Collection<ChunkPosition> chunks,\n                                                  boolean saveChunks, ChunkCallback chunkCallback) {\n        if (CHUNK_PROVIDER_SERVER_GET_CHUNK_IF_CACHED.isValid()) {\n            Iterator<ChunkPosition> chunksIterator = chunks.iterator();\n            while (chunksIterator.hasNext()) {\n                ChunkPosition chunkPosition = chunksIterator.next();\n\n                WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                Chunk cachedUnloadedChunk = worldServer.getChunkProvider().getChunkAtIfCachedImmediately(\n                        chunkPosition.getX(), chunkPosition.getZ());\n                if (cachedUnloadedChunk != null) {\n                    chunkCallback.onLoadedChunk(cachedUnloadedChunk);\n                    chunksIterator.remove();\n                }\n            }\n\n            if (chunks.isEmpty()) {\n                chunkCallback.onFinish();\n                return;\n            }\n        }\n\n        CompletableFuture<Void> pendingTask = new CompletableFuture<>();\n        PENDING_CHUNK_ACTIONS.add(pendingTask);\n\n        BukkitExecutor.createTask().runAsync(v -> {\n            CountDownLatch countDownLatch;\n            if (chunkCallback.isWaitForChunkLoad) {\n                countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size());\n            } else {\n                countDownLatch = null;\n            }\n\n            chunks.forEach(chunkPosition -> {\n                WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                PlayerChunkMap playerChunkMap = worldServer.getChunkProvider().playerChunkMap;\n\n                ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunkPosition.getX(), chunkPosition.getZ());\n\n                boolean calledCountdown = false;\n                try {\n                    NBTTagCompound chunkCompound = playerChunkMap.read(chunkCoords);\n\n                    if (chunkCompound == null) {\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                        return;\n                    }\n\n                    NBTTagCompound chunkDataCompound = playerChunkMap.getChunkData(worldServer.getTypeKey(),\n                            Suppliers.ofInstance(worldServer.getWorldPersistentData()), chunkCompound, chunkCoords, worldServer);\n\n                    if (chunkDataCompound.hasKeyOfType(\"Level\", 10)) {\n                        chunkCallback.onUnloadedChunk(chunkPosition, chunkDataCompound.getCompound(\"Level\"));\n                        calledCountdown = true;\n                        if (saveChunks)\n                            playerChunkMap.a(chunkCoords, chunkDataCompound);\n                    } else {\n                        if (countDownLatch != null)\n                            countDownLatch.countDown();\n                    }\n                } catch (Exception error) {\n                    if (!calledCountdown && countDownLatch != null)\n                        countDownLatch.countDown();\n                    Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                }\n            });\n\n            if (countDownLatch != null) {\n                try {\n                    countDownLatch.await();\n                } catch (InterruptedException error) {\n                    throw new RuntimeException(error);\n                }\n            }\n        }).runSync(v -> {\n            chunkCallback.onFinish();\n\n            pendingTask.complete(null);\n            PENDING_CHUNK_ACTIONS.remove(pendingTask);\n        });\n    }\n\n    public static List<CompletableFuture<Void>> getPendingChunkActions() {\n        return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkCoordIntPair chunkCoord, World world) {\n        try {\n            // Paper's constructor for ProtoChunk\n            return new ProtoChunk(chunkCoord, ChunkConverter.a, world);\n        } catch (Throwable ex) {\n            // Spigot's constructor for ProtoChunk\n            // noinspection deprecation\n            return new ProtoChunk(chunkCoord, ChunkConverter.a);\n        }\n    }\n\n    public static IBlockData setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag statesTag,\n                                      CompoundTag tileEntity) {\n        if (!isValidPosition(chunk.getWorld(), blockPosition))\n            return null;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (statesTag != null) {\n            for (Map.Entry<String, Tag<?>> entry : statesTag.entrySet()) {\n                try {\n                    // noinspection rawtypes\n                    IBlockState blockState = BlockStatesMapper.getBlockState(entry.getKey());\n                    if (blockState != null) {\n                        if (entry.getValue() instanceof ByteTag) {\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, ((ByteTag) entry.getValue()).getValue() == 1);\n                        } else if (entry.getValue() instanceof IntArrayTag) {\n                            int[] data = ((IntArrayTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, data[0]);\n                        } else if (entry.getValue() instanceof StringTag) {\n                            String data = ((StringTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, Enum.valueOf(blockState.getType(), data));\n                        }\n                    }\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockData.getBlock() instanceof BlockBed) {\n            chunk.world.setTypeAndData(blockPosition, blockData, 3);\n            return blockData;\n        }\n\n        int indexY = blockPosition.getY() >> 4;\n\n        ChunkSection chunkSection = chunk.getSections()[indexY];\n\n        if (chunkSection == null) {\n            try {\n                // Paper's constructor for ChunkSection for more optimized chunk sections.\n                chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, chunk, chunk.world, true);\n            } catch (Throwable ex) {\n                // Spigot's constructor for ChunkSection\n                // noinspection deprecation\n                chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4);\n            }\n        }\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        boolean isOriginallyChunkSectionEmpty = chunkSection.c();\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData, false);\n\n        chunk.heightMap.get(HeightMap.Type.MOTION_BLOCKING).a(blockX, blockY, blockZ, blockData);\n        chunk.heightMap.get(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES).a(blockX, blockY, blockZ, blockData);\n        chunk.heightMap.get(HeightMap.Type.OCEAN_FLOOR).a(blockX, blockY, blockZ, blockData);\n        chunk.heightMap.get(HeightMap.Type.WORLD_SURFACE).a(blockX, blockY, blockZ, blockData);\n\n        chunk.markDirty();\n        chunk.setNeedsSaving(true);\n\n        boolean isChunkSectionEmpty = chunkSection.c();\n\n        if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty)\n            chunk.getWorld().e().a(blockPosition, isChunkSectionEmpty);\n\n        chunk.getWorld().e().a(blockPosition);\n\n        if (tileEntity != null) {\n            NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT();\n            if (tileEntityCompound != null) {\n                tileEntityCompound.setInt(\"x\", blockPosition.getX());\n                tileEntityCompound.setInt(\"y\", blockPosition.getY());\n                tileEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition);\n                if (worldTileEntity != null)\n                    worldTileEntity.load(blockData, tileEntityCompound);\n            }\n        }\n\n        return blockData;\n    }\n\n    private static boolean isValidPosition(World world, BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight();\n    }\n\n    public static abstract class ChunkCallback {\n\n        private final ChunkLoadReason chunkLoadReason;\n        private final boolean isWaitForChunkLoad;\n\n        @Nullable\n        protected CountDownLatch chunkLoadLatch;\n\n        public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) {\n            this.chunkLoadReason = chunkLoadReason;\n            this.isWaitForChunkLoad = isWaitForChunkLoad;\n        }\n\n        public abstract void onLoadedChunk(Chunk chunk);\n\n        public abstract void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk);\n\n        public abstract void onFinish();\n\n        protected final void latchCountDown() {\n            if (this.chunkLoadLatch != null)\n                this.chunkLoadLatch.countDown();\n        }\n\n        public final void onChunkNotExist(ChunkPosition chunkPosition) {\n            if (!plugin.getProviders().hasCustomWorldsSupport()) {\n                latchCountDown();\n                return;\n            }\n\n            ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> {\n                if (error == null) {\n                    BukkitExecutor.ensureMain(() -> {\n                        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n                        onLoadedChunk(chunk);\n                    });\n                } else {\n                    latchCountDown();\n                    throw new RuntimeException(error);\n                }\n            });\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.signs.IslandSigns;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.NMSWorld;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.NMSCachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator.IslandsGeneratorImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners.TileEntityMobSpawnerNotifier;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockTickListServerTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.ChunkReaderImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.WorldEditSessionImpl;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.destroystokyo.paper.antixray.ChunkPacketBlockController;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockAccessAir;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.BlockPropertySlabType;\nimport net.minecraft.server.v1_16_R3.BlockStepAbstract;\nimport net.minecraft.server.v1_16_R3.Blocks;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IChatBaseComponent;\nimport net.minecraft.server.v1_16_R3.PacketPlayOutWorldBorder;\nimport net.minecraft.server.v1_16_R3.SoundCategory;\nimport net.minecraft.server.v1_16_R3.SoundEffectType;\nimport net.minecraft.server.v1_16_R3.TagsBlock;\nimport net.minecraft.server.v1_16_R3.TileEntityMobSpawner;\nimport net.minecraft.server.v1_16_R3.TileEntitySign;\nimport net.minecraft.server.v1_16_R3.World;\nimport net.minecraft.server.v1_16_R3.WorldBorder;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.block.data.Waterlogged;\nimport org.bukkit.block.data.type.BubbleColumn;\nimport org.bukkit.block.data.type.Sign;\nimport org.bukkit.block.data.type.WallSign;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftSign;\nimport org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.function.IntFunction;\n\npublic class NMSWorldImpl implements NMSWorld {\n\n    private static final ReflectMethod<Float> SOUND_VOLUME = new ReflectMethod<>(SoundEffectType.class, \"a\");\n    private static final ReflectMethod<Float> SOUND_PITCH = new ReflectMethod<>(SoundEffectType.class, \"b\");\n    private static final ReflectField<Object> CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(World.class,\n            Object.class, \"chunkPacketBlockController\").removeFinal();\n\n    private static boolean alreadyWarned = false;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return getBlockKeyInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return ConstantKeys.AIR;\n        }\n    }\n\n    private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock();\n\n        Location location = new Location(\n                Bukkit.getWorld(chunkSnapshot.getWorldName()),\n                (chunkSnapshot.getX() << 4) + x,\n                y,\n                (chunkSnapshot.getZ() << 4) + z\n        );\n\n        return Keys.of(KeyBlocksCache.getBlockKey(block), location);\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return canPlayerSuffocateInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return true;\n        }\n    }\n\n    private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        IBlockData blockData = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState();\n        return !blockData.getCollisionShape(BlockAccessAir.INSTANCE, BlockPosition.ZERO).isEmpty();\n    }\n\n    @Override\n    public void listenSpawner(Location location, IntFunction<Integer> delayChangeCallback) {\n        TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class);\n        if (mobSpawner == null || mobSpawner instanceof TileEntityMobSpawnerNotifier)\n            return;\n\n        World world = mobSpawner.getWorld();\n\n        TileEntityMobSpawnerNotifier tileEntityMobSpawnerNotifier =\n                new TileEntityMobSpawnerNotifier(mobSpawner, delayChangeCallback);\n\n        world.removeTileEntity(mobSpawner.getPosition());\n        world.setTileEntity(mobSpawner.getPosition(), tileEntityMobSpawnerNotifier);\n    }\n\n    @Override\n    public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) {\n        if (!plugin.getSettings().isWorldBorders())\n            return;\n\n        Player player = superiorPlayer.asPlayer();\n        org.bukkit.World world = superiorPlayer.getWorld();\n\n        if (world == null || player == null)\n            return;\n\n        int islandSize = island == null ? 0 : island.getIslandSize();\n\n        boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0;\n\n        WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle();\n\n        WorldBorder worldBorder;\n\n        if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) {\n            worldBorder = worldServer.getWorldBorder();\n        } else {\n            Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n            if (dimension == null)\n                return;\n\n            Location center = island.getCenter(dimension);\n\n            worldBorder = new WorldBorder();\n            worldBorder.world = worldServer;\n            worldBorder.setWarningDistance(0);\n            worldBorder.setCenter(center.getX(), center.getZ());\n\n            switch (superiorPlayer.getBorderColor()) {\n                case BLUE: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    break;\n                }\n                case GREEN: {\n                    worldBorder.setSize((islandSize * 2) + 1.001D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE);\n                    break;\n                }\n                case RED: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE);\n                    break;\n                }\n            }\n        }\n\n        PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder,\n                PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE);\n        ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder);\n    }\n\n    @Override\n    public Object getBlockData(org.bukkit.block.Block block) {\n        return block.getBlockData();\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId) {\n        WorldServer world = ((CraftWorld) location.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n            IBlockData blockData =\n                    NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null);\n\n            if (blockData != null) {\n                world.getChunkProvider().flagDirty(blockPosition);\n                if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) {\n                    world.chunkPacketBlockController.onBlockChange(world, blockPosition, blockData, Blocks.AIR.getBlockData(), 530);\n                }\n            }\n        }\n    }\n\n    @Override\n    public ICachedBlock cacheBlock(org.bukkit.block.Block block) {\n        return NMSCachedBlock.obtain(block);\n    }\n\n    @Override\n    public boolean isWaterLogged(org.bukkit.block.Block block) {\n        if (Materials.isWater(block.getType()))\n            return true;\n\n        org.bukkit.block.data.BlockData blockData = block.getBlockData();\n\n        return blockData instanceof BubbleColumn ||\n                (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged());\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof WallSign)\n            return SignType.WALL_SIGN;\n        else if (sign instanceof Sign)\n            return SignType.STANDING_SIGN;\n        else\n            return SignType.UNKNOWN;\n    }\n\n    @Override\n    public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) {\n        IBlockData blockData = ((CraftBlock) block).getNMS();\n        return PistonPushReaction.values()[blockData.getPushReaction().ordinal()];\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) {\n        return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS());\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) {\n        return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle());\n    }\n\n    private int getDefaultAmount(IBlockData blockData) {\n        Block nmsBlock = blockData.getBlock();\n\n        // Checks for double slabs\n        if ((nmsBlock.a(TagsBlock.SLABS) || nmsBlock.a(TagsBlock.WOODEN_SLABS)) &&\n                blockData.get(BlockStepAbstract.a) == BlockPropertySlabType.DOUBLE) {\n            return 2;\n        }\n\n        return 1;\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) {\n        return !bukkitBlock.isPassable();\n    }\n\n    @Override\n    public void placeSign(Island island, Location location) {\n        TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class);\n        if (tileEntitySign == null)\n            return;\n\n        String[] lines = new String[4];\n        System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length);\n        String[] strippedLines = new String[4];\n        for (int i = 0; i < 4; i++)\n            strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]);\n\n        IChatBaseComponent[] newLines;\n\n        IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false);\n        if (result.isCancelEvent()) {\n            newLines = CraftSign.sanitizeLines(strippedLines);\n        } else {\n            newLines = CraftSign.sanitizeLines(lines);\n        }\n\n        System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4);\n    }\n\n    @Override\n    public void playGeneratorSound(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getX(), location.getY(), location.getZ());\n            world.triggerEffect(1501, blockPosition, 0);\n        }\n    }\n\n    @Override\n    public void playBreakAnimation(org.bukkit.block.Block block) {\n        World world = ((CraftWorld) block.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(block.getX(), block.getY(), block.getZ());\n            world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition)));\n        }\n    }\n\n    @Override\n    public void playPlaceSound(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            SoundEffectType soundEffectType = world.getType(blockPosition).getStepSound();\n\n            float volume = SOUND_VOLUME.isValid() ? SOUND_VOLUME.invoke(soundEffectType) : soundEffectType.getVolume();\n            float pitch = SOUND_PITCH.isValid() ? SOUND_PITCH.invoke(soundEffectType) : soundEffectType.getPitch();\n\n            world.playSound(null, blockPosition, soundEffectType.getPlaceSound(),\n                    SoundCategory.BLOCKS, (volume + 1.0F) / 2.0F, pitch * 0.8F);\n\n        }\n    }\n\n    @Override\n    public int getMinHeight(org.bukkit.World world) {\n        try {\n            return world.getMinHeight();\n        } catch (Throwable error) {\n            return 0;\n        }\n    }\n\n    @Override\n    public void removeAntiXray(org.bukkit.World bukkitWorld) {\n        World world = ((CraftWorld) bukkitWorld).getHandle();\n        if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid())\n            CHUNK_PACKET_BLOCK_CONTROLLER.set(world, ChunkPacketBlockController.NO_OPERATION_INSTANCE);\n    }\n\n    @Override\n    public void setOceanLevel(org.bukkit.World world) {\n        // Not possible in this version, it is hardcoded 63\n    }\n\n    @Override\n    public IslandsGenerator createGenerator(Dimension dimension) {\n        return new IslandsGeneratorImpl(dimension);\n    }\n\n    @Override\n    public WorldEditSession createEditSession(org.bukkit.World world) {\n        return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle());\n    }\n\n    @Override\n    public WorldEditSession createPartialEditSession(Dimension dimension) {\n        return WorldEditSessionImpl.obtain(dimension);\n    }\n\n    @Override\n    public ChunkReader createChunkReader(Chunk chunk) {\n        return new ChunkReaderImpl(chunk);\n    }\n\n    @Override\n    public void listenBlockStateChanges(org.bukkit.World world) {\n        WorldServer worldServer = ((CraftWorld) world).getHandle();\n        BlockTickListServerTracker.listenForTicks(worldServer);\n        if (!alreadyWarned) {\n            Log.warn(\"This version is old and you may experience issues with block changes detection\");\n            alreadyWarned = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;\n\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic abstract class CropsTickingMethod {\n\n    private static final ReflectField<Random> WORLD_SERVER_RANDOM_TICK_RANDOM = new ReflectField<>(\n            WorldServer.class, Random.class, \"randomTickRandom\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static Set<Block> CROPS_TO_GROW_CACHE;\n\n    static {\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate);\n    }\n\n    private static final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition();\n\n    private static final CropsTickingMethod INSTANCE = WORLD_SERVER_RANDOM_TICK_RANDOM.isValid() ?\n            new PaperCropsTickingMethod() : new SpigotCropsTickingMethod();\n\n    protected CropsTickingMethod() {\n\n    }\n\n    public static void register() {\n        // Calls the static initializer which registers the callback.\n    }\n\n    public static void tick(Chunk chunk, int tickSpeed) {\n        INSTANCE.doTick(chunk, tickSpeed);\n    }\n\n    protected abstract void doTick(Chunk chunk, int tickSpeed);\n\n    private static void onSettingsUpdate() {\n        CROPS_TO_GROW_CACHE = new HashSet<>();\n        plugin.getSettings().getCropsToGrow().forEach(cropName -> {\n            Key key = Keys.ofMaterialAndData(cropName);\n            if (key instanceof MaterialKey) {\n                Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial());\n                if (block != null && block.getBlockData().isTicking())\n                    CROPS_TO_GROW_CACHE.add(block);\n            }\n        });\n    }\n\n    private static class PaperCropsTickingMethod extends CropsTickingMethod {\n\n        @Override\n        protected void doTick(Chunk chunk, int tickSpeed) {\n            WorldServer worldServer = chunk.world;\n\n            ChunkCoordIntPair chunkCoord = chunk.getPos();\n            int chunkOffsetX = chunkCoord.x << 4;\n            int chunkOffsetZ = chunkCoord.z << 4;\n\n            Random randomTickRandom = WORLD_SERVER_RANDOM_TICK_RANDOM.get(worldServer);\n\n            ChunkSection[] sections = chunk.getSections();\n            for (int sectionIndex = 0; sectionIndex < 16; ++sectionIndex) {\n                ChunkSection chunkSection = sections[sectionIndex];\n                if (chunkSection == null || chunkSection == Chunk.a)\n                    continue;\n\n                int tickingBlocks = chunkSection.tickingList.size();\n                if (tickingBlocks <= 0)\n                    continue;\n\n                int offsetY = sectionIndex << 4;\n\n                for (int i = 0; i < tickSpeed; ++i) {\n                    int index = randomTickRandom.nextInt(4096);\n                    if (index >= tickingBlocks)\n                        continue;\n\n                    long raw = chunkSection.tickingList.getRaw(index);\n                    int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw);\n                    IBlockData blockData = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw);\n                    if (!CROPS_TO_GROW_CACHE.contains(blockData.getBlock()))\n                        continue;\n\n                    chunkTickMutablePosition.d((location & 15) | chunkOffsetX,\n                            ((location >>> 8) & 255) | offsetY,\n                            ((location >>> 4) & 15) | chunkOffsetZ);\n\n                    blockData.b(worldServer, chunkTickMutablePosition, randomTickRandom);\n                }\n\n            }\n\n        }\n\n    }\n\n    private static class SpigotCropsTickingMethod extends CropsTickingMethod {\n\n        private static int random = ThreadLocalRandom.current().nextInt();\n\n        @Override\n        protected void doTick(Chunk chunk, int tickSpeed) {\n            WorldServer worldServer = chunk.world;\n\n            ChunkCoordIntPair chunkCoord = chunk.getPos();\n            int chunkOffsetX = chunkCoord.x << 4;\n            int chunkOffsetZ = chunkCoord.z << 4;\n\n            for (ChunkSection chunkSection : chunk.getSections()) {\n                if (chunkSection != Chunk.a && chunkSection.d()) {\n                    for (int i = 0; i < tickSpeed; i++) {\n                        random = random * 3 + 1013904223;\n                        int factor = random >> 2;\n                        int x = factor & 15;\n                        int z = factor >> 8 & 15;\n                        int y = factor >> 16 & 15;\n                        IBlockData blockData = chunkSection.getType(x, y, z);\n                        if (blockData.isTicking() && CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) {\n                            chunkTickMutablePosition.d(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ);\n                            blockData.b(worldServer, chunkTickMutablePosition, worldServer.random);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.GameRules;\nimport net.minecraft.server.v1_16_R3.ITickable;\nimport net.minecraft.server.v1_16_R3.TileEntity;\nimport net.minecraft.server.v1_16_R3.TileEntityTypes;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class CropsTickingTileEntity extends TileEntity implements ITickable {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Chunk2ObjectMap<CropsTickingTileEntity> tickingChunks = new Chunk2ObjectMap<>();\n\n    private final WeakReference<Island> island;\n    private final WeakReference<Chunk> chunk;\n\n    private int currentTick = 0;\n\n    private double cachedCropGrowthMultiplier;\n\n    private CropsTickingTileEntity(Island island, Chunk chunk) {\n        super(TileEntityTypes.COMMAND_BLOCK);\n        this.island = new WeakReference<>(island);\n        this.chunk = new WeakReference<>(chunk);\n        ChunkCoordIntPair chunkCoord = chunk.getPos();\n        setLocation(chunk.getWorld(), new BlockPosition(chunkCoord.x << 4, 1, chunkCoord.z << 4));\n\n        try {\n            // Not a method of Spigot - fixes https://github.com/OmerBenGera/SuperiorSkyblock2/issues/5\n            setCurrentChunk(chunk);\n        } catch (Throwable ignored) {\n        }\n\n        assert world != null;\n\n        world.tileEntityListTick.add(this);\n        this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1;\n    }\n\n    public static void create(Island island, String worldName, Chunk chunk) {\n        long chunkPair = chunk.getPos().pair();\n        tickingChunks.computeIfAbsent(worldName, chunkPair, () -> new CropsTickingTileEntity(island, chunk));\n    }\n\n    public static CropsTickingTileEntity remove(String worldName, long chunkCoords) {\n        return tickingChunks.remove(worldName, chunkCoords);\n    }\n\n    public static void forEachChunk(List<ChunkPosition> chunkPositions, Consumer<CropsTickingTileEntity> cropsTickingTileEntityConsumer) {\n        if (tickingChunks.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> {\n            long chunkKey = chunkPosition.asPair();\n            CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey);\n            if (cropsTickingTileEntity != null)\n                cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity);\n        });\n    }\n\n    @Override\n    public void tick() {\n        assert world != null;\n\n        if (++currentTick <= plugin.getSettings().getCropsInterval())\n            return;\n\n        Chunk chunk = this.chunk.get();\n        Island island = this.island.get();\n\n        if (chunk == null || island == null) {\n            world.tileEntityListTick.remove(this);\n            return;\n        }\n\n        currentTick = 0;\n\n        int worldRandomTick = world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED);\n        int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval());\n        if (chunkRandomTickSpeed > 0)\n            CropsTickingMethod.tick(chunk, chunkRandomTickSpeed);\n    }\n\n    @Override\n    public void w() {\n        tick();\n    }\n\n    public void setCropGrowthMultiplier(double cropGrowthMultiplier) {\n        this.cachedCropGrowthMultiplier = cropGrowthMultiplier;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/DragonUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.WorldGenEndTrophy;\n\nimport java.lang.reflect.Modifier;\n\npublic class DragonUtils {\n\n    private static final ReflectField<BlockPosition> END_PODIUM_LOCATION = new ReflectField<BlockPosition>(\n            WorldGenEndTrophy.class, BlockPosition.class,\n            Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static BlockPosition currentPodiumPosition = BlockPosition.ZERO;\n\n    private DragonUtils() {\n\n    }\n\n    public static void runWithPodiumPosition(BlockPosition podiumPosition, Runnable runnable) {\n        try {\n            END_PODIUM_LOCATION.set(null, podiumPosition);\n            currentPodiumPosition = podiumPosition;\n            runnable.run();\n        } finally {\n            END_PODIUM_LOCATION.set(null, BlockPosition.ZERO);\n            currentPodiumPosition = BlockPosition.ZERO;\n        }\n    }\n\n    public static BlockPosition getCurrentPodiumPosition() {\n        return currentPodiumPosition;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys;\nimport net.minecraft.server.v1_16_R3.EnderDragonBattle;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.WorldServer;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class EndWorldEnderDragonBattleHandler extends EnderDragonBattle {\n\n    private static final IslandCacheKey<IslandEnderDragonBattle> CACHE_KEY = IslandCacheKeys.register(\"DRAGON_BATTLE\", IslandEnderDragonBattle.class);\n\n    private final List<IslandEnderDragonBattle> worldDragonBattlesList = new LinkedList<>();\n\n    public EndWorldEnderDragonBattleHandler(WorldServer worldServer) {\n        super(worldServer, worldServer.getSeed(), new NBTTagCompound());\n    }\n\n    @Override\n    public void b() {\n        this.worldDragonBattlesList.forEach(EnderDragonBattle::b);\n    }\n\n    public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) {\n        IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle);\n        if (oldBattle != null)\n            this.worldDragonBattlesList.remove(oldBattle);\n        this.worldDragonBattlesList.add(enderDragonBattle);\n    }\n\n    @Nullable\n    public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) {\n        return islandCache.get(CACHE_KEY);\n    }\n\n    @Nullable\n    public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) {\n        IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY);\n        if (enderDragonBattle != null)\n            this.worldDragonBattlesList.remove(enderDragonBattle);\n        return enderDragonBattle;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.BlockPredicate;\nimport net.minecraft.server.v1_16_R3.Blocks;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.DragonControllerLanding;\nimport net.minecraft.server.v1_16_R3.DragonControllerPhase;\nimport net.minecraft.server.v1_16_R3.EnderDragonBattle;\nimport net.minecraft.server.v1_16_R3.EntityEnderDragon;\nimport net.minecraft.server.v1_16_R3.EntityPlayer;\nimport net.minecraft.server.v1_16_R3.HeightMap;\nimport net.minecraft.server.v1_16_R3.IDragonController;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.ShapeDetector;\nimport net.minecraft.server.v1_16_R3.ShapeDetectorBlock;\nimport net.minecraft.server.v1_16_R3.ShapeDetectorBuilder;\nimport net.minecraft.server.v1_16_R3.TileEntity;\nimport net.minecraft.server.v1_16_R3.TileEntityEnderPortal;\nimport net.minecraft.server.v1_16_R3.Vec3D;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\n\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class IslandEnderDragonBattle extends EnderDragonBattle {\n\n    private static final ReflectField<EnderDragonBattle> DRAGON_BATTLE = new ReflectField<EnderDragonBattle>(\n            EntityEnderDragon.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1)\n            .removeFinal();\n\n    private static final ReflectField<Boolean> SCAN_FOR_LEGACY_PORTALS = new ReflectField<>(\n            EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 3);\n\n    private static final ReflectField<Boolean> WAS_DRAGON_KILLED = new ReflectField<>(\n            EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 1);\n\n    private static final ReflectField<Vec3D> LANDING_TARGET_POSITION = new ReflectField<>(\n            DragonControllerLanding.class, Vec3D.class, Modifier.PRIVATE, 1);\n\n    private static final ShapeDetector EXIT_PORTAL_PATTERN = ShapeDetectorBuilder.a()\n            .a(new String[]{\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \"})\n            .a(new String[]{\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \"})\n            .a(new String[]{\"       \", \"       \", \"       \", \"   #   \", \"       \", \"       \", \"       \"})\n            .a(new String[]{\"  ###  \", \" #   # \", \"#     #\", \"#  #  #\", \"#     #\", \" #   # \", \"  ###  \"})\n            .a(new String[]{\"       \", \"  ###  \", \" ##### \", \" ##### \", \" ##### \", \"  ###  \", \"       \"})\n            .a('#', ShapeDetectorBlock.a(BlockPredicate.a(Blocks.BEDROCK)))\n            .b();\n\n    private final Island island;\n    private final BlockPosition islandBlockPosition;\n    private final Vec3D islandBlockVectored;\n\n    private final IslandEntityEnderDragon entityEnderDragon;\n\n    private byte currentTick = 0;\n\n    public IslandEnderDragonBattle(Island island, WorldServer worldServer, Location location) {\n        this(island, worldServer, new BlockPosition(location.getX(), location.getY(), location.getZ()),\n                null);\n    }\n\n    public IslandEnderDragonBattle(Island island, WorldServer worldServer, BlockPosition islandBlockPosition,\n                                   @Nullable IslandEntityEnderDragon islandEntityEnderDragon) {\n        super(worldServer, worldServer.getSeed(), new NBTTagCompound());\n        SCAN_FOR_LEGACY_PORTALS.set(this, false);\n        WAS_DRAGON_KILLED.set(this, false);\n        this.island = island;\n        this.islandBlockPosition = islandBlockPosition;\n        this.islandBlockVectored = Vec3D.c(islandBlockPosition);\n        this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon;\n        DRAGON_BATTLE.set(this.entityEnderDragon, this);\n    }\n\n    @Override\n    public void b() {\n        // doServerTick\n\n        DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::b);\n\n        IDragonController currentController = this.entityEnderDragon.getDragonControllerManager().a();\n        if (currentController instanceof DragonControllerLanding && !this.islandBlockVectored.equals(currentController.g())) {\n            LANDING_TARGET_POSITION.set(currentController, this.islandBlockVectored);\n        }\n\n        if (++currentTick >= 20) {\n            updateBattlePlayers();\n            currentTick = 0;\n        }\n    }\n\n    @Nullable\n    @Override\n    public ShapeDetector.ShapeDetectorCollection getExitPortalShape() {\n        // findExitPortal\n\n        int chunkX = this.islandBlockPosition.getX() >> 4;\n        int chunkZ = this.islandBlockPosition.getZ() >> 4;\n\n        for (int x = -8; x <= 8; ++x) {\n            for (int z = -8; z <= 8; ++z) {\n                Chunk chunk = this.world.getChunkAt(chunkX + x, chunkZ + z);\n\n                for (TileEntity tileEntity : chunk.getTileEntities().values()) {\n                    if (tileEntity instanceof TileEntityEnderPortal) {\n                        ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, tileEntity.getPosition());\n                        if (shapeDetectorCollection != null) {\n                            if (this.exitPortalLocation == null)\n                                this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition();\n\n                            return shapeDetectorCollection;\n                        }\n                    }\n                }\n            }\n        }\n\n        int highestBlock = this.world.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, this.islandBlockPosition).getY();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition currentPosition = wrapper.getHandle();\n            currentPosition.d(this.islandBlockPosition.getX(), 0, this.islandBlockPosition.getZ());\n            for (int y = highestBlock; y >= 0; --y) {\n                currentPosition.setY(y);\n\n                ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, currentPosition);\n\n                if (shapeDetectorCollection != null) {\n                    if (this.exitPortalLocation == null)\n                        this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition();\n\n                    return shapeDetectorCollection;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    @Override\n    public void resetCrystals() {\n        // resetSpikeCrystals\n\n        DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::resetCrystals);\n    }\n\n    public void removeBattlePlayers() {\n        this.bossBattle.getPlayers().forEach(this.bossBattle::removePlayer);\n    }\n\n    public IslandEntityEnderDragon getEnderDragon() {\n        return this.entityEnderDragon;\n    }\n\n    private void updateBattlePlayers() {\n        Set<UUID> nearbyPlayers = new HashSet<>();\n\n        WorldInfo worldInfo = WorldInfo.of(this.world.getWorld());\n\n        try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) {\n            strategy.getPlayers(worldInfo).forEach(player -> {\n                EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();\n                this.bossBattle.addPlayer(entityPlayer);\n                nearbyPlayers.add(entityPlayer.getUniqueID());\n            });\n        }\n\n        this.bossBattle.getPlayers().stream()\n                .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUniqueID()))\n                .forEach(this.bossBattle::removePlayer);\n    }\n\n    private IslandEntityEnderDragon spawnEnderDragon() {\n        IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.world, islandBlockPosition);\n        entityEnderDragon.getDragonControllerManager().setControllerPhase(DragonControllerPhase.HOLDING_PATTERN);\n        entityEnderDragon.setPositionRotation(islandBlockPosition.getX(), 128,\n                islandBlockPosition.getZ(), this.world.getRandom().nextFloat() * 360.0F, 0.0F);\n\n        this.world.addEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL);\n\n        this.dragonUUID = entityEnderDragon.getUniqueID();\n        this.resetCrystals(); // scan for crystals\n\n        return entityEnderDragon;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.DifficultyDamageScaler;\nimport net.minecraft.server.v1_16_R3.EntityEnderDragon;\nimport net.minecraft.server.v1_16_R3.EntityTypes;\nimport net.minecraft.server.v1_16_R3.EnumMobSpawn;\nimport net.minecraft.server.v1_16_R3.GroupDataEntity;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.World;\nimport net.minecraft.server.v1_16_R3.WorldAccess;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftEnderDragon;\n\npublic class IslandEntityEnderDragon extends EntityEnderDragon {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static EntityEnderDragon fromEntityTypes(EntityTypes<? extends EntityEnderDragon> entityTypes, World world) {\n        return plugin.getGrid().isIslandsWorld(world.getWorld()) ? new IslandEntityEnderDragon(world) :\n                new EntityEnderDragon(entityTypes, world);\n    }\n\n    private final Dimension dimension;\n    private BlockPosition islandBlockPosition;\n\n    public IslandEntityEnderDragon(WorldServer worldServer, BlockPosition islandBlockPosition) {\n        this(worldServer);\n        this.islandBlockPosition = islandBlockPosition;\n    }\n\n    private IslandEntityEnderDragon(World world) {\n        super(EntityTypes.ENDER_DRAGON, world);\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld());\n    }\n\n    @Nullable\n    @Override\n    public GroupDataEntity prepare(WorldAccess worldaccess,\n                                   DifficultyDamageScaler difficultydamagescaler,\n                                   EnumMobSpawn enummobspawn,\n                                   @Nullable GroupDataEntity groupdataentity,\n                                   @Nullable NBTTagCompound nbttagcompound) {\n        if (this.islandBlockPosition == null)\n            finalizeIslandEnderDragon();\n\n        return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound);\n    }\n\n    @Override\n    public void loadData(NBTTagCompound nbtTagCompound) {\n        super.loadData(nbtTagCompound);\n        finalizeIslandEnderDragon();\n    }\n\n    @Override\n    public void movementTick() {\n        DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::movementTick);\n    }\n\n    @Override\n    public CraftEnderDragon getBukkitEntity() {\n        return (CraftEnderDragon) super.getBukkitEntity();\n    }\n\n    private void finalizeIslandEnderDragon() {\n        if (!(world instanceof WorldServer) || !(((WorldServer) world).getDragonBattle() instanceof EndWorldEnderDragonBattleHandler))\n            return;\n\n        EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) ((WorldServer) world).getDragonBattle();\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null)\n            return;\n\n        Location middleBlock = island.getCenter(dimension);\n\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        if (dimensionConfig instanceof SettingsManager.Worlds.End) {\n            middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock);\n        }\n\n        this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ());\n\n        IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this);\n        dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/SpikesCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.CacheStats;\nimport com.google.common.cache.LoadingCache;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.common.collect.Lists;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.MathHelper;\nimport net.minecraft.server.v1_16_R3.WorldGenEnder;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class SpikesCache implements LoadingCache<Long, List<WorldGenEnder.Spike>> {\n\n    private static final SpikesCache INSTANCE = new SpikesCache();\n\n    private final LoadingCache<BlockPosition, List<WorldGenEnder.Spike>> cachedSpikes = CacheBuilder.newBuilder()\n            .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader());\n\n    private long worldSeed;\n\n    public static SpikesCache getInstance() {\n        return INSTANCE;\n    }\n\n    private SpikesCache() {\n\n    }\n\n    @Override\n    public List<WorldGenEnder.Spike> get(Long worldSeed) throws ExecutionException {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public List<WorldGenEnder.Spike> getUnchecked(Long worldSeed) {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public ImmutableMap<Long, List<WorldGenEnder.Spike>> getAll(Iterable<? extends Long> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public List<WorldGenEnder.Spike> apply(Long worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void refresh(Long worldSeed) {\n        try {\n            this.worldSeed = worldSeed;\n            cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition());\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public ConcurrentMap<Long, List<WorldGenEnder.Spike>> asMap() {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Nullable\n    @Override\n    public List<WorldGenEnder.Spike> getIfPresent(Object worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public List<WorldGenEnder.Spike> get(Long worldSeed, Callable<? extends List<WorldGenEnder.Spike>> loader) throws ExecutionException {\n        try {\n            this.worldSeed = worldSeed;\n            return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader);\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public ImmutableMap<Long, List<WorldGenEnder.Spike>> getAllPresent(Iterable<?> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void put(Long worldSeed, List<WorldGenEnder.Spike> spikes) {\n        try {\n            this.worldSeed = worldSeed;\n            cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes);\n        } finally {\n            this.worldSeed = 0;\n        }\n    }\n\n    @Override\n    public void putAll(Map<? extends Long, ? extends List<WorldGenEnder.Spike>> spikesMap) {\n        spikesMap.forEach(this::put);\n    }\n\n    @Override\n    public void invalidate(Object worldSeed) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void invalidateAll(Iterable<?> keys) {\n        throw new UnsupportedOperationException(\"This operation is not supported in SpikesCache.\");\n    }\n\n    @Override\n    public void invalidateAll() {\n        this.cachedSpikes.invalidateAll();\n    }\n\n    @Override\n    public long size() {\n        return this.cachedSpikes.size();\n    }\n\n    @Override\n    public CacheStats stats() {\n        return this.cachedSpikes.stats();\n    }\n\n    @Override\n    public void cleanUp() {\n        this.cachedSpikes.cleanUp();\n    }\n\n    private class InternalCacheLoader extends CacheLoader<BlockPosition, List<WorldGenEnder.Spike>> {\n\n        @Override\n        public List<WorldGenEnder.Spike> load(BlockPosition blockPosition) {\n            List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());\n\n            Collections.shuffle(list, new Random(worldSeed));\n            List<WorldGenEnder.Spike> spikesList = Lists.newArrayList();\n\n            for (int i = 0; i < 10; ++i) {\n                int spikeX = MathHelper.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i)));\n                int spikeZ = MathHelper.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i)));\n                int l = list.get(i);\n                int radius = 2 + l / 3;\n                int height = 76 + l * 3;\n                boolean guarded = l == 1 || l == 2;\n\n                spikesList.add(new WorldGenEnder.Spike(spikeX + blockPosition.getX(),\n                        spikeZ + blockPosition.getZ(), radius, height, guarded));\n            }\n\n            return spikesList;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/generator/IslandsGeneratorImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_16_R3.BiomeBase;\nimport net.minecraft.server.v1_16_R3.BiomeStorage;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport net.minecraft.server.v1_16_R3.Registry;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;\nimport org.bukkit.generator.BlockPopulator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\n@SuppressWarnings({\"unused\", \"NullableProblems\"})\npublic class IslandsGeneratorImpl extends IslandsGenerator {\n\n    private static final ReflectField<BiomeBase[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            BiomeStorage.class, BiomeBase[].class, \"h\");\n    private static final ReflectField<Registry<BiomeBase>> BIOME_REGISTRY = new ReflectField<>(\n            BiomeStorage.class, Registry.class, \"registry\", \"g\");\n    private static final ReflectField<BiomeStorage> BIOME_STORAGE = new ReflectField<>(\n            new ClassInfo(\"generator.CustomChunkGenerator$CustomBiomeGrid\", ClassInfo.PackageType.CRAFTBUKKIT),\n            BiomeStorage.class, \"biome\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Dimension dimension;\n\n    public IslandsGeneratorImpl(Dimension dimension) {\n        this.dimension = dimension;\n    }\n\n    @Override\n    public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) {\n        ChunkData chunkData = createChunkData(world);\n\n        Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension);\n\n        setBiome(biomeGrid, targetBiome);\n\n        if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            chunkData.setBlock(0, 99, 0, Material.BEDROCK);\n        }\n\n        return chunkData;\n    }\n\n    @Override\n    public List<BlockPopulator> getDefaultPopulators(World world) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Location getFixedSpawnLocation(World world, Random random) {\n        return new Location(world, 0, 100, 0);\n    }\n\n    private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) {\n        BiomeStorage biomeStorage = BIOME_STORAGE.get(biomeGrid);\n        BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeStorage);\n\n        BiomeBase biomeBase = CraftBlock.biomeToBiomeBase((IRegistry<BiomeBase>) BIOME_REGISTRY.get(biomeStorage), biome);\n\n        if (biomeBases == null)\n            return;\n\n        Arrays.fill(biomeBases, biomeBase);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityBrewing.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu;\n\nimport net.minecraft.server.v1_16_R3.ChatMessage;\nimport net.minecraft.server.v1_16_R3.TileEntityBrewingStand;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuTileEntityBrewing extends TileEntityBrewingStand {\n\n    private final InventoryHolder holder;\n\n    public MenuTileEntityBrewing(InventoryHolder holder, String title) {\n        this.holder = holder;\n        this.setCustomName(new ChatMessage(title));\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityDispenser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu;\n\nimport net.minecraft.server.v1_16_R3.ChatMessage;\nimport net.minecraft.server.v1_16_R3.TileEntityDispenser;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuTileEntityDispenser extends TileEntityDispenser {\n\n    private final InventoryHolder holder;\n\n    public MenuTileEntityDispenser(InventoryHolder holder, String title) {\n        this.holder = holder;\n        this.setCustomName(new ChatMessage(title));\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityFurnace.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu;\n\nimport net.minecraft.server.v1_16_R3.ChatMessage;\nimport net.minecraft.server.v1_16_R3.TileEntityFurnaceFurnace;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuTileEntityFurnace extends TileEntityFurnaceFurnace {\n\n    private final InventoryHolder holder;\n\n    public MenuTileEntityFurnace(InventoryHolder holder, String title) {\n        this.holder = holder;\n        this.setCustomName(new ChatMessage(title));\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityHopper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu;\n\nimport net.minecraft.server.v1_16_R3.ChatMessage;\nimport net.minecraft.server.v1_16_R3.TileEntityHopper;\nimport org.bukkit.inventory.InventoryHolder;\n\npublic class MenuTileEntityHopper extends TileEntityHopper {\n\n    private final InventoryHolder holder;\n\n    public MenuTileEntityHopper(InventoryHolder holder, String title) {\n        this.holder = holder;\n        this.setCustomName(new ChatMessage(title));\n    }\n\n    @Override\n    public InventoryHolder getOwner() {\n        return holder;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.player;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.mojang.authlib.GameProfile;\nimport net.minecraft.server.v1_16_R3.EntityPlayer;\nimport net.minecraft.server.v1_16_R3.MinecraftServer;\nimport net.minecraft.server.v1_16_R3.PlayerInteractManager;\nimport net.minecraft.server.v1_16_R3.World;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftServer;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.Optional;\n\npublic class OfflinePlayerDataImpl implements OfflinePlayerData {\n\n    private static final ObjectsPool<OfflinePlayerDataImpl> POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new);\n\n    private Player fakePlayer;\n\n    public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) {\n        return POOL.obtain().initialize(offlinePlayer);\n    }\n\n    private OfflinePlayerDataImpl() {\n\n    }\n\n    private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) {\n        GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(),\n                Optional.ofNullable(offlinePlayer.getName()).orElse(\"\"));\n\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        WorldServer worldServer = server.getWorldServer(World.OVERWORLD);\n        assert worldServer != null;\n        EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));\n        this.fakePlayer = entityPlayer.getBukkitEntity();\n        this.fakePlayer.loadData();\n\n        return this;\n    }\n\n    @Override\n    public Player getFakeOnlinePlayer() {\n        return this.fakePlayer;\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle();\n        entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle();\n        entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    @Override\n    public void applyChanges() {\n        this.fakePlayer.saveData();\n    }\n\n    @Override\n    public void release() {\n        this.fakePlayer = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/spawners/TileEntityMobSpawnerNotifier.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.server.v1_16_R3.MobSpawnerAbstract;\nimport net.minecraft.server.v1_16_R3.TileEntityMobSpawner;\n\nimport java.lang.reflect.Modifier;\nimport java.util.function.IntFunction;\n\npublic class TileEntityMobSpawnerNotifier extends TileEntityMobSpawner {\n\n    private static final ReflectField<MobSpawnerAbstract> MOB_SPAWNER_ABSTRACT;\n\n    static {\n        // In Airplane, the modifiers of the field is `public final` instead of `private final`\n        // as it is in Paper and Spigot. We want to make sure we support all jars.\n        ReflectField<MobSpawnerAbstract> mobSpawnerAbstract = new ReflectField<>(\n                TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n        if (mobSpawnerAbstract.isValid()) {\n            MOB_SPAWNER_ABSTRACT = mobSpawnerAbstract;\n        } else {\n            MOB_SPAWNER_ABSTRACT = new ReflectField<>(TileEntityMobSpawner.class, MobSpawnerAbstract.class,\n                    Modifier.PUBLIC | Modifier.FINAL, 1);\n        }\n\n        MOB_SPAWNER_ABSTRACT.removeFinal();\n    }\n\n    private final TileEntityMobSpawner tileEntityMobSpawner;\n    private final IntFunction<Integer> delayChangeCallback;\n\n    public TileEntityMobSpawnerNotifier(TileEntityMobSpawner tileEntityMobSpawner, IntFunction<Integer> delayChangeCallback) {\n        this.tileEntityMobSpawner = tileEntityMobSpawner;\n        this.delayChangeCallback = delayChangeCallback;\n        this.position = tileEntityMobSpawner.getPosition();\n        this.world = tileEntityMobSpawner.getWorld();\n        MOB_SPAWNER_ABSTRACT.set(this, tileEntityMobSpawner.getSpawner());\n        updateDelay();\n    }\n\n    @Override\n    public void tick() {\n        MobSpawnerAbstract mobSpawnerAbstract = tileEntityMobSpawner.getSpawner();\n        int startDelay = mobSpawnerAbstract.spawnDelay;\n        try {\n            tileEntityMobSpawner.tick();\n        } finally {\n            int newDelay = mobSpawnerAbstract.spawnDelay;\n            if (newDelay > startDelay)\n                updateDelay();\n        }\n    }\n\n    public void updateDelay() {\n        MobSpawnerAbstract mobSpawnerAbstract = tileEntityMobSpawner.getSpawner();\n        mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport net.minecraft.server.v1_16_R3.MinecraftKey;\nimport net.minecraft.server.v1_16_R3.TileEntityTypes;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class BlockEntityCache {\n\n    private static final Map<Block, String> BLOCK_TO_ID = new IdentityHashMap<>();\n\n    private BlockEntityCache() {\n\n    }\n\n    public static String getTileEntityId(IBlockData blockData) {\n        return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> {\n            for (TileEntityTypes<?> tileEntityTypes : IRegistry.BLOCK_ENTITY_TYPE) {\n                if (tileEntityTypes.isValidBlock(block)) {\n                    MinecraftKey minecraftKey = TileEntityTypes.a(tileEntityTypes);\n                    if (minecraftKey != null)\n                        return minecraftKey.getKey();\n                }\n            }\n\n            return \"\";\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockStatesMapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport net.minecraft.server.v1_16_R3.IBlockState;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class BlockStatesMapper {\n\n    private static final Map<String, IBlockState<?>> nameToBlockState = new HashMap<>();\n    private static final Map<IBlockState<?>, String> blockStateToName = new HashMap<>();\n\n    static {\n        Map<String, String> fieldNameToName = new HashMap<>();\n        fieldNameToName.put(\"F\", \"axis-empty\");\n        fieldNameToName.put(\"N\", \"facing-notup\");\n        fieldNameToName.put(\"O\", \"facing-horizontal\");\n        fieldNameToName.put(\"S\", \"wall-east\");\n        fieldNameToName.put(\"T\", \"wall-north\");\n        fieldNameToName.put(\"U\", \"wall-south\");\n        fieldNameToName.put(\"V\", \"wall-west\");\n        fieldNameToName.put(\"W\", \"redstone-east\");\n        fieldNameToName.put(\"X\", \"redstone-north\");\n        fieldNameToName.put(\"Y\", \"redstone-south\");\n        fieldNameToName.put(\"Z\", \"redstone-west\");\n        fieldNameToName.put(\"aa\", \"double-half\");\n        fieldNameToName.put(\"ac\", \"track-shape-empty\");\n        fieldNameToName.put(\"ad\", \"track-shape\");\n        fieldNameToName.put(\"ae\", \"age1\");\n        fieldNameToName.put(\"af\", \"age2\");\n        fieldNameToName.put(\"ag\", \"age3\");\n        fieldNameToName.put(\"ah\", \"age5\");\n        fieldNameToName.put(\"ai\", \"age7\");\n        fieldNameToName.put(\"aj\", \"age15\");\n        fieldNameToName.put(\"ak\", \"age25\");\n        fieldNameToName.put(\"ar\", \"level3\");\n        fieldNameToName.put(\"as\", \"level8\");\n        fieldNameToName.put(\"at\", \"level1-8\");\n        fieldNameToName.put(\"av\", \"level15\");\n        fieldNameToName.put(\"an\", \"distance1-7\");\n        fieldNameToName.put(\"aB\", \"distance7\");\n        fieldNameToName.put(\"aF\", \"chest-type\");\n        fieldNameToName.put(\"aG\", \"comparator-mode\");\n        fieldNameToName.put(\"aJ\", \"piston-type\");\n        fieldNameToName.put(\"aK\", \"slab-type\");\n\n        try {\n            // Fixes BlockProperties being private-class in some versions of Yatopia causing illegal access errors.\n            Class<?> blockPropertiesClass = Class.forName(\"net.minecraft.server.v1_16_R3.BlockProperties\");\n\n            for (Field field : blockPropertiesClass.getFields()) {\n                field.setAccessible(true);\n                Object value = field.get(null);\n                if (value instanceof IBlockState) {\n                    register(fieldNameToName.getOrDefault(field.getName(), ((IBlockState<?>) value).getName()),\n                            field.getName(), (IBlockState<?>) value);\n                }\n            }\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while loading block states mapper:\");\n        }\n\n    }\n\n    private static void register(String key, String fieldName, IBlockState<?> blockState) {\n        if (nameToBlockState.containsKey(key)) {\n            Log.error(\"Block state \", key, \"(\", fieldName, \") already exists. Contact Ome_R!\");\n        } else {\n            nameToBlockState.put(key, blockState);\n            blockStateToName.put(blockState, key);\n        }\n    }\n\n    @Nullable\n    public static IBlockState<?> getBlockState(String name) {\n        return nameToBlockState.get(name);\n    }\n\n    @Nullable\n    public static String getBlockStateName(IBlockState<?> blockState) {\n        return blockStateToName.get(blockState);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.NextTickListEntry;\nimport net.minecraft.server.v1_16_R3.TickListServer;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState;\n\nimport java.lang.reflect.Modifier;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class BlockTickListServerTracker {\n\n    private static final ReflectField<Consumer<NextTickListEntry<Block>>> TICK_FUNCTION_SPIGOT =\n            new ReflectField<Consumer<NextTickListEntry<Block>>>(TickListServer.class,\n                    Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<Consumer<NextTickListEntry<Block>>> TICK_FUNCTION_PAPER =\n            new ReflectField<Consumer<NextTickListEntry<Block>>>(\n                    new ClassInfo(\"com.destroystokyo.paper.server.ticklist.PaperTickList\", ClassInfo.PackageType.UNKNOWN),\n                    Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private BlockTickListServerTracker() {\n\n    }\n\n    public static void listenForTicks(WorldServer worldServer) {\n        TickListServer<Block> blockTicks = worldServer.getBlockTickList();\n        if (TICK_FUNCTION_PAPER.isValid()) {\n            TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(worldServer, nextTickData));\n        } else {\n            TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(worldServer, nextTickData));\n        }\n    }\n\n    private static void tick(WorldServer worldServer, NextTickListEntry<Block> nextTickData) {\n        BlockPosition blockPosition = nextTickData.getPosition();\n        IBlockData blockState = worldServer.getType(blockPosition);\n        if (blockState.a(nextTickData.b())) {\n            IBlockData oldData = worldServer.getType(blockPosition);\n            try {\n                plugin.getGameEventsDispatcher().startCaptureEvents();\n                blockState.a(worldServer, blockPosition, worldServer.random);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in that tick.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            IBlockData newData = worldServer.getType(blockPosition);\n            if (oldData.getBlock() != newData.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(worldServer, blockPosition);\n                CraftBlockState oldState = CraftBlockState.getBlockState(worldServer, blockPosition, 3);\n                oldState.setData(oldData);\n                blockUpdateShapeEvent.oldState = oldState;\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.BlockStateBoolean;\nimport net.minecraft.server.v1_16_R3.BlockStateInteger;\nimport net.minecraft.server.v1_16_R3.Blocks;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.DataPaletteBlock;\nimport net.minecraft.server.v1_16_R3.Entity;\nimport net.minecraft.server.v1_16_R3.EnumSkyBlock;\nimport net.minecraft.server.v1_16_R3.GameProfileSerializer;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.LightEngine;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.NBTTagFloat;\nimport net.minecraft.server.v1_16_R3.NibbleArray;\nimport net.minecraft.server.v1_16_R3.SectionPosition;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.InventoryHolder;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ChunkReaderImpl implements ChunkReader {\n\n    private static final DataPaletteBlock<IBlockData> EMPTY_BLOCKS = new ChunkSection(0).getBlocks();\n    private static final byte[] EMPTY_LIGHT = new byte[2048];\n\n    private final int x;\n    private final int z;\n\n    private final Map<BlockPosition, CompoundTag> tileEntities = new HashMap<>();\n    private final List<CachedEntity> entities = new LinkedList<>();\n    private final DataPaletteBlock<IBlockData>[] blockids;\n    private final byte[][] skylight;\n    private final byte[][] emitlight;\n\n    public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n\n        ChunkCoordIntPair chunkCoords = chunk.getPos();\n        this.x = chunkCoords.x;\n        this.z = chunkCoords.z;\n\n        ChunkSection[] chunkSections = chunk.getSections();\n        this.blockids = new DataPaletteBlock[chunkSections.length];\n        this.skylight = new byte[chunkSections.length][];\n        this.emitlight = new byte[chunkSections.length][];\n\n        LightEngine lightEngine = chunk.world.getChunkProvider().getLightEngine();\n\n        for (int i = 0; i < this.blockids.length; ++i) {\n            ChunkSection chunkSection = chunkSections[i];\n\n            if (chunkSection == null) {\n                this.blockids[i] = EMPTY_BLOCKS;\n                this.skylight[i] = EMPTY_LIGHT;\n                this.emitlight[i] = EMPTY_LIGHT;\n            } else {\n                this.blockids[i] = copyDataPalette(chunkSection.getBlocks());\n\n                NibbleArray skyLightArray = lightEngine.a(EnumSkyBlock.SKY).a(SectionPosition.a(this.x, i, this.z));\n                if (skyLightArray == null) {\n                    this.skylight[i] = EMPTY_LIGHT;\n                } else {\n                    this.skylight[i] = new byte[2048];\n                    if (!skyLightArray.c())\n                        System.arraycopy(skyLightArray.asBytes(), 0, this.skylight[i], 0, 2048);\n                }\n\n                NibbleArray emitLightArray = lightEngine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(this.x, i, this.z));\n                if (emitLightArray == null) {\n                    this.emitlight[i] = EMPTY_LIGHT;\n                } else {\n                    this.emitlight[i] = new byte[2048];\n                    if (!emitLightArray.c())\n                        System.arraycopy(emitLightArray.asBytes(), 0, this.emitlight[i], 0, 2048);\n                }\n            }\n        }\n\n        chunk.getTileEntities().forEach((blockPosition, tileEntity) -> {\n            NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound());\n\n            tileEntityCompound.remove(\"x\");\n            tileEntityCompound.remove(\"y\");\n            tileEntityCompound.remove(\"z\");\n\n            InventoryHolder inventoryHolder = tileEntity.getOwner();\n            if (inventoryHolder != null)\n                tileEntityCompound.setString(\"inventoryType\", inventoryHolder.getInventory().getType().name());\n\n            tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound));\n        });\n\n        for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities())\n            entities.add(new CachedEntity(((CraftEntity) entity).getHandle()));\n    }\n\n    @Override\n    public int getX() {\n        return this.x;\n    }\n\n    @Override\n    public int getZ() {\n        return this.z;\n    }\n\n    @Override\n    public Material getType(int x, int y, int z) {\n        return CraftMagicNumbers.getMaterial(getBlockData(x, y, z).getBlock());\n    }\n\n    @Override\n    public short getData(int x, int y, int z) {\n        return CraftMagicNumbers.toLegacyData(getBlockData(x, y, z));\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag getTileEntity(int x, int y, int z) {\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.d((this.x << 4) + x, y, (this.z << 4) + z);\n            return this.tileEntities.get(blockPosition);\n        }\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag readBlockStates(int x, int y, int z) {\n        IBlockData blockData = getBlockData(x, y, z);\n\n        if (blockData.getStateMap().isEmpty())\n            return null;\n\n        CompoundTag compoundTag = CompoundTag.of();\n\n        blockData.getStateMap().forEach((blockState, value) -> {\n            Class<?> keyClass = blockState.getClass();\n            String name = BlockStatesMapper.getBlockStateName(blockState);\n\n            if (keyClass.equals(BlockStateBoolean.class)) {\n                compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0);\n            } else if (keyClass.equals(BlockStateInteger.class)) {\n                BlockStateInteger key = (BlockStateInteger) blockState;\n                compoundTag.setIntArray(name, new int[]{(Integer) value, key.min, key.max});\n            } else {\n                compoundTag.setString(name, ((Enum<?>) value).name());\n            }\n        });\n\n        return compoundTag;\n    }\n\n    @Override\n    public byte[] getLightLevels(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel};\n    }\n\n    @Override\n    public void forEachEntity(EntityConsumer consumer) {\n        if (entities.isEmpty())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = wrapper.getHandle();\n            for (CachedEntity cachedEntity : entities) {\n                location.setX(cachedEntity.x);\n                location.setY(cachedEntity.y);\n                location.setZ(cachedEntity.z);\n                location.setYaw(cachedEntity.yaw);\n                location.setPitch(cachedEntity.pitch);\n                consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location);\n            }\n        }\n    }\n\n    private IBlockData getBlockData(int x, int y, int z) {\n        return this.blockids[y >> 4].a(x, y & 15, z);\n    }\n\n    private static DataPaletteBlock<IBlockData> copyDataPalette(DataPaletteBlock<IBlockData> original) {\n        NBTTagCompound data = new NBTTagCompound();\n        original.a(data, \"Palette\", \"BlockStates\");\n\n        DataPaletteBlock<IBlockData> blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID,\n                GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData());\n        blockids.a(data.getList(\"Palette\", 10), data.getLongArray(\"BlockStates\"));\n\n        return blockids;\n    }\n\n    private static class CachedEntity {\n\n        private final double x;\n        private final double y;\n        private final double z;\n        private final float yaw;\n        private final float pitch;\n        private final EntityType entityType;\n        private final CompoundTag entityTag;\n\n        CachedEntity(Entity entity) {\n            this.x = entity.locX();\n            this.y = entity.locY();\n            this.z = entity.locZ();\n            this.yaw = entity.getBukkitYaw();\n            this.pitch = entity.pitch;\n            this.entityType = entity.getBukkitEntity().getType();\n\n            NBTTagCompound nbtTagCompound = new NBTTagCompound();\n            entity.save(nbtTagCompound);\n            nbtTagCompound.set(\"Yaw\", NBTTagFloat.a(entity.yaw));\n            nbtTagCompound.set(\"Pitch\", NBTTagFloat.a(entity.pitch));\n\n            this.entityTag = CompoundTag.fromNBT(nbtTagCompound);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class KeyBlocksCache {\n\n    private static final Map<Block, Key> BLOCK_TO_KEY = new IdentityHashMap<>();\n\n    private KeyBlocksCache() {\n\n    }\n\n    public static Key getBlockKey(Block block) {\n        return BLOCK_TO_KEY.computeIfAbsent(block, unused -> {\n            Material blockType = CraftMagicNumbers.getMaterial(block);\n            return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType);\n        });\n    }\n\n    public static void cacheAllBlocks() {\n        IRegistry.BLOCK.forEach(KeyBlocksCache::getBlockKey);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.HeightMap;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport org.bukkit.Location;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class WorldEditSessionDataImpl implements WorldEditSession.Data {\n\n    private static final boolean isStarLightInterface = ((Supplier<Boolean>) () -> {\n        try {\n            Class.forName(\"ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }).get();\n\n    private final List<PositionedObject<PositionedChunkData>> chunks = new LinkedList<>();\n    private final List<PositionedObject<IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<PositionedObject<CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<PositionedObject<Void>> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList();\n\n    public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks,\n                                    List<Pair<BlockPosition, IBlockData>> blocksToUpdate,\n                                    List<Pair<BlockPosition, CompoundTag>> blockEntities,\n                                    Set<ChunkCoordIntPair> lightenChunks) {\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // Convert chunk data\n        Iterator<Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData>> chunksIterator = chunks.entryIterator();\n        while (chunksIterator.hasNext()) {\n            Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData> entry = chunksIterator.next();\n            int currChunkPosXAxis = ChunkCoordIntPair.getX(entry.getKey());\n            int currChunkPosZAxis = ChunkCoordIntPair.getZ(entry.getKey());\n            WorldEditSessionImpl.ChunkData chunkData = entry.getValue();\n\n            List<PositionedObject<Void>> lights;\n            if (isStarLightInterface || chunkData.lights().isEmpty()) {\n                lights = Collections.emptyList();\n            } else {\n                lights = new LinkedList<>();\n                chunkData.lights().forEach(lightPosition -> {\n                    lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis,\n                            lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis,\n                            null));\n                });\n            }\n\n            PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(),\n                    chunkData.heightmaps(), lights);\n\n            this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis,\n                    currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData));\n        }\n\n        // Convert blocksToUpdate\n        blocksToUpdate.forEach(blockToUpdate -> {\n            BlockPosition blockPos = blockToUpdate.getKey();\n            this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis,\n                    blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis,\n                    blockToUpdate.getValue()));\n        });\n\n        // Convert blockEntities\n        blockEntities.forEach(blockEntity -> {\n            BlockPosition blockPos = blockEntity.getKey();\n            this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis,\n                    blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis,\n                    blockEntity.getValue()));\n        });\n\n        // Convert lights\n        lightenChunks.forEach(lightPosition -> {\n            this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis,\n                    lightPosition.z - baseChunkPosZAxis, null));\n        });\n    }\n\n    public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis,\n                           int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession,\n                           Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks) {\n        this.chunks.forEach(chunkDataPositioned -> {\n            long newPos = ChunkCoordIntPair.pair(baseChunkPosXAxis + chunkDataPositioned.xOffset,\n                    baseChunkPosZAxis + chunkDataPositioned.zOffset);\n\n            List<BlockPosition> lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>();\n            chunkDataPositioned.object.lights.forEach(lightPositioned -> {\n                lights.add(new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset,\n                        baseBlockPosYAxis + lightPositioned.yOffset,\n                        baseBlockPosZAxis + lightPositioned.zOffset));\n            });\n\n            chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections,\n                    chunkDataPositioned.object.heightmaps, lights));\n        });\n    }\n\n    public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, IBlockData>> blocksToUpdate) {\n        this.blocksToUpdate.forEach(blockToUpdatePositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset,\n                    baseBlockPosYAxis + blockToUpdatePositioned.yOffset,\n                    baseBlockPosZAxis + blockToUpdatePositioned.zOffset);\n            blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object));\n        });\n    }\n\n    public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, CompoundTag>> blockEntities) {\n        this.blockEntities.forEach(blockEntityPositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset,\n                    baseBlockPosYAxis + blockEntityPositioned.yOffset,\n                    baseBlockPosZAxis + blockEntityPositioned.zOffset);\n            blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object));\n        });\n    }\n\n    public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set<ChunkCoordIntPair> lightenChunks) {\n        this.lightenChunks.forEach(lightPositioned -> {\n            ChunkCoordIntPair newPos = new ChunkCoordIntPair(baseChunkPosXAxis + lightPositioned.xOffset,\n                    baseChunkPosZAxis + lightPositioned.zOffset);\n            lightenChunks.add(newPos);\n        });\n    }\n\n    private static class PositionedObject<V> {\n\n        private final int xOffset;\n        private final int yOffset;\n        private final int zOffset;\n        private final V object;\n\n        PositionedObject(int xOffset, int zOffset, V object) {\n            this(xOffset, 0, zOffset, object);\n        }\n\n        PositionedObject(int xOffset, int yOffset, int zOffset, V object) {\n            this.xOffset = xOffset;\n            this.yOffset = yOffset;\n            this.zOffset = zOffset;\n            this.object = object;\n        }\n\n    }\n\n    private static class PositionedChunkData {\n\n        private final ChunkSection[] chunkSections;\n        private final Map<HeightMap.Type, HeightMap> heightmaps;\n        private final List<PositionedObject<Void>> lights;\n\n        public PositionedChunkData(ChunkSection[] chunkSections,\n                                   Map<HeightMap.Type, HeightMap> heightmaps,\n                                   List<PositionedObject<Void>> lights) {\n            this.chunkSections = chunkSections;\n            this.heightmaps = heightmaps;\n            this.lights = lights;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.ByteTag;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.IntArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.google.common.base.Preconditions;\nimport net.minecraft.server.v1_16_R3.BiomeBase;\nimport net.minecraft.server.v1_16_R3.BiomeStorage;\nimport net.minecraft.server.v1_16_R3.Block;\nimport net.minecraft.server.v1_16_R3.BlockBed;\nimport net.minecraft.server.v1_16_R3.BlockPosition;\nimport net.minecraft.server.v1_16_R3.Chunk;\nimport net.minecraft.server.v1_16_R3.ChunkConverter;\nimport net.minecraft.server.v1_16_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_16_R3.ChunkSection;\nimport net.minecraft.server.v1_16_R3.ChunkStatus;\nimport net.minecraft.server.v1_16_R3.FluidType;\nimport net.minecraft.server.v1_16_R3.FluidTypes;\nimport net.minecraft.server.v1_16_R3.HeightMap;\nimport net.minecraft.server.v1_16_R3.IBlockData;\nimport net.minecraft.server.v1_16_R3.IBlockState;\nimport net.minecraft.server.v1_16_R3.IRegistry;\nimport net.minecraft.server.v1_16_R3.LightEngineThreaded;\nimport net.minecraft.server.v1_16_R3.NBTTagCompound;\nimport net.minecraft.server.v1_16_R3.ProtoChunk;\nimport net.minecraft.server.v1_16_R3.ProtoChunkTickList;\nimport net.minecraft.server.v1_16_R3.RegionLimitedWorldAccess;\nimport net.minecraft.server.v1_16_R3.TileEntity;\nimport net.minecraft.server.v1_16_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_16_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class WorldEditSessionImpl implements WorldEditSession {\n\n    private static final ObjectsPool<WorldEditSessionImpl> POOL = new ObjectsPool<>(WorldEditSessionImpl::new);\n\n    private static final ReflectField<BiomeBase[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            BiomeStorage.class, BiomeBase[].class, \"h\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final boolean isStarLightInterface = ((Supplier<Boolean>) () -> {\n        try {\n            Class.forName(\"ca.spottedleaf.starlight.common.light.StarLightInterface\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }).get();\n\n    private final Long2ObjectMapView<ChunkData> chunks = CollectionsFactory.createLong2ObjectHashMap();\n    private final List<Pair<BlockPosition, IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<Pair<BlockPosition, CompoundTag>> blockEntities = new LinkedList<>();\n    private final Set<ChunkCoordIntPair> lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet();\n\n    private Dimension dimension;\n\n    @Nullable\n    private WorldServer worldServer;\n\n    public static WorldEditSessionImpl obtain(WorldServer worldServer) {\n        return POOL.obtain().initialize(worldServer);\n    }\n\n    public static WorldEditSessionImpl obtain(Dimension dimension) {\n        return POOL.obtain().initialize(dimension);\n    }\n\n    private WorldEditSessionImpl() {\n    }\n\n    private WorldEditSessionImpl initialize(WorldServer worldServer) {\n        this.worldServer = worldServer;\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld());\n        return this;\n    }\n\n    private WorldEditSessionImpl initialize(Dimension dimension) {\n        this.worldServer = null;\n        this.dimension = dimension;\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag,\n                         @Nullable CompoundTag blockEntityData) {\n        BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n        if (!isValidPosition(blockPosition))\n            return;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (statesTag != null) {\n            for (Map.Entry<String, Tag<?>> entry : statesTag.entrySet()) {\n                try {\n                    // noinspection rawtypes\n                    IBlockState blockState = BlockStatesMapper.getBlockState(entry.getKey());\n                    if (blockState != null) {\n                        if (entry.getValue() instanceof ByteTag) {\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, ((ByteTag) entry.getValue()).getValue() == 1);\n                        } else if (entry.getValue() instanceof IntArrayTag) {\n                            int[] data = ((IntArrayTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, data[0]);\n                        } else if (entry.getValue() instanceof StringTag) {\n                            String data = ((StringTag) entry.getValue()).getValue();\n                            // noinspection unchecked\n                            blockData = blockData.set(blockState, Enum.valueOf(blockState.getType(), data));\n                        }\n                    }\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) ||\n                blockData.getBlock() instanceof BlockBed) {\n            blocksToUpdate.add(new Pair<>(blockPosition, blockData));\n            return;\n        }\n\n        ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(blockPosition);\n\n        if (blockEntityData != null)\n            blockEntities.add(new Pair<>(blockPosition, blockEntityData));\n\n        ChunkData chunkData = this.chunks.computeIfAbsent(chunkCoord.pair(), ChunkData::new);\n\n        if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockData.f() > 0)\n            chunkData.lights.add(blockPosition);\n\n        ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4];\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData, false);\n\n        chunkData.heightmaps.get(HeightMap.Type.MOTION_BLOCKING).a(blockX, blockY, blockZ, blockData);\n        chunkData.heightmaps.get(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES).a(blockX, blockY, blockZ, blockData);\n        chunkData.heightmaps.get(HeightMap.Type.OCEAN_FLOOR).a(blockX, blockY, blockZ, blockData);\n        chunkData.heightmaps.get(HeightMap.Type.WORLD_SURFACE).a(blockX, blockY, blockZ, blockData);\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#getAffectedChunks on partial initialized session\");\n\n        if (chunks.isEmpty())\n            return Collections.emptyList();\n\n        List<ChunkPosition> chunkPositions = new LinkedList<>();\n        World bukkitWorld = worldServer.getWorld();\n        LongIterator iterator = chunks.keyIterator();\n        while (iterator.hasNext()) {\n            long chunkKey = iterator.next();\n            int chunkX = (int) chunkKey;\n            int chunkZ = (int) (chunkKey >> 32);\n            chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false));\n        }\n        return chunkPositions;\n    }\n\n    @Override\n    public void applyBlocks(org.bukkit.Chunk bukkitChunk) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#applyBlocks on partial initialized session\");\n\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        ChunkCoordIntPair chunkCoord = chunk.getPos();\n\n        ChunkData chunkData = this.chunks.remove(chunkCoord.pair());\n\n        if (chunkData == null)\n            return;\n\n        int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length);\n        for (int i = 0; i < chunkSectionsCount; ++i) {\n            chunk.getSections()[i] = chunkData.chunkSections[i];\n        }\n\n        chunkData.heightmaps.forEach(((type, heightmap) -> {\n            chunk.a(type, heightmap.a());\n        }));\n\n        // Update the biome for the chunk\n        BiomeBase[] biomes = BIOME_BASE_ARRAY.get(chunk.getBiomeIndex());\n        if (biomes != null) {\n            IRegistry<BiomeBase> biomesRegistry = worldServer.r().b(IRegistry.ay);\n            BiomeBase biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(this.dimension));\n            Arrays.fill(biomes, biome);\n        }\n\n        if (plugin.getSettings().isLightsUpdate()) {\n            if (isStarLightInterface) {\n                this.lightenChunks.add(chunkCoord);\n            } else {\n                LightEngineThreaded lightEngineThreaded = worldServer.getChunkProvider().getLightEngine();\n                chunkData.lights.forEach(lightEngineThreaded::a);\n                // Queues chunk light for this chunk.\n                lightEngineThreaded.a(chunk, false);\n            }\n        }\n\n        chunk.setNeedsSaving(true);\n    }\n\n\n    @Override\n    public void finish(Island island) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#finish on partial initialized session\");\n\n        // Update blocks\n        blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3));\n\n        // Update block entities\n        blockEntities.forEach(data -> {\n            NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT();\n            if (blockEntityCompound != null) {\n                BlockPosition blockPosition = data.getKey();\n                blockEntityCompound.setInt(\"x\", blockPosition.getX());\n                blockEntityCompound.setInt(\"y\", blockPosition.getY());\n                blockEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition);\n                if (worldTileEntity != null)\n                    worldTileEntity.load(worldServer.getType(blockPosition), blockEntityCompound);\n            }\n        });\n\n        if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) {\n            LightEngineThreaded lightEngineThreaded = worldServer.getChunkProvider().getLightEngine();\n            lightEngineThreaded.relight(lightenChunks, chunkCallback -> {\n            }, completeCallback -> {\n            });\n            this.lightenChunks.clear();\n        }\n\n        release();\n    }\n\n    @Override\n    public Data readData(Location baseLocation) {\n        return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks);\n    }\n\n    @Override\n    public void applyData(Data data, Location baseLocation) {\n        WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data;\n\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // We need to transform all data to the new base location values\n\n        dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis,\n                baseBlockPosZAxis, this, this.chunks);\n        dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate);\n        dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities);\n        dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks);\n    }\n\n    @Override\n    public void release() {\n        this.chunks.clear();\n        this.blocksToUpdate.clear();\n        this.blockEntities.clear();\n        this.lightenChunks.clear();\n        this.worldServer = null;\n        this.dimension = null;\n        POOL.release(this);\n    }\n\n    public ChunkData createChunkData(ChunkSection[] chunkSections, Map<HeightMap.Type, HeightMap> heightmaps, List<BlockPosition> lights) {\n        return new ChunkData(chunkSections, heightmaps, lights);\n    }\n\n    private boolean isValidPosition(BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < 256;\n    }\n\n    public class ChunkData {\n\n        private final ChunkSection[] chunkSections;\n        private final Map<HeightMap.Type, HeightMap> heightmaps;\n        private final List<BlockPosition> lights;\n\n        private ChunkData(long chunkKey) {\n            this(new ChunkSection[16], new EnumMap<>(HeightMap.Type.class), new LinkedList<>());\n\n            ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkKey);\n\n            createChunkSections();\n\n            ProtoChunkTickList<Block> blockTickScheduler = new ProtoChunkTickList<>(block -> {\n                return block == null || block.getBlockData().isAir();\n            }, chunkCoord);\n            ProtoChunkTickList<FluidType> fluidTickScheduler = new ProtoChunkTickList<>((fluid) -> {\n                return fluid == null || fluid == FluidTypes.EMPTY;\n            }, chunkCoord);\n\n            ProtoChunk tempChunk;\n\n            try {\n                tempChunk = new ProtoChunk(chunkCoord, ChunkConverter.a, this.chunkSections, blockTickScheduler, fluidTickScheduler, worldServer);\n            } catch (Throwable error) {\n                tempChunk = new ProtoChunk(chunkCoord, ChunkConverter.a, this.chunkSections, blockTickScheduler, fluidTickScheduler);\n            }\n\n            createHeightmaps(tempChunk);\n            if (worldServer != null)\n                runCustomWorldGenerator(tempChunk);\n        }\n\n        private ChunkData(ChunkSection[] chunkSections, Map<HeightMap.Type, HeightMap> heightmaps, List<BlockPosition> lights) {\n            this.chunkSections = chunkSections;\n            this.heightmaps = heightmaps;\n            this.lights = lights;\n        }\n\n        public ChunkSection[] chunkSections() {\n            return this.chunkSections;\n        }\n\n        public Map<HeightMap.Type, HeightMap> heightmaps() {\n            return this.heightmaps;\n        }\n\n        public List<BlockPosition> lights() {\n            return this.lights;\n        }\n\n        private void createChunkSections() {\n            for (int i = 0; i < this.chunkSections.length; ++i) {\n                int chunkSectionPos = i << 4;\n\n                try {\n                    this.chunkSections[i] = new ChunkSection(chunkSectionPos, null, worldServer, true);\n                } catch (Throwable error) {\n                    this.chunkSections[i] = new ChunkSection(chunkSectionPos);\n                }\n            }\n        }\n\n        private void runCustomWorldGenerator(ProtoChunk tempChunk) {\n            ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator();\n\n            if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n                return;\n\n            CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer,\n                    worldServer.getChunkProvider().getChunkGenerator(),\n                    bukkitGenerator);\n\n            RegionLimitedWorldAccess region = new RegionLimitedWorldAccess(worldServer, Collections.singletonList(tempChunk));\n\n            chunkGenerator.buildBase(region, tempChunk);\n\n            // We want to copy the level chunk sections back\n            ChunkSection[] tempChunkSections = tempChunk.getSections();\n            for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) {\n                ChunkSection chunkSection = tempChunkSections[i];\n                if (chunkSection != null && chunkSection != Chunk.a)\n                    this.chunkSections[i] = chunkSection;\n            }\n        }\n\n        private void createHeightmaps(ProtoChunk tempChunk) {\n            for (HeightMap.Type heightmapType : HeightMap.Type.values()) {\n                if (ChunkStatus.FULL.h().contains(heightmapType)) {\n                    this.heightmaps.put(heightmapType, new HeightMap(tempChunk, heightmapType));\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ngroup 'NMS:v1_17'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.17.1-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot\")\n    compileOnly project(\":NMS:Paper\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_17') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_17\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_17/properties",
    "content": "NMS_VERSION=v1_17\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_17_R1\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.Registry\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=java.util.Random\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17;\n\nimport com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment;\nimport net.minecraft.core.Registry;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms {\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        try {\n            return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH));\n        } catch (IllegalArgumentException e) {\n            return null;\n        }\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        Enchantment glowEnchant;\n\n        try {\n            glowEnchant = new PaperGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        } catch (Throwable error) {\n            glowEnchant = new SpigotGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        }\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Registry;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.chunk.ChunkBiomeContainer;\nimport net.minecraft.world.level.chunk.ChunkStatus;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;\nimport org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSChunks {\n\n    private static final ReflectField<Biome[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            ChunkBiomeContainer.class, Biome[].class, \"f\");\n    private static final ReflectField<ChunkBiomeContainer> CHUNK_BIOME_CONTAINER = new ReflectField<>(\n            LevelChunk.class, ChunkBiomeContainer.class, Modifier.PRIVATE, 1);\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n                Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n                Biome[] biomes = BIOME_BASE_ARRAY.get(levelChunk.getBiomes());\n\n                if (biomes == null)\n                    throw new RuntimeException(\"Error while receiving biome bases of chunk (\" + chunkPos.x + \",\" + chunkPos.z + \").\");\n\n                Arrays.fill(biomes, biome);\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z);\n                //noinspection deprecation\n                ClientboundLevelChunkPacket levelChunkPacket = new ClientboundLevelChunkPacket(levelChunk);\n                ClientboundLightUpdatePacket lightUpdatePacket = new ClientboundLightUpdatePacket(chunkPos,\n                        levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(lightUpdatePacket);\n                    serverPlayer.connection.send(levelChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                if (!chunkCompound.contains(\"Level\", 10))\n                    return;\n\n                CompoundTag unloadedChunk = chunkCompound.getCompound(\"Level\");\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n                Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                int[] biomes = unloadedChunk.contains(\"Biomes\", 11) ? unloadedChunk.getIntArray(\"Biomes\") : new int[256];\n                Arrays.fill(biomes, biomesRegistry.getId(biome));\n                unloadedChunk.putIntArray(\"Biomes\", biomes);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Arrays.fill(levelChunk.getSections(), LevelChunk.EMPTY_SECTION);\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                if (!chunkCompound.contains(\"Level\", 10))\n                    return;\n\n                CompoundTag unloadedChunk = chunkCompound.getCompound(\"Level\");\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                ListTag sectionsList = new ListTag();\n                ListTag tileEntities = new ListTag();\n\n                unloadedChunk.put(\"Sections\", sectionsList);\n                unloadedChunk.put(\"TileEntities\", tileEntities);\n                unloadedChunk.put(\"Entities\", new ListTag());\n\n                if (!(serverLevel.generator instanceof IslandsGenerator)) {\n                    ChunkPos chunkPos = unloadedChunkCompound.chunkPos();\n\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkPos, serverLevel);\n\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] levelChunkSections = protoChunk.getSections();\n\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        for (LevelChunkSection levelChunkSection : levelChunkSections) {\n                            if (levelChunkSection != LevelChunk.EMPTY_SECTION && levelChunkSection.bottomBlockY() >> 4 == i) {\n                                CompoundTag sectionCompound = new CompoundTag();\n                                sectionCompound.putByte(\"Y\", (byte) (i & 255));\n                                levelChunkSection.getStates().write(sectionCompound, \"Palette\", \"BlockStates\");\n                                sectionsList.add(sectionCompound);\n                            }\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.getBlockEntitiesPos()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbt(blockEntityPos);\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                if (!chunkCompound.contains(\"Level\", 10))\n                    return;\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                CompoundTag unloadedChunk = chunkCompound.getCompound(\"Level\");\n\n                ListTag sectionsList = unloadedChunk.getList(\"Sections\", 10);\n                LevelChunkSection[] levelChunkSections = new LevelChunkSection[sectionsList.size()];\n\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    if (sectionCompound.contains(\"Palette\", 9) && sectionCompound.contains(\"BlockStates\", 12)) {\n                        //noinspection deprecation\n                        LevelChunkSection levelChunkSection = levelChunkSections[i] = new LevelChunkSection(yPosition);\n                        levelChunkSection.getStates().read(sectionCompound.getList(\"Palette\", 10),\n                                sectionCompound.getLongArray(\"BlockStates\"));\n                        levelChunkSection.recalcBlockCounts();\n                    }\n                }\n\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, levelChunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                if (!chunkCompound.contains(\"Level\", 10))\n                    return;\n\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getCompound(\"Level\")\n                                .getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(LevelChunk levelChunk) {\n        ServerLevel serverLevel = levelChunk.level;\n\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) {\n            CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                    serverLevel.getChunkSource().getGenerator(),\n                    bukkitGenerator);\n\n            WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(levelChunk),\n                    ChunkStatus.SURFACE, 0);\n\n            try {\n                chunkGenerator.buildSurface(region, levelChunk);\n            } catch (ClassCastException error) {\n                ProtoChunk protoChunk = NMSUtils.createProtoChunk(levelChunk.getPos(), serverLevel);\n                chunkGenerator.buildSurface(region, protoChunk);\n\n                // Load chunk sections from proto chunk to the actual chunk\n                for (int i = 0; i < protoChunk.getSections().length && i < levelChunk.getSections().length; ++i) {\n                    levelChunk.getSections()[i] = protoChunk.getSections()[i];\n                }\n\n                // Load biomes from proto chunk to the actual chunk\n                if (protoChunk.getBiomes() != null)\n                    CHUNK_BIOME_CONTAINER.set(levelChunk, protoChunk.getBiomes());\n\n                // Load tile entities from proto chunk to the actual chunk\n                protoChunk.getBlockEntities().forEach(((blockPosition, tileEntity) -> levelChunk.setBlockEntity(tileEntity)));\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.v1_17_R1.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(\n            Entity.class, int.class, Modifier.PROTECTED, 2);\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        return PORTAL_TICKS.get(entity);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSTags {\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.of(compoundTag);\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.setTag(compoundTag);\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.vibration.IslandSculkSensorBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.world.BlockServerTickListTracker;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_17_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSWorld {\n\n    private static boolean alreadyWarned = false;\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.messages;\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.delegate;\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.get();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n        serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos());\n\n        serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        BlockServerTickListTracker.listenForTicks(serverLevel);\n        if (!alreadyWarned) {\n            Log.warn(\"This version is old and you may experience issues with block changes detection\");\n            alreadyWarned = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_17.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_17.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData,\n                                        @Nullable CompoundTag entityNbt) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_17.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.utils.TickingBlockList;\nimport com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl;\nimport com.google.common.base.Suppliers;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Registry;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.NbtUtils;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkStatus;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.ProtoTickList;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.material.Fluid;\nimport net.minecraft.world.level.material.Fluids;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_17_R1.CraftWorld;\nimport org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final ReflectField<IOWorker> ENTITY_STORAGE_WORKER = new ReflectField<>(\n            EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n    private static final ReflectMethod<CompletableFuture<CompoundTag>> WORKER_LOAD_ASYNC = new ReflectMethod<>(\n            IOWorker.class, CompletableFuture.class, 1, ChunkPos.class);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException {\n        return chunkMap.read(chunkPos);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException {\n        return chunkMap.getChunkData(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        return BukkitExecutor.createTask().runSync(v -> {\n            chunks.forEach(chunkPosition -> {\n                ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage);\n\n                ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> {\n                    if (error != null) {\n                        countDownLatch.countDown();\n                        throw new RuntimeException(error);\n                    } else {\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                        } else {\n                            NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                            chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                        }\n                    }\n                });\n            });\n        });\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        try {\n            return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel);\n        } catch (Throwable ex) {\n            //noinspection deprecation\n            return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel);\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        ProtoTickList<Block> blockTickScheduler = new ProtoTickList<>(block -> {\n            return block == null || block.defaultBlockState().isAir();\n        }, chunkPos, levelHeightAccessor);\n        ProtoTickList<Fluid> fluidTickScheduler = new ProtoTickList<>((fluid) -> {\n            return fluid == null || fluid == Fluids.EMPTY;\n        }, chunkPos, levelHeightAccessor);\n\n        try {\n            return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor, serverLevel);\n        } catch (Throwable error) {\n            return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor);\n        }\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.getMaterial().isLiquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.isEmpty();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.load(compoundTag);\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.relight(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        if (compoundTag.getByte(\"SSB.HasSignLines\") == 1) {\n            // We want to convert the sign lines from raw string to json\n            for (int i = 1; i <= 4; ++i) {\n                String line = compoundTag.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(line)) {\n                    Component newLine = CraftChatMessage.fromString(line)[0];\n                    compoundTag.putString(\"Text\" + i, Component.Serializer.toJson(newLine));\n                }\n            }\n        }\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<DimensionType> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = DimensionType.NETHER_LOCATION;\n            case THE_END -> resourceKey = DimensionType.END_LOCATION;\n            default -> resourceKey = DimensionType.OVERWORLD_LOCATION;\n        }\n\n        Registry<DimensionType> registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY);\n        return registry.getOrThrow(resourceKey);\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        for (int i = 0; i < chunkSections.length; ++i) {\n            int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i);\n\n            try {\n                chunkSections[i] = new LevelChunkSection(chunkSectionPos, null, serverLevel, true);\n            } catch (Throwable error) {\n                chunkSections[i] = new LevelChunkSection(chunkSectionPos);\n            }\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ProtoChunk protoChunk) {\n        CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk),\n                ChunkStatus.SURFACE, 0);\n\n        chunkGenerator.buildSurface(region, protoChunk);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new LevelChunkSection(0).getStates();\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        CompoundTag data = new CompoundTag();\n        original.write(data, \"Palette\", \"BlockStates\");\n\n        PalettedContainer<BlockState> blockids = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE,\n                Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState,\n                Blocks.AIR.defaultBlockState(), null, false);\n        blockids.read(data.getList(\"Palette\", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray(\"BlockStates\"));\n\n        return blockids;\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.save(new CompoundTag());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile);\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.tickingList.size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.tickingList.getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.getValue();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.dragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer));\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.GameEventListener;\n\nimport javax.annotation.Nullable;\n\npublic class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n\n    public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState());\n        this.island = island;\n    }\n\n    @Override\n    public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) {\n        if (!super.shouldListen(world, listener, pos, event, entity))\n            return false;\n\n        if (entity instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.world;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.ServerTickList;\nimport net.minecraft.world.level.TickNextTickData;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockStates;\n\nimport java.lang.reflect.Modifier;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class BlockServerTickListTracker {\n\n    private static final ReflectField<Consumer<TickNextTickData<Block>>> TICK_FUNCTION_SPIGOT =\n            new ReflectField<Consumer<TickNextTickData<Block>>>(ServerTickList.class,\n                    Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<Consumer<TickNextTickData<Block>>> TICK_FUNCTION_PAPER =\n            new ReflectField<Consumer<TickNextTickData<Block>>>(\n                    new ClassInfo(\"com.destroystokyo.paper.server.ticklist.PaperTickList\", ClassInfo.PackageType.UNKNOWN),\n                    Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private BlockServerTickListTracker() {\n\n    }\n\n    public static void listenForTicks(ServerLevel serverLevel) {\n        ServerTickList<Block> blockTicks = serverLevel.getBlockTicks();\n        if (TICK_FUNCTION_PAPER.isValid()) {\n            TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData));\n        } else {\n            TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData));\n        }\n    }\n\n    private static void tick(ServerLevel serverLevel, TickNextTickData<Block> nextTickData) {\n        BlockState blockState = serverLevel.getBlockState(nextTickData.pos);\n        if (blockState.is(nextTickData.getType())) {\n            BlockState oldState = serverLevel.getBlockState(nextTickData.pos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                blockState.tick(serverLevel, nextTickData.pos, serverLevel.random);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = serverLevel.getBlockState(nextTickData.pos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(serverLevel, nextTickData.pos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(nextTickData.pos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_17.world;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ngroup 'NMS:v1_18'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.18.2-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot\")\n    compileOnly project(\":NMS:Paper\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_18') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_18\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_18/properties",
    "content": "NMS_VERSION=v1_18\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_18_R2\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.Registry\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=java.util.Random\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18;\n\nimport com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment;\nimport net.minecraft.core.Registry;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms {\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        try {\n            return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH));\n        } catch (IllegalArgumentException e) {\n            return null;\n        }\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        Enchantment glowEnchant;\n\n        try {\n            glowEnchant = new PaperGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        } catch (Throwable error) {\n            glowEnchant = new SpigotGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        }\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n                Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.bottomBlockY() >> 4,\n                                currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n                Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codec(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow(false, error -> {\n                });\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(levelChunk.level.getSectionYFromSectionIndex(i), biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codec(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow(false, error -> {\n                    });\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n                    Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codec(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos);\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codec(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codec(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.v1_18_R2.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(\n            Entity.class, int.class, Modifier.PROTECTED, 2);\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        return PORTAL_TICKS.get(entity);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSTags {\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.of(compoundTag);\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.setTag(compoundTag);\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.vibration.IslandSculkSensorBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.world.BlockLevelTicksTracker;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_18_R2.CraftWorld;\nimport org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSWorld {\n\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    private static boolean alreadyWarned = false;\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.messages;\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.delegate;\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.structureSets, original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n        serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos());\n\n        serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n        if (!alreadyWarned) {\n            Log.warn(\"This version is old and you may experience issues with block changes detection\");\n            alreadyWarned = true;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_18.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_18.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData,\n                                        @Nullable CompoundTag entityNbt) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_18.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_18.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.ChunkStatus;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_18_R2.CraftWorld;\nimport org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final ReflectField<IOWorker> ENTITY_STORAGE_WORKER = new ReflectField<>(\n            EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n    private static final ReflectMethod<CompletableFuture<CompoundTag>> WORKER_LOAD_ASYNC = new ReflectMethod<>(\n            IOWorker.class, CompletableFuture.class, 1, ChunkPos.class);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException {\n        return chunkMap.read(chunkPos);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        return BukkitExecutor.createTask().runSync(v -> {\n            chunks.forEach(chunkPosition -> {\n                ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage);\n\n                ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> {\n                    if (error != null) {\n                        countDownLatch.countDown();\n                        throw new RuntimeException(error);\n                    } else {\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                        } else {\n                            NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                            chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                        }\n                    }\n                });\n            });\n        });\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.getMaterial().isLiquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.load(compoundTag);\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.relight(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        if (compoundTag.getByte(\"SSB.HasSignLines\") == 1) {\n            // We want to convert the sign lines from raw string to json\n            for (int i = 1; i <= 4; ++i) {\n                String line = compoundTag.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(line)) {\n                    Component newLine = CraftChatMessage.fromString(line)[0];\n                    compoundTag.putString(\"Text\" + i, Component.Serializer.toJson(newLine));\n                }\n            }\n        }\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<DimensionType> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = DimensionType.NETHER_LOCATION;\n            case THE_END -> resourceKey = DimensionType.END_LOCATION;\n            default -> resourceKey = DimensionType.OVERWORLD_LOCATION;\n        }\n\n        Registry<DimensionType> registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY);\n        return registry.getOrThrow(resourceKey);\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);\n\n        Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry,\n                IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i);\n\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess),\n                ChunkStatus.SURFACE, 0);\n\n        chunkGenerator.buildSurface(region,\n                serverLevel.structureFeatureManager().forWorldGenRegion(region),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata();\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile);\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.tickingList.size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.tickingList.getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.getValue();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.dragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.setUnsaved(true);\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer));\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.GameEventListener;\n\nimport javax.annotation.Nullable;\n\npublic class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n\n    public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState());\n        this.island = island;\n    }\n\n    @Override\n    public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) {\n        if (!super.shouldListen(world, listener, pos, event, entity))\n            return false;\n\n        if (entity instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ChunkHolder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> isPositionTickingWithEntitiesLoaded(serverLevel, chunkPos),\n                serverLevel.getProfilerSupplier());\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoaded(ServerLevel serverLevel, long chunkPos) {\n        ChunkHolder chunkHolder = serverLevel.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady() && serverLevel.areEntitiesLoaded(chunkPos);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_18.world;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ngroup 'NMS:v1_19'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.19.4-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot\")\n    compileOnly project(\":NMS:Paper\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_19') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_19\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_19/properties",
    "content": "NMS_VERSION=v1_19\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_19_R3\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19;\n\nimport com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms {\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        Enchantment glowEnchant;\n\n        try {\n            glowEnchant = new PaperGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        } catch (Throwable error) {\n            glowEnchant = new SpigotGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        }\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.bottomBlockY() >> 4,\n                                currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow(false, error -> {\n                });\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(levelChunk.level.getSectionYFromSectionIndex(i), biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow(false, error -> {\n                    });\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos);\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.v1_19_R3.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(\n            Entity.class, int.class, Modifier.PROTECTED, 2);\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        return PORTAL_TICKS.get(entity);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSTags {\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.of(compoundTag);\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.setTag(compoundTag);\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.vibration.IslandSculkSensorBlockEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.v1_19_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSWorld {\n\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.messages;\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity)\n            return;\n\n        ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle();\n        serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos());\n\n        serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_19.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_19.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData,\n                                        @Nullable CompoundTag entityNbt) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_19.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_19.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.ChunkStatus;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_19_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<IOWorker> ENTITY_STORAGE_WORKER = new ReflectField<>(\n            EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        CompoundTag entityData = serverLevel.entityDataControllerNew.readData(\n                                chunkPosition.getX(), chunkPosition.getZ());\n\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                            return;\n                        }\n\n                        NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                        chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().registryOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.getMaterial().isLiquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.load(compoundTag);\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.relight(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        if (compoundTag.getByte(\"SSB.HasSignLines\") == 1) {\n            // We want to convert the sign lines from raw string to json\n            for (int i = 1; i <= 4; ++i) {\n                String line = compoundTag.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(line)) {\n                    Component newLine = CraftChatMessage.fromString(line)[0];\n                    compoundTag.putString(\"Text\" + i, Component.Serializer.toJson(newLine));\n                }\n            }\n        }\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBlock.biomeToBiomeBase(biomesRegistry,\n                IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i);\n\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess),\n                ChunkStatus.SURFACE, 0);\n\n        chunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata();\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile);\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.tickingList.size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.tickingList.getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.getValue();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.dragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.setUnsaved(true);\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer));\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.GameEventListener;\n\nimport javax.annotation.Nullable;\n\npublic class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n\n    public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState());\n        this.island = island;\n    }\n\n    @Override\n    public boolean shouldListen(ServerLevel world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable GameEvent.Context context) {\n        if (!super.shouldListen(world, listener, pos, event, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos),\n                serverLevel.getProfilerSupplier());\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"io.papermc.paper.chunk.system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_19.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n\ngroup 'NMS:v1_20_3'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.20.4-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_20\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_20_3/properties",
    "content": "NMS_VERSION=v1_20_3\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_20_R3\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.PaperGlowEnchantment;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.SpigotGlowEnchantment;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_20_R3.CraftRegistry;\nimport org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms {\n\n    private static final ReflectField<Map<NamespacedKey, Enchantment>> REGISTRY_CACHE =\n            new ReflectField<>(CraftRegistry.class, Map.class, \"cache\");\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n    private static Enchantment initializeGlowEnchantment() {\n        Enchantment glowEnchant;\n\n        try {\n            glowEnchant = new PaperGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        } catch (Throwable error) {\n            glowEnchant = new SpigotGlowEnchantment(\"superiorskyblock_glowing_enchant\");\n        }\n\n        Map<NamespacedKey, Enchantment> registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT);\n\n        registryCache.put(glowEnchant.getKey(), glowEnchant);\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome;\nimport org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow(false, error -> {\n                });\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow(false, error -> {\n                    });\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow(false, error -> {\n                                }));\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos);\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow(false, error -> {\n                            });\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.v1_20_R3.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(\n            Entity.class, int.class, Modifier.PROTECTED, 2);\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        return PORTAL_TICKS.get(entity);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSTags {\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.of(compoundTag);\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.setTag(compoundTag);\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.v1_20_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData,\n                                        @Nullable CompoundTag entityNbt) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.ChunkStatus;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_20_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<IOWorker> ENTITY_STORAGE_WORKER = new ReflectField<>(\n            EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        CompoundTag entityData = serverLevel.entityDataControllerNew.readData(\n                                chunkPosition.getX(), chunkPosition.getZ());\n\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                            return;\n                        }\n\n                        NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                        chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().registryOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.load(compoundTag);\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.relight(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess),\n                ChunkStatus.SURFACE, 0);\n\n        chunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata();\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.tickingList.size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.tickingList.getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.setUnsaved(true);\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer));\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        if (blockEntityCompound.contains(key)) {\n            CompoundTag frontText = blockEntityCompound.getCompound(key);\n            ListTag messages = frontText.getList(\"messages\", net.minecraft.nbt.Tag.TAG_STRING);\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT));\n        }\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent gameEvent, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, gameEvent, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(GameEvent gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos),\n                serverLevel.getProfilerSupplier());\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"io.papermc.paper.chunk.system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_3.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_20_4'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.20.6-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_20\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_20_4/properties",
    "content": "NMS_VERSION=v1_20_4\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4;\n\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms {\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess());\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(\n            Entity.class, int.class, Modifier.PROTECTED, 2);\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        return PORTAL_TICKS.get(entity);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSTags {\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                itemStack.save(MinecraftServer.getServer().registryAccess());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @javax.annotation.Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<IOWorker> ENTITY_STORAGE_WORKER = new ReflectField<>(\n            EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        CompoundTag entityData = serverLevel.entityDataControllerNew.readData(\n                                chunkPosition.getX(), chunkPosition.getZ());\n\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                            return;\n                        }\n\n                        NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                        chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().registryOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess());\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.relight(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess),\n                ChunkStatus.SURFACE, 0);\n\n        chunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.tickingList.size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.tickingList.getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) {\n        if (blockEntityCompound.contains(key)) {\n            net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key);\n            ListTag messages = frontText.getList(\"messages\", net.minecraft.nbt.Tag.TAG_STRING);\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT));\n        }\n    }\n\n    private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.setUnsaved(true);\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return MinecraftServer.getServer().getPlayerList().load(serverPlayer);\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos),\n                serverLevel.getProfilerSupplier());\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"io.papermc.paper.chunk.system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_20_4.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.1-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21/properties",
    "content": "NMS_VERSION=v1_21\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21;\n\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms {\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess());\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.setUnsaved(true);\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getHolderOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21;\n\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport net.minecraft.world.item.Items;\nimport net.minecraft.world.item.crafting.Ingredient;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSEntities {\n\n    private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL);\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem));\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSTags {\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                itemStack.save(MinecraftServer.getServer().registryAccess());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner = new TrialSpawner(\n                    trialSpawner.normalConfig,\n                    trialSpawner.ominousConfig,\n                    trialSpawner.getData(),\n                    trialSpawner.getTargetCooldownLength(),\n                    trialSpawner.getRequiredPlayerRange(),\n                    trialSpawner.stateAccessor,\n                    IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector),\n                    trialSpawner.getEntitySelector()\n            );\n        }\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.MobSpawnType;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @javax.annotation.Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        MobSpawnType spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.utils;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.IOWorker;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException {\n        chunkMap.write(chunkPos, chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        net.minecraft.nbt.CompoundTag entityData = serverLevel.moonrise$getEntityChunkDataController()\n                                .readData(chunkPosition.getX(), chunkPosition.getZ());\n\n                        if (entityData == null) {\n                            chunkCallback.onChunkNotExist(chunkPosition);\n                            return;\n                        }\n\n                        NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                        chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().registryOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess());\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSection();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinBuildHeight();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxBuildHeight();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.setUnsaved(true);\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return MinecraftServer.getServer().getPlayerList().load(serverPlayer);\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        if (blockEntityCompound.contains(key)) {\n            CompoundTag frontText = blockEntityCompound.getCompound(key);\n            ListTag messages = frontText.getList(\"messages\", net.minecraft.nbt.Tag.TAG_STRING);\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT));\n        }\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos),\n                serverLevel.getProfilerSupplier());\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder =\n                serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_10'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.11-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_10/properties",
    "content": "NMS_VERSION=v1_21_10\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart\nGET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParseException;\nimport com.mojang.serialization.JsonOps;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.ComponentSerialization;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms {\n\n    public static final ReflectField<double[]> SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class,\n            double[].class, Modifier.PUBLIC | Modifier.FINAL, 1);\n\n    private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create();\n\n    @Override\n    public String parseSignLine(String original) {\n        RegistryOps<JsonElement> context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE);\n        JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0])\n                .getOrThrow(JsonParseException::new);\n        return COMPONENT_GSON.toJson(jsonElement);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0];\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.logging.LogUtils;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\nimport static com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSChunks {\n\n    private static final ReflectMethod<Codec<PalettedContainer<Holder<Biome>>>> CONTAINER_FACTORY_BIOME_RW_CODEC =\n            new ReflectMethod<>(PalettedContainerFactory.class, \"biomeContainerCodecRW\");\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                DataResult<Tag> dataResult = getBiomeContainerRWCodec()\n                        .encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"biomes\", biomesCompound));\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                    DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                            .encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"block_states\", blockStatesCompound));\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i);\n                    byte yPosition = sectionCompound.getByteOr(\"Y\", (byte) 0);\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        Optional<CompoundTag> blockStatesCompound = sectionCompound.getCompound(\"block_states\");\n                        if (blockStatesCompound.isPresent()) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY\n                                    .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        Optional<CompoundTag> biomesCompound = sectionCompound.getCompound(\"biomes\");\n                        if (biomesCompound.isPresent()) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = getBiomeContainerRWCodec()\n                                    .parse(NbtOps.INSTANCE, biomesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes();\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty(\"Entities\");\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getIntOr(\"DataVersion\", 0);\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag);\n            return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL);\n        }\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n    private static Codec<PalettedContainer<Holder<Biome>>> getBiomeContainerRWCodec() {\n        if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) {\n            return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY);\n        } else {\n            return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec();\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.google.common.collect.HashMultimap;\nimport com.google.common.collect.Multimap;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.util.Util;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.slf4j.Logger;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSTags {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        Multimap<String, Property> properties = HashMultimap.create();\n        properties.put(\"textures\", new Property(\"textures\", texture));\n\n        GameProfile gameProfile = new GameProfile(Util.NIL_UUID, \"\", new PropertyMap(properties));\n\n        ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        RegistryOps<Tag> context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow();\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION);\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.getIntOr(key, def);\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        RegistryOps<Tag> context =\n                MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        return ItemStack.CODEC.parse(context, compoundTag)\n                .resultOrPartial((itemId) -> LOGGER.error(\"Tried to load invalid item: '{}'\", itemId))\n                .orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).byteValue();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).keySet();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).doubleValue();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).floatValue();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).intValue();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).longValue();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).shortValue();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).value();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<CollectingNeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<CollectingNeighborUpdater>(\n            Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime());\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector));\n        }\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\nimport net.minecraft.world.level.storage.ValueInput;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        super.readAdditionalSaveData(input);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram;\n\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.level.storage.ValueOutput;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void load(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.Identifier;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.Strategy;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.TagValueOutput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create(\n            MinecraftServer.getServer().registryAccess());\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(chunkCompoundTag);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if (readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                DEFAULT_PALETTED_CONTAINER_FACTORY,\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(),\n                new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"block_entity@\" + blockEntity.getBlockPos(), LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag);\n            blockEntity.loadWithComponents(valueInput);\n        }\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = createBiomesContainer(biome);\n            PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"cached_entity@\" + entity.getUUID(), LOGGER)) {\n            TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess());\n            entity.save(valueOutput);\n            return valueOutput.buildResult();\n        }\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.properties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absSnapTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static PalettedContainer<Holder<Biome>> createBiomesContainer(Holder<Biome> biome) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        Strategy<Holder<Biome>> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap());\n        return new PalettedContainerFactory(\n                null,\n                null,\n                null,\n                biomesStrategy,\n                biome,\n                null,\n                null\n        ).createForBiomes();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) {\n            return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId())\n                    .map(playerData -> {\n                        ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData);\n                        serverPlayer.load(valueInput);\n                        return playerData;\n                    });\n        }\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLongOr(key, def);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        blockEntityCompound.getCompound(key).ifPresent(textCompound -> {\n            ListTag messages = textCompound.getListOrEmpty(\"messages\");\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]);\n                }\n            }\n\n            for (int i = 0; i < 4; i++) {\n                if (textLines.get(i) == null)\n                    textLines.set(i, Component.empty());\n            }\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(nbt -> blockEntityCompound.put(key, nbt));\n        });\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static Identifier getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(serverLevel::isPositionTickingWithEntitiesLoaded);\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_10.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n        fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, \"test-block-mode\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_3'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.3-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_3/properties",
    "content": "NMS_VERSION=v1_21_3\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3;\n\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms {\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess());\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSTags {\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                itemStack.save(MinecraftServer.getServer().registryAccess());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner = new TrialSpawner(\n                    trialSpawner.normalConfig,\n                    trialSpawner.ominousConfig,\n                    trialSpawner.getData(),\n                    trialSpawner.getTargetCooldownLength(),\n                    trialSpawner.getRequiredPlayerRange(),\n                    trialSpawner.stateAccessor,\n                    IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector),\n                    trialSpawner.getEntitySelector()\n            );\n        }\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if(readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().lookupOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess());\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return MinecraftServer.getServer().getPlayerList().load(serverPlayer);\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        if (blockEntityCompound.contains(key)) {\n            CompoundTag frontText = blockEntityCompound.getCompound(key);\n            ListTag messages = frontText.getList(\"messages\", net.minecraft.nbt.Tag.TAG_STRING);\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT));\n        }\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos));\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder =\n                serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_3.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_4'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.4-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_4/properties",
    "content": "NMS_VERSION=v1_21_4\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4;\n\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms {\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess());\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).put(\"biomes\", biomesCompound);\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).put(\"block_states\", blockStatesCompound);\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getList(\"sections\", 10);\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompound(i);\n                    byte yPosition = sectionCompound.getByte(\"Y\");\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        if (sectionCompound.contains(\"block_states\", 10)) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"block_states\")).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        if (sectionCompound.contains(\"biomes\", 10)) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    sectionCompound.getCompound(\"biomes\")).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList(\"Entities\", 10);\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getInt(\"DataVersion\");\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL);\n    }\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSTags {\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                itemStack.save(MinecraftServer.getServer().registryAccess());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def;\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).getAsByte();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).getAllKeys();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).getAsDouble();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).getAsFloat();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).getAsInt();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).getAsLong();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).getAsShort();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).getAsString();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner = new TrialSpawner(\n                    trialSpawner.normalConfig,\n                    trialSpawner.ominousConfig,\n                    trialSpawner.getData(),\n                    trialSpawner.getTargetCooldownLength(),\n                    trialSpawner.getRequiredPlayerRange(),\n                    trialSpawner.stateAccessor,\n                    IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector),\n                    trialSpawner.getEntitySelector()\n            );\n        }\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if(readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().lookupOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess());\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absMoveTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return MinecraftServer.getServer().getPlayerList().load(serverPlayer);\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLong(key);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        if (blockEntityCompound.contains(key)) {\n            CompoundTag frontText = blockEntityCompound.getCompound(key);\n            ListTag messages = frontText.getList(\"messages\", net.minecraft.nbt.Tag.TAG_STRING);\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT));\n        }\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final BiFunction<ServerLevel, Long, Boolean> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION =\n            initializePositionTickingWithEntitiesLoaded();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos));\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) {\n        return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos);\n    }\n\n    private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) {\n        ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder =\n                serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);\n        return chunkHolder != null && chunkHolder.isTickingReady();\n    }\n\n    private static BiFunction<ServerLevel, Long, Boolean> initializePositionTickingWithEntitiesLoaded() {\n        try {\n            Class.forName(\"ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder\");\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper;\n        } catch (Throwable error) {\n            return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_4.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_5'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.5-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_5/properties",
    "content": "NMS_VERSION=v1_21_5\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5;\n\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms {\n\n    @Override\n    public String parseSignLine(String original) {\n        return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess());\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSChunks {\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"biomes\", biomesCompound));\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"block_states\", blockStatesCompound));\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i);\n                    byte yPosition = sectionCompound.getByteOr(\"Y\", (byte) 0);\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        Optional<CompoundTag> blockStatesCompound = sectionCompound.getCompound(\"block_states\");\n                        if (blockStatesCompound.isPresent()) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    blockStatesCompound.get()).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        Optional<CompoundTag> biomesCompound = sectionCompound.getCompound(\"biomes\");\n                        if (biomesCompound.isPresent()) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    biomesCompound.get()).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty(\"Entities\");\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getIntOr(\"DataVersion\", 0);\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL);\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSTags {\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                itemStack.save(MinecraftServer.getServer().registryAccess());\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION);\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.getIntOr(key, def);\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).byteValue();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).keySet();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).doubleValue();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).floatValue();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).intValue();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).longValue();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).shortValue();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).value();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner = new TrialSpawner(\n                    trialSpawner.normalConfig,\n                    trialSpawner.ominousConfig,\n                    trialSpawner.getData(),\n                    trialSpawner.getTargetCooldownLength(),\n                    trialSpawner.getRequiredPlayerRange(),\n                    trialSpawner.stateAccessor,\n                    IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector),\n                    trialSpawner.getEntitySelector()\n            );\n        }\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) {\n        // loadData\n        super.readAdditionalSaveData(compoundTag);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    public void addAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void readAdditionalSaveData(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public CompoundTag saveWithoutId(CompoundTag compoundTag) {\n        // Do not save NBT.\n        return compoundTag;\n    }\n\n    @Override\n    public void load(CompoundTag compoundTag) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if (readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().lookupOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess());\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        CompoundTag compoundTag = new CompoundTag();\n        entity.save(compoundTag);\n        return compoundTag;\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absSnapTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        return MinecraftServer.getServer().getPlayerList().load(serverPlayer);\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLongOr(key, def);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        blockEntityCompound.getCompound(key).ifPresent(textCompound -> {\n            ListTag messages = textCompound.getListOrEmpty(\"messages\");\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]);\n                }\n            }\n\n            while (textLines.size() < 4)\n                textLines.add(Component.empty());\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(nbt -> blockEntityCompound.put(key, nbt));\n        });\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(serverLevel::isPositionTickingWithEntitiesLoaded);\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_5.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n        fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, \"test-block-mode\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_7'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.7-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_7/properties",
    "content": "NMS_VERSION=v1_21_7\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParseException;\nimport com.mojang.serialization.JsonOps;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.ComponentSerialization;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms {\n\n    private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create();\n\n    @Override\n    public String parseSignLine(String original) {\n        RegistryOps<JsonElement> context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE);\n        JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0])\n                .getOrThrow(JsonParseException::new);\n        return COMPONENT_GSON.toJson(jsonElement);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        try {\n            return MinecraftServer.getServer().tps1.getAverage();\n        } catch (Throwable error) {\n            //noinspection removal\n            return MinecraftServer.getServer().recentTps[0];\n        }\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.logging.LogUtils;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.biome.Biomes;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerRO;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSChunks {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null, true);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n                PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                        biome, PalettedContainer.Strategy.SECTION_BIOMES);\n                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"biomes\", biomesCompound));\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Registry<Biome> biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(biomesRegistry);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState());\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                            Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                    DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"block_states\", blockStatesCompound));\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                    Codec<PalettedContainerRO<Holder<Biome>>> biomesCodec = PalettedContainer.codecRO(\n                            biomesRegistry.asHolderIdMap(),\n                            biomesRegistry.holderByNameCodec(),\n                            PalettedContainer.Strategy.SECTION_BIOMES,\n                            biomesRegistry.getOrThrow(Biomes.PLAINS)\n                    );\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                Registry<Biome> biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME);\n\n                Codec<PalettedContainer<BlockState>> blocksCodec = PalettedContainer.codecRW(\n                        Block.BLOCK_STATE_REGISTRY,\n                        BlockState.CODEC,\n                        PalettedContainer.Strategy.SECTION_STATES,\n                        Blocks.AIR.defaultBlockState()\n                );\n                Codec<PalettedContainer<Holder<Biome>>> biomesCodec = PalettedContainer.codecRW(\n                        biomesRegistry.asHolderIdMap(),\n                        biomesRegistry.holderByNameCodec(),\n                        PalettedContainer.Strategy.SECTION_BIOMES,\n                        biomesRegistry.getOrThrow(Biomes.PLAINS)\n                );\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i);\n                    byte yPosition = sectionCompound.getByteOr(\"Y\", (byte) 0);\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        Optional<CompoundTag> blockStatesCompound = sectionCompound.getCompound(\"block_states\");\n                        if (blockStatesCompound.isPresent()) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = blocksCodec.parse(NbtOps.INSTANCE,\n                                    blockStatesCompound.get()).promotePartial((sx) -> {\n                            });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        Optional<CompoundTag> biomesCompound = sectionCompound.getCompound(\"biomes\");\n                        if (biomesCompound.isPresent()) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = biomesCodec.parse(NbtOps.INSTANCE,\n                                    biomesCompound.get()).promotePartial((sx) -> {\n                            });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                                    biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty(\"Entities\");\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getIntOr(\"DataVersion\", 0);\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag);\n            return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL);\n        }\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.slf4j.Logger;\n\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSTags {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        PropertyMap propertyMap = new PropertyMap();\n        propertyMap.put(\"textures\", new Property(\"textures\", texture));\n\n        ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        RegistryOps<Tag> context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow();\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION);\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.getIntOr(key, def);\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        RegistryOps<net.minecraft.nbt.Tag> context =\n                MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        return ItemStack.CODEC.parse(context, compoundTag)\n                .resultOrPartial((itemId) -> LOGGER.error(\"Tried to load invalid item: '{}'\", itemId))\n                .orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).byteValue();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).keySet();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).doubleValue();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).floatValue();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).intValue();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).longValue();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).shortValue();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).value();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.NeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<NeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<NeighborUpdater>(\n            Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector));\n        }\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\nimport net.minecraft.world.level.storage.ValueInput;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        super.readAdditionalSaveData(input);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram;\n\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.level.storage.ValueOutput;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void load(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.TagValueOutput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if (readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                serverLevel.registryAccess().lookupOrThrow(Registries.BIOME),\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections,\n                new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"block_entity@\" + blockEntity.getBlockPos(), LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag);\n            blockEntity.loadWithComponents(valueInput);\n        }\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(),\n                    biome, PalettedContainer.Strategy.SECTION_BIOMES);\n            PalettedContainer<BlockState> statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY,\n                    Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);\n\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(),\n                PalettedContainer.Strategy.SECTION_STATES);\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"cached_entity@\" + entity.getUUID(), LOGGER)) {\n            TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess());\n            entity.save(valueOutput);\n            return valueOutput.buildResult();\n        }\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.getProperties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absSnapTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) {\n            return MinecraftServer.getServer().getPlayerList().playerIo.load(\n                    serverPlayer.getName().getString(), serverPlayer.getStringUUID(), scopedCollector)\n                    .map(playerData -> {\n                        ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData);\n                        serverPlayer.load(valueInput);\n                        return playerData;\n                    });\n        }\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLongOr(key, def);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        blockEntityCompound.getCompound(key).ifPresent(textCompound -> {\n            ListTag messages = textCompound.getListOrEmpty(\"messages\");\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]);\n                }\n            }\n\n            for (int i = 0; i < 4; i++) {\n                if (textLines.get(i) == null)\n                    textLines.set(i, Component.empty());\n            }\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(nbt -> blockEntityCompound.put(key, nbt));\n        });\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(serverLevel::isPositionTickingWithEntitiesLoaded);\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_7.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n        fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, \"test-block-mode\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(21))\n    }\n}\n\ngroup 'NMS:v1_21_9'\n\ndependencies {\n    paperweight.paperDevBundle(\"1.21.10-R0.1-SNAPSHOT\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nassemble {\n    dependsOn(reobfJar)\n}\n\nif (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_21\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_21_9/properties",
    "content": "NMS_VERSION=v1_21_9\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle\nGET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING)\nEND_DRAGON_FIGHT_CLASS=EndDragonFight\nSPIKE_FEATURE_CLASS=SpikeFeature"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParseException;\nimport com.mojang.serialization.JsonOps;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.ComponentSerialization;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms {\n\n    public static final ReflectField<double[]> SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class,\n            double[].class, Modifier.PUBLIC | Modifier.FINAL, 1);\n\n    private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create();\n\n    @Override\n    public String parseSignLine(String original) {\n        RegistryOps<JsonElement> context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE);\n        JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0])\n                .getOrThrow(JsonParseException::new);\n        return COMPONENT_GSON.toJson(jsonElement);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0];\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.logging.LogUtils;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\nimport static com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSChunks {\n\n    private static final ReflectMethod<Codec<PalettedContainer<Holder<Biome>>>> CONTAINER_FACTORY_BIOME_RW_CODEC =\n            new ReflectMethod<>(PalettedContainerFactory.class, \"biomeContainerCodecRW\");\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                DataResult<Tag> dataResult = getBiomeContainerRWCodec()\n                        .encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"biomes\", biomesCompound));\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                    DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                            .encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"block_states\", blockStatesCompound));\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i);\n                    byte yPosition = sectionCompound.getByteOr(\"Y\", (byte) 0);\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        Optional<CompoundTag> blockStatesCompound = sectionCompound.getCompound(\"block_states\");\n                        if (blockStatesCompound.isPresent()) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY\n                                    .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        Optional<CompoundTag> biomesCompound = sectionCompound.getCompound(\"biomes\");\n                        if (biomesCompound.isPresent()) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = getBiomeContainerRWCodec()\n                                    .parse(NbtOps.INSTANCE, biomesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes();\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPos chunkPos = levelChunk.getPos();\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty(\"Entities\");\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getIntOr(\"DataVersion\", 0);\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag);\n            return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL);\n        }\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n    private static Codec<PalettedContainer<Holder<Biome>>> getBiomeContainerRWCodec() {\n        if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) {\n            return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY);\n        } else {\n            return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec();\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.google.common.collect.HashMultimap;\nimport com.google.common.collect.Multimap;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.Util;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.slf4j.Logger;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSTags {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        Multimap<String, Property> properties = HashMultimap.create();\n        properties.put(\"textures\", new Property(\"textures\", texture));\n\n        GameProfile gameProfile = new GameProfile(Util.NIL_UUID, \"\", new PropertyMap(properties));\n\n        ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        RegistryOps<Tag> context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow();\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION);\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.getIntOr(key, def);\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        RegistryOps<net.minecraft.nbt.Tag> context =\n                MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        return ItemStack.CODEC.parse(context, compoundTag)\n                .resultOrPartial((itemId) -> LOGGER.error(\"Tried to load invalid item: '{}'\", itemId))\n                .orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).byteValue();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).keySet();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).doubleValue();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).floatValue();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).intValue();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).longValue();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).shortValue();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).value();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftServer;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<CollectingNeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<CollectingNeighborUpdater>(\n            Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE);\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector));\n        }\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.EndWorldEndDragonFightHandler;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\n\npublic class EndDragonFightWrapper extends EndDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.portalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.portalLocation = blockPos;\n    }\n\n\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\nimport net.minecraft.world.level.storage.ValueInput;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        super.readAdditionalSaveData(input);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram;\n\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.level.storage.ValueOutput;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void load(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.TickingBlockList;\nimport com.google.common.base.Suppliers;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.resources.ResourceLocation;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.Blocks;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.Strategy;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EndDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.TagValueOutput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.BiConsumer;\n\npublic class NMSUtilsVersioned {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create(\n            MinecraftServer.getServer().registryAccess());\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()),\n                chunkCompoundTag, Optional.empty(), chunkPos, serverLevel);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if (readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                DEFAULT_PALETTED_CONTAINER_FACTORY,\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(),\n                new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"block_entity@\" + blockEntity.getBlockPos(), LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag);\n            blockEntity.loadWithComponents(valueInput);\n        }\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = createBiomesContainer(biome);\n            PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"cached_entity@\" + entity.getUUID(), LOGGER)) {\n            TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess());\n            entity.save(valueOutput);\n            return valueOutput.buildResult();\n        }\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.properties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absSnapTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static PalettedContainer<Holder<Biome>> createBiomesContainer(Holder<Biome> biome) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        Strategy<Holder<Biome>> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap());\n        return new PalettedContainerFactory(\n                null,\n                null,\n                null,\n                biomesStrategy,\n                biome,\n                null,\n                null\n        ).createForBiomes();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) {\n            return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId())\n                    .map(playerData -> {\n                        ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData);\n                        serverPlayer.load(valueInput);\n                        return playerData;\n                    });\n        }\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLongOr(key, def);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        blockEntityCompound.getCompound(key).ifPresent(textCompound -> {\n            ListTag messages = textCompound.getListOrEmpty(\"messages\");\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]);\n                }\n            }\n\n            for (int i = 0; i < 4; i++) {\n                if (textLines.get(i) == null)\n                    textLines.set(i, Component.empty());\n            }\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(nbt -> blockEntityCompound.put(key, nbt));\n        });\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getNMS();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        if (blockState.getValues().isEmpty())\n            return false;\n\n        blockState.getValues().forEach(consumer);\n        return true;\n    }\n\n    public static ResourceLocation getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BlockEntityType.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(serverLevel::isPositionTickingWithEntitiesLoaded);\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_21_9.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n        fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, \"test-block-mode\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/build.gradle",
    "content": "group 'NMS:v1_8_R3'\n\ndependencies {\n    compileOnly \"org.spigotmc:v1_8_R3:latest\"\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('nms.compile_v1_8') && !Boolean.valueOf(project.findProperty(\"nms.compile_v1_8\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.BlockEntityCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.EntityFallingBlock;\nimport net.minecraft.server.v1_8_R3.EntityMinecartAbstract;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.IChatBaseComponent;\nimport net.minecraft.server.v1_8_R3.Item;\nimport net.minecraft.server.v1_8_R3.MinecraftKey;\nimport net.minecraft.server.v1_8_R3.MinecraftServer;\nimport net.minecraft.server.v1_8_R3.World;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftServer;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftFallingSand;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftMinecart;\nimport org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.enchantments.EnchantmentTarget;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.PotionEffect;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class NMSAlgorithmsImpl implements NMSAlgorithms {\n\n    private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment();\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void registerCommand(BukkitCommand command) {\n        ((CraftServer) plugin.getServer()).getCommandMap().register(\"superiorskyblock2\", command);\n    }\n\n    @Override\n    public String parseSignLine(String original) {\n        return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]);\n    }\n\n    @Override\n    public int getCombinedId(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        IBlockData blockData;\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            blockData = world.getType(wrapper.getHandle());\n        }\n        return Block.getCombinedId(blockData);\n    }\n\n    @Override\n    public int getCombinedId(Material material, byte data) {\n        //noinspection deprecation\n        return material.getId() + (data << 12);\n    }\n\n    @Override\n    public Optional<String> getTileEntityIdFromCombinedId(int combinedId) {\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (!blockData.getBlock().isTileEntity())\n            return Optional.empty();\n\n        String id = BlockEntityCache.getTileEntityId(blockData);\n\n        return Text.isBlank(id) ? Optional.empty() : Optional.of(id);\n    }\n\n    @Override\n    public int compareMaterials(Material o1, Material o2) {\n        return Integer.compare(o1.ordinal(), o2.ordinal());\n    }\n\n    @Override\n    public short getBlockDataValue(BlockState blockState) {\n        return blockState.getRawData();\n    }\n\n    @Override\n    public short getBlockDataValue(org.bukkit.block.Block block) {\n        return block.getData();\n    }\n\n    @Override\n    public short getMaxBlockDataValue(Material material) {\n        return 0;\n    }\n\n    @Override\n    public Key getBlockKey(int combinedId) {\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n        return KeyBlocksCache.getBlockKey(blockData);\n    }\n\n    @Override\n    public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) {\n        EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle();\n        return KeyBlocksCache.getBlockKey(minecart.getDisplayBlock());\n    }\n\n    @Override\n    public Key getFallingBlockType(FallingBlock bukkitFallingBlock) {\n        EntityFallingBlock fallingBlock = ((CraftFallingSand) bukkitFallingBlock).getHandle();\n        return Optional.ofNullable(fallingBlock.getBlock()).map(KeyBlocksCache::getBlockKey).orElse(ConstantKeys.AIR);\n    }\n\n    @Override\n    public void setCustomModel(ItemMeta itemMeta, int customModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        // Doesn't exist\n    }\n\n    @Override\n    public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) {\n        potionMeta.addCustomEffect(potionEffect, true);\n    }\n\n    @Override\n    public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) {\n        MinecraftKey minecraftKey = Item.REGISTRY.c(CraftItemStack.asNMSCopy(itemStack).getItem());\n        return minecraftKey == null ? \"minecraft:air\" : minecraftKey.toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.addEnchant(GLOW_ENCHANT, 1, true);\n    }\n\n    @Override\n    public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) {\n        return defaultHolder;\n    }\n\n    @Override\n    public int getMaxWorldSize() {\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        return server.getPropertyManager().getInt(\"max-world-size\", 29999984);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        return MinecraftServer.getServer().recentTps[0];\n    }\n\n    @Override\n    public int getDataVersion() {\n        return -1;\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        try {\n            return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH));\n        } catch (IllegalArgumentException e) {\n            return null;\n        }\n    }\n    private static Enchantment initializeGlowEnchantment() {\n        int enchantId = 100;\n        while (Enchantment.getById(enchantId) != null)\n            ++enchantId;\n\n        Enchantment glowEnchant = new Enchantment(enchantId) {\n            @Override\n            public String getName() {\n                return \"SuperiorSkyblockGlow\";\n            }\n\n            @Override\n            public int getMaxLevel() {\n                return 1;\n            }\n\n            @Override\n            public int getStartLevel() {\n                return 0;\n            }\n\n            @Override\n            public EnchantmentTarget getItemTarget() {\n                return null;\n            }\n\n            @Override\n            public boolean conflictsWith(Enchantment enchantment) {\n                return false;\n            }\n\n            @Override\n            public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) {\n                return true;\n            }\n        };\n\n        try {\n            Field field = Enchantment.class.getDeclaredField(\"acceptingNew\");\n            field.setAccessible(true);\n            field.set(null, true);\n            field.setAccessible(false);\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Enchantment.registerEnchantment(glowEnchant);\n        } catch (Exception ignored) {\n        }\n\n        return glowEnchant;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\n\n@SuppressWarnings(\"deprecation\")\npublic class NMSCachedBlock implements ICachedBlock {\n\n    private static final ObjectsPool<NMSCachedBlock> POOL = new ObjectsPool<>(NMSCachedBlock::new);\n\n    private Material blockType;\n    private byte blockData;\n\n    public static NMSCachedBlock obtain(Block block) {\n        return POOL.obtain().initialize(block);\n    }\n\n    private NMSCachedBlock() {\n    }\n\n    private NMSCachedBlock initialize(Block block) {\n        this.blockType = block.getType();\n        this.blockData = block.getData();\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location) {\n        Block block = location.getWorld().getBlockAt(location);\n        block.setType(blockType);\n        block.setData(blockData);\n    }\n\n    @Override\n    public void release() {\n        this.blockType = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.NMSChunks;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.chunks.CropsTickingTileEntity;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockDoubleStep;\nimport net.minecraft.server.v1_8_R3.BlockDoubleStepAbstract;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.Blocks;\nimport net.minecraft.server.v1_8_R3.Chunk;\nimport net.minecraft.server.v1_8_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_8_R3.ChunkSection;\nimport net.minecraft.server.v1_8_R3.EntityHuman;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.MinecraftKey;\nimport net.minecraft.server.v1_8_R3.TileEntity;\nimport net.minecraft.server.v1_8_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.v1_8_R3.util.UnsafeList;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\npublic class NMSChunksImpl implements NMSChunks {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        KeyBlocksCache.cacheAllBlocks();\n        CropsTickingTileEntity.register();\n    }\n\n    @Override\n    public void setBiome(List<ChunkPosition> chunkPositions, Biome biome, Collection<Player> playersToUpdate) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        byte biomeBase = (byte) CraftBlock.biomeToBiomeBase(biome).id;\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                Arrays.fill(chunk.getBiomeIndex(), biomeBase);\n                chunk.e();\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        });\n    }\n\n    @Override\n    public void deleteChunks(Island island, List<ChunkPosition> chunkPositions, @Nullable Runnable onFinish) {\n        if (chunkPositions.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(),\n                chunkPosition.getX(), chunkPosition.getZ(), false));\n\n        NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                Arrays.fill(chunk.getSections(), null);\n\n                removeEntities(chunk);\n                removeTileEntities(chunk);\n                removeBlocks(chunk);\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        });\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Blocks>> calculateChunks(List<ChunkPosition> chunkPositions,\n                                                                           Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache) {\n        List<CalculatedChunk.Blocks> allCalculatedChunks = new LinkedList<>();\n        List<ChunkPosition> chunkPositionsToCalculate = new LinkedList<>();\n\n        Iterator<ChunkPosition> chunkPositionsIterator = chunkPositions.iterator();\n        while (chunkPositionsIterator.hasNext()) {\n            ChunkPosition chunkPosition = chunkPositionsIterator.next();\n            CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition));\n            if (cachedCalculatedChunk != null) {\n                allCalculatedChunks.add(cachedCalculatedChunk);\n                chunkPositionsIterator.remove();\n            } else {\n                chunkPositionsToCalculate.add(chunkPosition);\n            }\n        }\n\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(allCalculatedChunks);\n\n        CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture = new CompletableFuture<>();\n\n        NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() {\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                World bukkitWorld = chunk.world.getWorld();\n                ChunkPosition chunkPosition = ChunkPosition.of(bukkitWorld, chunk.locX, chunk.locZ, false);\n\n                KeyMap<Counter> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n                List<Location> spawnersLocations = new LinkedList<>();\n\n                for (ChunkSection chunkSection : chunk.getSections()) {\n                    if (chunkSection != null && !chunkSection.a()) {\n                        for (BlockPosition bp : BlockPosition.b(new BlockPosition(0, 0, 0), new BlockPosition(15, 15, 15))) {\n                            IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ());\n                            Block block = blockData.getBlock();\n                            if (block != Blocks.AIR) {\n                                Location location = new Location(bukkitWorld,\n                                        (chunkPosition.getX() << 4) + bp.getX(),\n                                        chunkSection.getYPosition() + bp.getY(),\n                                        (chunkPosition.getZ() << 4) + bp.getZ());\n                                int blockAmount = 1;\n\n                                if (block instanceof BlockDoubleStep) {\n                                    blockAmount = 2;\n                                    // Converts the block data to a regular slab\n                                    MinecraftKey blockKey = Block.REGISTRY.c(block);\n                                    blockData = Block.REGISTRY.get(new MinecraftKey(blockKey.a()\n                                                    .replace(\"double_\", \"\"))).getBlockData()\n                                            .set(BlockDoubleStepAbstract.VARIANT, blockData.get(BlockDoubleStepAbstract.VARIANT));\n                                }\n\n                                Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData), location);\n                                blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount);\n                                if (block == Blocks.MOB_SPAWNER) {\n                                    spawnersLocations.add(location);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations);\n                allCalculatedChunks.add(calculatedChunk);\n\n                if (!isLoaded)\n                    unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public CompletableFuture<List<CalculatedChunk.Entities>> calculateChunkEntities(Collection<ChunkPosition> chunkPositions) {\n        if (chunkPositions.isEmpty())\n            return CompletableFuture.completedFuture(Collections.emptyList());\n\n        CompletableFuture<List<CalculatedChunk.Entities>> completableFuture = new CompletableFuture<>();\n\n        List<CalculatedChunk.Entities> allCalculatedChunks = new LinkedList<>();\n\n        NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() {\n\n            @Override\n            public void onChunk(Chunk chunk, boolean isLoaded) {\n                KeyMap<Counter> chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n                for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) {\n                    if (!BukkitEntities.canBypassEntityLimit(bukkitEntity))\n                        chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1);\n                }\n\n                ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false);\n                CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities);\n                allCalculatedChunks.add(calculatedChunk);\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        });\n\n        return completableFuture;\n    }\n\n    @Override\n    public void injectChunkSections(org.bukkit.Chunk chunk) {\n        // No implementation\n    }\n\n    @Override\n    public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.a());\n    }\n\n    @Override\n    public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) {\n        Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().chunkProviderServer\n                .getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n        return chunk == null ? null : chunk.bukkitChunk;\n    }\n\n    @Override\n    public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) {\n        if (plugin.getSettings().getCropsInterval() <= 0)\n            return;\n\n        if (stop) {\n            CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove(\n                    chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ()));\n            if (cropsTickingTileEntity != null) {\n                try {\n                    cropsTickingTileEntity.getWorld().tileEntityList.remove(cropsTickingTileEntity);\n                } catch (Throwable error) {\n                    cropsTickingTileEntity.getWorld().t(cropsTickingTileEntity.getPosition());\n                }\n            }\n        } else {\n            CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle());\n        }\n    }\n\n    @Override\n    public void updateCropsTicker(List<ChunkPosition> chunkPositions, double newCropGrowthMultiplier) {\n        if (chunkPositions.isEmpty()) return;\n        CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity ->\n                cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier));\n    }\n\n    @Override\n    public void shutdown() {\n        // Do nothing. There are no tasks to wait for.\n    }\n\n    @Override\n    public List<Location> getBlockEntities(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n        List<Location> blockEntities = new LinkedList<>();\n\n        World bukkitWorld = bukkitChunk.getWorld();\n\n        chunk.getTileEntities().keySet().forEach(blockPosition ->\n                blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ())));\n\n        return blockEntities;\n    }\n\n    private static void removeEntities(Chunk chunk) {\n        for (int i = 0; i < chunk.entitySlices.length; i++) {\n            chunk.entitySlices[i].forEach(entity -> {\n                if (!(entity instanceof EntityHuman))\n                    entity.dead = true;\n            });\n            chunk.entitySlices[i] = new UnsafeList<>();\n        }\n    }\n\n    private static void removeTileEntities(Chunk chunk) {\n        boolean hasWorldHField = false;\n\n        try {\n            // This field doesn't exist in Taco 1.8\n            List<TileEntity> tileEntities = chunk.world.h;\n            hasWorldHField = true;\n        } catch (Throwable ignored) {\n        }\n\n        if (hasWorldHField) {\n            chunk.tileEntities.forEach(((blockPosition, tileEntity) -> {\n                chunk.world.tileEntityList.remove(tileEntity);\n                chunk.world.h.remove(tileEntity);\n                chunk.world.capturedTileEntities.remove(blockPosition);\n            }));\n        } else {\n            chunk.tileEntities.forEach(((blockPosition, tileEntity) -> {\n                chunk.world.tileEntityList.remove(tileEntity);\n                chunk.world.capturedTileEntities.remove(blockPosition);\n            }));\n        }\n\n        chunk.tileEntities.clear();\n    }\n\n    private static void removeBlocks(Chunk chunk) {\n        WorldServer worldServer = (WorldServer) chunk.world;\n\n        if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) {\n            CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, 0L, worldServer.generator);\n            Chunk generatedChunk = customChunkGenerator.getOrCreateChunk(chunk.locX, chunk.locZ);\n\n            for (int i = 0; i < 16; i++)\n                chunk.getSections()[i] = generatedChunk.getSections()[i];\n\n            for (Map.Entry<BlockPosition, TileEntity> entry : generatedChunk.getTileEntities().entrySet())\n                worldServer.setTileEntity(entry.getKey(), entry.getValue());\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.nms.NMSEntities;\nimport net.minecraft.server.v1_8_R3.Entity;\nimport net.minecraft.server.v1_8_R3.Items;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftAnimals;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;\nimport org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.inventory.EntityEquipment;\nimport org.bukkit.inventory.ItemStack;\n\npublic class NMSEntitiesImpl implements NMSEntities {\n\n    private static final ReflectField<Integer> PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, \"al\");\n\n    @Override\n    public ItemStack[] getEquipment(EntityEquipment entityEquipment) {\n        ItemStack[] itemStacks = new ItemStack[6];\n\n        itemStacks[0] = new ItemStack(Material.ARMOR_STAND);\n        itemStacks[1] = entityEquipment.getItemInHand();\n        itemStacks[2] = entityEquipment.getHelmet();\n        itemStacks[3] = entityEquipment.getChestplate();\n        itemStacks[4] = entityEquipment.getLeggings();\n        itemStacks[5] = entityEquipment.getBoots();\n\n        return itemStacks;\n    }\n\n    @Override\n    public boolean isAnimalFood(ItemStack itemStack, Animals animals) {\n        return ((CraftAnimals) animals).getHandle().d(CraftItemStack.asNMSCopy(itemStack));\n    }\n\n    @Override\n    public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) {\n        return CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL;\n    }\n\n    @Override\n    public int getPortalTicks(org.bukkit.entity.Entity entity) {\n        return PORTAL_TICKS.get(((CraftEntity) entity).getHandle());\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSHologramsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.nms.NMSHolograms;\nimport net.minecraft.server.v1_8_R3.AxisAlignedBB;\nimport net.minecraft.server.v1_8_R3.DamageSource;\nimport net.minecraft.server.v1_8_R3.EntityArmorStand;\nimport net.minecraft.server.v1_8_R3.EntityHuman;\nimport net.minecraft.server.v1_8_R3.ItemStack;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.Vec3D;\nimport net.minecraft.server.v1_8_R3.World;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftArmorStand;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\n\n@SuppressWarnings(\"unused\")\npublic class NMSHologramsImpl implements NMSHolograms {\n\n    @Override\n    public Hologram createHologram(Location location) {\n        World world = ((CraftWorld) location.getWorld()).getHandle();\n        EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ());\n        world.addEntity(entityHologram);\n        return entityHologram;\n    }\n\n    @Override\n    public boolean isHologram(Entity entity) {\n        return ((CraftEntity) entity).getHandle() instanceof Hologram;\n    }\n\n    public static class EntityHologram extends EntityArmorStand implements Hologram {\n\n        EntityHologram(World world, double x, double y, double z) {\n            super(world, x, y, z);\n            setInvisible(true);\n            setSmall(true);\n            setArms(false);\n            setGravity(false);\n            setBasePlate(true);\n            n(true);\n            super.setCustomNameVisible(true);\n            super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D));\n            this.onGround = true; // Workaround to force EntityTrackerEntry to send a teleport packet.\n        }\n\n        @Override\n        public void setHologramName(String name) {\n            super.setCustomName(name);\n        }\n\n        @Override\n        public void removeHologram() {\n            super.die();\n        }\n\n        @Override\n        public ArmorStand getHandle() {\n            return this.getBukkitEntity();\n        }\n\n        @Override\n        public void inactiveTick() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        @Override\n        public void setEquipment(int i, ItemStack item) {\n            // Prevent stand being equipped\n        }\n\n        @Override\n        public boolean d(int i, ItemStack item) {\n            // Prevent stand being equipped\n            return false;\n        }\n\n        @Override\n        public void b(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n        }\n\n        @Override\n        public boolean a(EntityHuman human, Vec3D vec3d) {\n            // Prevent stand being equipped\n            return true;\n        }\n\n        @Override\n        public void t_() {\n            // Disable normal ticking for this entity.\n\n            // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity.\n            if (this.onGround) {\n                this.onGround = false;\n            }\n        }\n\n        @Override\n        public void die() {\n            // Prevent being killed.\n        }\n\n        @Override\n        public void makeSound(String sound, float f1, float f2) {\n            // Remove sounds.\n        }\n\n        @Override\n        public boolean c(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public boolean d(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n            return false;\n        }\n\n        @Override\n        public void e(NBTTagCompound nbttagcompound) {\n            // Do not save NBT.\n        }\n\n        @Override\n        public CraftArmorStand getBukkitEntity() {\n            if (super.bukkitEntity == null) {\n                this.bukkitEntity = new CraftArmorStand(this.world.getServer(), this);\n            }\n            return (CraftArmorStand) this.bukkitEntity;\n        }\n\n        @Override\n        public boolean isInvulnerable(DamageSource source) {\n            /*\n             * The field Entity.invulnerable is private.\n             * It's only used while saving NBTTags, but since the entity would be killed\n             * on chunk unload, we prefer to override isInvulnerable().\n             */\n            return true;\n        }\n\n        @Override\n        public void setCustomName(String customName) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void setCustomNameVisible(boolean visible) {\n            // Locks the custom name.\n        }\n\n        @Override\n        public void a(AxisAlignedBB boundingBox) {\n            // Do not change it!\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.NMSPlayers;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.player.OfflinePlayerDataImpl;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.service.bossbar.EmptyBossBar;\nimport com.mojang.authlib.properties.Property;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport net.minecraft.server.v1_8_R3.Entity;\nimport net.minecraft.server.v1_8_R3.EntityItem;\nimport net.minecraft.server.v1_8_R3.EntityPlayer;\nimport net.minecraft.server.v1_8_R3.PacketPlayOutChat;\nimport net.minecraft.server.v1_8_R3.PacketPlayOutTitle;\nimport net.minecraft.server.v1_8_R3.PlayerConnection;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftItem;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;\nimport org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class NMSPlayersImpl implements NMSPlayers {\n\n    @Override\n    public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) {\n        return OfflinePlayerDataImpl.create(offlinePlayer);\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer) {\n        superiorPlayer.runIfOnline(player -> {\n            EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();\n            Optional<Property> optional = entityPlayer.getProfile().getProperties().get(\"textures\").stream().findFirst();\n            optional.ifPresent(property -> setSkinTexture(superiorPlayer, property));\n        });\n    }\n\n    @Override\n    public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) {\n        superiorPlayer.setTextureValue(property.getValue());\n    }\n\n    @Override\n    public void sendActionBar(Player player, String message) {\n        PacketPlayOutChat packetPlayOutChat = new PacketPlayOutChat(null, (byte) 2);\n        packetPlayOutChat.components = TextComponent.fromLegacyText(message);\n        ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutChat);\n    }\n\n    @Override\n    public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) {\n        return EmptyBossBar.getInstance();\n    }\n\n    @Override\n    public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) {\n        PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection;\n\n        PacketPlayOutTitle times;\n        if (title != null) {\n            times = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, CraftChatMessage.fromString(title)[0]);\n            playerConnection.sendPacket(times);\n        }\n\n        if (subtitle != null) {\n            times = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.SUBTITLE, CraftChatMessage.fromString(subtitle)[0]);\n            playerConnection.sendPacket(times);\n        }\n\n        times = new PacketPlayOutTitle(fadeIn, duration, fadeOut);\n        playerConnection.sendPacket(times);\n    }\n\n    @Override\n    public boolean wasThrownByPlayer(org.bukkit.entity.Item item, SuperiorPlayer superiorPlayer) {\n        Entity entity = ((CraftItem) item).getHandle();\n        return entity instanceof EntityItem && superiorPlayer.getName().equals(((EntityItem) entity).n());\n    }\n\n    @Nullable\n    @Override\n    public Locale getPlayerLocale(Player player) {\n        try {\n            return PlayerLocales.getLocale(player.spigot().getLocale());\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.nms.NMSTags;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport net.minecraft.server.v1_8_R3.Entity;\nimport net.minecraft.server.v1_8_R3.EntityTypes;\nimport net.minecraft.server.v1_8_R3.ItemStack;\nimport net.minecraft.server.v1_8_R3.MinecraftKey;\nimport net.minecraft.server.v1_8_R3.NBTBase;\nimport net.minecraft.server.v1_8_R3.NBTTagByte;\nimport net.minecraft.server.v1_8_R3.NBTTagByteArray;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.NBTTagDouble;\nimport net.minecraft.server.v1_8_R3.NBTTagFloat;\nimport net.minecraft.server.v1_8_R3.NBTTagInt;\nimport net.minecraft.server.v1_8_R3.NBTTagIntArray;\nimport net.minecraft.server.v1_8_R3.NBTTagList;\nimport net.minecraft.server.v1_8_R3.NBTTagLong;\nimport net.minecraft.server.v1_8_R3.NBTTagShort;\nimport net.minecraft.server.v1_8_R3.NBTTagString;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.Set;\n\n@SuppressWarnings({\"unused\"})\npublic class NMSTagsImpl implements NMSTags {\n\n    @Override\n    public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound());\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) {\n        if (compoundTag.containsKey(\"NBT\")) {\n            // Old compound version, deserialize it accordingly\n            return deserializeItemOld(compoundTag);\n        }\n\n        NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT();\n        ItemStack itemStack = ItemStack.createStack(tagCompound);\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) {\n        String typeName = Materials.patchOldMaterialName(compoundTag.getString(\"type\").orElse(null));\n        Material type = Material.valueOf(typeName);\n        int amount = compoundTag.getInt(\"amount\").orElse(0);\n        short data = (short) compoundTag.getShort(\"data\").orElse(0);\n        CompoundTag nbtData = compoundTag.getCompound(\"NBT\").orElse(null);\n\n        org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data);\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n        if (nbtData != null)\n            itemStack.setTag((NBTTagCompound) nbtData.toNBT());\n\n        return CraftItemStack.asCraftMirror(itemStack);\n    }\n\n    @Override\n    public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) {\n        CraftWorld craftWorld = (CraftWorld) location.getWorld();\n        NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT();\n\n        if (nbtTagCompound == null)\n            nbtTagCompound = new NBTTagCompound();\n\n        if (!nbtTagCompound.hasKey(\"id\"))\n            //noinspection deprecation\n            nbtTagCompound.setString(\"id\", new MinecraftKey(entityType.getName()).a());\n\n        Entity entity = EntityTypes.a(nbtTagCompound, craftWorld.getHandle());\n        entity.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((NBTTagByteArray) object).c();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NBTTagByte) object).f();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((NBTTagCompound) object).c();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NBTTagDouble) object).g();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NBTTagFloat) object).h();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((NBTTagIntArray) object).c();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NBTTagInt) object).d();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((NBTTagList) object).g(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NBTTagLong) object).c();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NBTTagShort) object).e();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((NBTTagString) object).a_();\n    }\n\n    @Override\n    public Object parseList(ListTag listTag) {\n        NBTTagList nbtTagList = new NBTTagList();\n\n        for (Tag<?> tag : listTag)\n            nbtTagList.add((NBTBase) tag.toNBT());\n\n        return nbtTagList;\n    }\n\n    @Override\n    public Object getNBTCompoundTag(Object object, String key) {\n        return ((NBTTagCompound) object).get(key);\n    }\n\n    @Override\n    public void setNBTCompoundTagValue(Object object, String key, Object value) {\n        ((NBTTagCompound) object).set(key, (NBTBase) value);\n    }\n\n    @Override\n    public int getNBTTagListSize(Object object) {\n        return ((NBTTagList) object).size();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.google.common.collect.Maps;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.Chunk;\nimport net.minecraft.server.v1_8_R3.ChunkProviderServer;\nimport net.minecraft.server.v1_8_R3.ChunkRegionLoader;\nimport net.minecraft.server.v1_8_R3.ChunkSection;\nimport net.minecraft.server.v1_8_R3.EntityHuman;\nimport net.minecraft.server.v1_8_R3.EntityPlayer;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.IChunkLoader;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.Packet;\nimport net.minecraft.server.v1_8_R3.PlayerChunkMap;\nimport net.minecraft.server.v1_8_R3.TileEntity;\nimport net.minecraft.server.v1_8_R3.World;\nimport net.minecraft.server.v1_8_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\n\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class NMSUtils {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ReflectField<IChunkLoader> CHUNK_LOADER = new ReflectField<>(\n            ChunkProviderServer.class, IChunkLoader.class, \"chunkLoader\");\n\n    private static final Map<UUID, IChunkLoader> chunkLoadersMap = Maps.newConcurrentMap();\n\n    public static final ObjectsPool<ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition>> BLOCK_POS_POOL =\n            ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0));\n\n    private NMSUtils() {\n\n    }\n\n    @Nullable\n    public static <T extends TileEntity> T getTileEntityAt(Location location, Class<T> type) {\n        org.bukkit.World bukkitWorld = location.getWorld();\n\n        if (bukkitWorld == null)\n            return null;\n\n        WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n            TileEntity tileEntity = worldServer.getTileEntity(blockPosition);\n            return !type.isInstance(tileEntity) ? null : type.cast(tileEntity);\n        }\n    }\n\n    public static void runActionOnChunks(Collection<ChunkPosition> chunksCoords,\n                                         boolean saveChunks, ChunkCallback chunkCallback) {\n        List<ChunkPosition> unloadedChunks = new LinkedList<>();\n        List<Chunk> loadedChunks = new LinkedList<>();\n\n        chunksCoords.forEach(chunkPosition -> {\n            WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n            Chunk chunk = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ());\n\n            if (chunk != null) {\n                loadedChunks.add(chunk);\n            } else {\n                unloadedChunks.add(chunkPosition.copy());\n            }\n        });\n\n        boolean hasUnloadedChunks = !unloadedChunks.isEmpty();\n\n        loadedChunks.forEach(loadedChunk -> chunkCallback.onChunk(loadedChunk, true));\n\n        if (hasUnloadedChunks) {\n            runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback);\n        } else {\n            chunkCallback.onFinish();\n        }\n    }\n\n    public static void runActionOnUnloadedChunks(Collection<ChunkPosition> chunks,\n                                                 boolean saveChunks, ChunkCallback chunkCallback) {\n        chunks.forEach(chunkPosition -> {\n            WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n            IChunkLoader chunkLoader = chunkLoadersMap.computeIfAbsent(worldServer.getDataManager().getUUID(),\n                    uuid -> CHUNK_LOADER.get(worldServer.chunkProviderServer));\n\n            if (chunkLoader instanceof ChunkRegionLoader &&\n                    !((ChunkRegionLoader) chunkLoader).chunkExists(worldServer, chunkPosition.getX(), chunkPosition.getZ()))\n                return;\n\n            try {\n                Chunk loadedChunk = chunkLoader.a(worldServer, chunkPosition.getX(), chunkPosition.getZ());\n\n                if (loadedChunk != null) {\n                    chunkCallback.onChunk(loadedChunk, false);\n\n                    if (saveChunks) {\n                        try {\n                            chunkLoader.a(worldServer, loadedChunk);\n                        } catch (Exception error) {\n                            Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                        }\n                    }\n                }\n\n                chunkCallback.onFinish();\n            } catch (Exception error) {\n                Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n            }\n        });\n    }\n\n    public static void sendPacketToRelevantPlayers(WorldServer worldServer, int chunkX, int chunkZ, Packet<?> packet) {\n        PlayerChunkMap playerChunkMap = worldServer.getPlayerChunkMap();\n        for (EntityHuman entityHuman : worldServer.players) {\n            if (entityHuman instanceof EntityPlayer && playerChunkMap.a((EntityPlayer) entityHuman, chunkX, chunkZ))\n                ((EntityPlayer) entityHuman).playerConnection.sendPacket(packet);\n        }\n    }\n\n    public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag tileEntity) {\n        if (!isValidPosition(chunk.world, blockPosition))\n            return;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n\n        if (blockData.getBlock().getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) {\n            chunk.world.setTypeAndData(blockPosition, blockData, 3);\n            return;\n        }\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        int highestBlockLight = chunk.b(blockX, blockZ);\n        boolean initLight = false;\n\n        int indexY = blockY >> 4;\n\n        ChunkSection chunkSection = chunk.getSections()[indexY];\n\n        if (chunkSection == null) {\n            chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, !chunk.world.worldProvider.o());\n            initLight = blockY > highestBlockLight;\n        }\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData);\n\n        chunk.e();\n\n        if (initLight)\n            chunk.initLighting();\n\n        if (tileEntity != null) {\n            NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT();\n            if (tileEntityCompound != null) {\n                tileEntityCompound.setInt(\"x\", blockPosition.getX());\n                tileEntityCompound.setInt(\"y\", blockPosition.getY());\n                tileEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition);\n                if (worldTileEntity != null)\n                    worldTileEntity.a(tileEntityCompound);\n            }\n        }\n    }\n\n    private static boolean isValidPosition(World world, BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight();\n    }\n\n    public interface ChunkCallback {\n\n        void onChunk(Chunk chunk, boolean isLoaded);\n\n        void onFinish();\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.signs.IslandSigns;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport com.bgsoftware.superiorskyblock.nms.NMSWorld;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.generator.IslandsGeneratorImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.spawners.MobSpawnerAbstractNotifier;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.ChunkReaderImpl;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.WorldEditSessionImpl;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockDoubleStep;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.EnumParticle;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.IChatBaseComponent;\nimport net.minecraft.server.v1_8_R3.MobSpawnerAbstract;\nimport net.minecraft.server.v1_8_R3.PacketPlayOutBlockChange;\nimport net.minecraft.server.v1_8_R3.PacketPlayOutWorldBorder;\nimport net.minecraft.server.v1_8_R3.TileEntityMobSpawner;\nimport net.minecraft.server.v1_8_R3.TileEntitySign;\nimport net.minecraft.server.v1_8_R3.WorldBorder;\nimport net.minecraft.server.v1_8_R3.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.block.CraftSign;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;\nimport org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers;\nimport org.bukkit.entity.Player;\nimport org.bukkit.material.MaterialData;\n\nimport java.lang.reflect.Modifier;\nimport java.util.function.IntFunction;\n\npublic class NMSWorldImpl implements NMSWorld {\n\n\n    private static final ReflectField<MobSpawnerAbstract> MOB_SPAWNER_ABSTRACT = new ReflectField<MobSpawnerAbstract>(\n            TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    private static boolean alreadyWarned = false;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return getBlockKeyInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return ConstantKeys.AIR;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        int blockId = chunkSnapshot.getBlockTypeId(x, y, z);\n        int blockData = chunkSnapshot.getBlockData(x, y, z);\n        int combinedId = blockId + (blockData << 12);\n\n        Location location = new Location(\n                Bukkit.getWorld(chunkSnapshot.getWorldName()),\n                (chunkSnapshot.getX() << 4) + x,\n                y,\n                (chunkSnapshot.getZ() << 4) + z\n        );\n\n        return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location);\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        try {\n            return canPlayerSuffocateInternal(chunkSnapshot, x, y, z);\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return true;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        int blockId = chunkSnapshot.getBlockTypeId(x, y, z);\n        int blockData = chunkSnapshot.getBlockData(x, y, z);\n        int combinedId = blockId + (blockData << 12);\n        return Block.getByCombinedId(combinedId).getBlock().w();\n    }\n\n    @Override\n    public void listenSpawner(Location location, IntFunction<Integer> delayChangeCallback) {\n        TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class);\n        if (mobSpawner == null)\n            return;\n\n        MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner();\n        if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier)\n            return;\n\n        MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback);\n        MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier);\n        mobSpawnerAbstractNotifier.updateDelay();\n    }\n\n    @Override\n    public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) {\n        if (!plugin.getSettings().isWorldBorders())\n            return;\n\n        Player player = superiorPlayer.asPlayer();\n        World world = superiorPlayer.getWorld();\n\n        if (world == null || player == null)\n            return;\n\n        int islandSize = island == null ? 0 : island.getIslandSize();\n\n        boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0;\n\n        WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle();\n\n        WorldBorder worldBorder;\n\n        if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) {\n            worldBorder = worldServer.getWorldBorder();\n        } else {\n            Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n            if (dimension == null)\n                return;\n\n            Location center = island.getCenter(dimension);\n\n            worldBorder = new WorldBorder();\n            worldBorder.world = worldServer;\n            worldBorder.setWarningDistance(0);\n\n            if (dimension.getEnvironment() == World.Environment.NETHER) {\n                worldBorder.setCenter(center.getX() * 8, center.getZ() * 8);\n            } else {\n                worldBorder.setCenter(center.getX(), center.getZ());\n            }\n\n            switch (superiorPlayer.getBorderColor()) {\n                case BLUE: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    break;\n                }\n                case GREEN: {\n                    worldBorder.setSize((islandSize * 2) + 1.001D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE);\n                    break;\n                }\n                case RED: {\n                    worldBorder.setSize((islandSize * 2) + 1D);\n                    worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE);\n                    break;\n                }\n            }\n        }\n\n        PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder,\n                PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE);\n        ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder);\n    }\n\n    @Override\n    public Object getBlockData(org.bukkit.block.Block block) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId) {\n        WorldServer world = ((CraftWorld) location.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n            NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null);\n            NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4,\n                    new PacketPlayOutBlockChange(world, blockPosition));\n        }\n    }\n\n    @Override\n    public ICachedBlock cacheBlock(org.bukkit.block.Block block) {\n        return NMSCachedBlock.obtain(block);\n    }\n\n    @Override\n    public boolean isWaterLogged(org.bukkit.block.Block block) {\n        Material blockType = block.getType();\n        return blockType == Material.WATER || blockType == Material.STATIONARY_WATER;\n    }\n\n    @Override\n    public SignType getSignType(org.bukkit.block.Block block) {\n        Material blockType = block.getType();\n        return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN :\n                blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN;\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        throw new UnsupportedOperationException(\"Not supported\");\n    }\n\n    @Override\n    public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) {\n        Block nmsBlock = CraftMagicNumbers.getBlock(block);\n        return PistonPushReaction.values()[nmsBlock.getMaterial().getPushReaction()];\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.Block block) {\n        WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();\n        IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ()));\n        return getDefaultAmount(blockData);\n    }\n\n    @Override\n    public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) {\n        MaterialData materialData = bukkitBlockState.getData();\n        // noinspection deprecation\n        int combinedId = materialData.getItemType().getId() + (materialData.getData() << 12);\n        return getDefaultAmount(Block.getByCombinedId(combinedId));\n    }\n\n    private int getDefaultAmount(IBlockData blockData) {\n        Block nmsBlock = blockData.getBlock();\n\n        // Checks for double slabs\n        if (nmsBlock instanceof BlockDoubleStep) {\n            return 2;\n        }\n\n        return 1;\n    }\n\n    @Override\n    public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) {\n        WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());\n            return worldServer.getType(blockPosition).getBlock().w();\n        }\n    }\n\n    @Override\n    public void placeSign(Island island, Location location) {\n        TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class);\n        if (tileEntitySign == null)\n            return;\n\n        String[] lines = new String[4];\n        System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length);\n        String[] strippedLines = new String[4];\n        for (int i = 0; i < 4; i++)\n            strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]);\n\n        IChatBaseComponent[] newLines;\n\n        IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false);\n        if (result.isCancelEvent()) {\n            newLines = CraftSign.sanitizeLines(strippedLines);\n        } else {\n            newLines = CraftSign.sanitizeLines(lines);\n        }\n\n        System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4);\n    }\n\n    @Override\n    public void playGeneratorSound(Location location) {\n        WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n\n            double x = location.getX();\n            double y = location.getY();\n            double z = location.getZ();\n\n            blockPosition.c(x, y, z);\n\n            worldServer.makeSound(x + 0.5D, y + 0.5D, z + 0.5D, \"random.fizz\", 0.5F,\n                    2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F);\n\n            for (int i = 0; i < 8; i++) {\n                worldServer.addParticle(EnumParticle.SMOKE_LARGE,\n                        x + Math.random(), y + 1.2D, z + Math.random(),\n                        0.0D, 0.0D, 0.0D);\n            }\n        }\n    }\n\n    @Override\n    public void playBreakAnimation(org.bukkit.block.Block block) {\n        WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle();\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(block.getX(), block.getY(), block.getZ());\n            worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition)));\n        }\n    }\n\n    @Override\n    public void playPlaceSound(Location location) {\n        WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle();\n\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n            Block.StepSound stepSound = worldServer.getType(blockPosition).getBlock().stepSound;\n            worldServer.makeSound(blockPosition.getX() + 0.5F, blockPosition.getY() + 0.5F, blockPosition.getZ() + 0.5F,\n                    stepSound.getPlaceSound(), (stepSound.getVolume1() + 1.0F) / 2.0F, stepSound.getVolume2() * 0.8F);\n        }\n    }\n\n    @Override\n    public int getMinHeight(World world) {\n        return 0;\n    }\n\n    @Override\n    public void removeAntiXray(World bukkitWorld) {\n        // Doesn't exist in this version.\n    }\n\n    @Override\n    public void setOceanLevel(World world) {\n        ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight());\n    }\n\n    @Override\n    public IslandsGenerator createGenerator(Dimension dimension) {\n        return new IslandsGeneratorImpl(dimension);\n    }\n\n    @Override\n    public WorldEditSession createEditSession(World world) {\n        return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle());\n    }\n\n    @Override\n    public WorldEditSession createPartialEditSession(Dimension dimension) {\n        return WorldEditSessionImpl.obtain(dimension);\n    }\n\n    @Override\n    public ChunkReader createChunkReader(Chunk chunk) {\n        return new ChunkReaderImpl(chunk);\n    }\n\n    @Override\n    public void listenBlockStateChanges(org.bukkit.World world) {\n        if (!alreadyWarned) {\n            Log.warn(\"This version is old and you may experience issues with block changes detection\");\n            alreadyWarned = true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.chunks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.Chunk;\nimport net.minecraft.server.v1_8_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_8_R3.ChunkSection;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.IUpdatePlayerListBox;\nimport net.minecraft.server.v1_8_R3.TileEntity;\nimport org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.function.Consumer;\n\npublic class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerListBox {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static Set<Block> CROPS_TO_GROW_CACHE;\n\n    static {\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate);\n    }\n\n    private static final Chunk2ObjectMap<CropsTickingTileEntity> tickingChunks = new Chunk2ObjectMap<>();\n    private static int random = ThreadLocalRandom.current().nextInt();\n\n    private final WeakReference<Island> island;\n    private final WeakReference<Chunk> chunk;\n    private final int chunkX;\n    private final int chunkZ;\n\n    private int currentTick = 0;\n\n    private double cachedCropGrowthMultiplier;\n\n    public static void register() {\n        // Calls the static initializer which registers the callback.\n    }\n\n    public static CropsTickingTileEntity remove(String worldName, long chunkCoords) {\n        return tickingChunks.remove(worldName, chunkCoords);\n    }\n\n    public static void create(Island island, String worldName, Chunk chunk) {\n        long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ);\n        tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk));\n    }\n\n    public static void forEachChunk(List<ChunkPosition> chunkPositions, Consumer<CropsTickingTileEntity> cropsTickingTileEntityConsumer) {\n        if (tickingChunks.isEmpty())\n            return;\n\n        chunkPositions.forEach(chunkPosition -> {\n            long chunkKey = chunkPosition.asPair();\n            CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey);\n            if (cropsTickingTileEntity != null)\n                cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity);\n        });\n    }\n\n    private CropsTickingTileEntity(Island island, Chunk chunk) {\n        this.island = new WeakReference<>(island);\n        this.chunk = new WeakReference<>(chunk);\n        this.chunkX = chunk.locX;\n        this.chunkZ = chunk.locZ;\n        a(chunk.getWorld());\n        a(new BlockPosition(chunkX << 4, 1, chunkZ << 4));\n        try {\n            world.tileEntityList.add(this);\n        } catch (Throwable error) {\n            world.a(this);\n        }\n        this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1;\n    }\n\n    @Override\n    public void c() {\n        if (++currentTick <= plugin.getSettings().getCropsInterval())\n            return;\n\n        Chunk chunk = this.chunk.get();\n        Island island = this.island.get();\n\n        if (chunk == null || island == null) {\n            world.tileEntityList.remove(this);\n            return;\n        }\n\n        currentTick = 0;\n\n        int worldRandomTick = world.getGameRules().c(\"randomTickSpeed\");\n\n        int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval());\n\n        if (chunkRandomTickSpeed > 0) {\n            for (ChunkSection chunkSection : chunk.getSections()) {\n                if (chunkSection != null && chunkSection.shouldTick()) {\n                    for (int i = 0; i < chunkRandomTickSpeed; i++) {\n                        random = random * 3 + 1013904223;\n                        int factor = random >> 2;\n                        int x = factor & 15;\n                        int z = factor >> 8 & 15;\n                        int y = factor >> 16 & 15;\n                        IBlockData blockData = chunkSection.getType(x, y, z);\n                        Block block = blockData.getBlock();\n                        if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) {\n                            block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)),\n                                    blockData, ThreadLocalRandom.current());\n                        }\n                    }\n                }\n            }\n        }\n\n    }\n\n    public void setCropGrowthMultiplier(double cropGrowthMultiplier) {\n        this.cachedCropGrowthMultiplier = cropGrowthMultiplier;\n    }\n\n    private static void onSettingsUpdate() {\n        CROPS_TO_GROW_CACHE = new HashSet<>();\n        plugin.getSettings().getCropsToGrow().forEach(cropName -> {\n            Key key = Keys.ofMaterialAndData(cropName);\n            if (key instanceof MaterialKey) {\n                Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial());\n                if (block != null && block.isTicking())\n                    CROPS_TO_GROW_CACHE.add(block);\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/generator/IslandsGeneratorImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.generator;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport net.minecraft.server.v1_8_R3.BiomeBase;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock;\nimport org.bukkit.generator.BlockPopulator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Random;\n\n@SuppressWarnings(\"unused\")\npublic class IslandsGeneratorImpl extends IslandsGenerator {\n\n    private static final ReflectField<BiomeBase[]> BIOME_BASE_ARRAY = new ReflectField<>(\n            new ClassInfo(\"generator.CustomChunkGenerator$CustomBiomeGrid\", ClassInfo.PackageType.CRAFTBUKKIT),\n            BiomeBase[].class, \"biome\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Dimension dimension;\n\n    public IslandsGeneratorImpl(Dimension dimension) {\n        this.dimension = dimension;\n    }\n\n    @Override\n    public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) {\n        ChunkData chunkData = createChunkData(world);\n\n        Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension);\n\n        setBiome(biomeGrid, targetBiome);\n\n        if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            chunkData.setBlock(0, 99, 0, Material.BEDROCK);\n        }\n\n        return chunkData;\n    }\n\n    @Override\n    public List<BlockPopulator> getDefaultPopulators(World world) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Location getFixedSpawnLocation(World world, Random random) {\n        return new Location(world, 0, 100, 0);\n    }\n\n    private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) {\n        BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biome);\n\n        BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeGrid);\n\n        if (biomeBases == null)\n            return;\n\n        Arrays.fill(biomeBases, biomeBase);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.player;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.mojang.authlib.GameProfile;\nimport net.minecraft.server.v1_8_R3.EntityPlayer;\nimport net.minecraft.server.v1_8_R3.MinecraftServer;\nimport net.minecraft.server.v1_8_R3.PlayerInteractManager;\nimport net.minecraft.server.v1_8_R3.WorldServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftServer;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftWorld;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\n\nimport java.util.Optional;\n\npublic class OfflinePlayerDataImpl implements OfflinePlayerData {\n\n    private static final ObjectsPool<OfflinePlayerDataImpl> POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new);\n\n    private Player fakePlayer;\n\n    public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) {\n        return POOL.obtain().initialize(offlinePlayer);\n    }\n\n    private OfflinePlayerDataImpl() {\n\n    }\n\n    private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) {\n        GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(),\n                Optional.ofNullable(offlinePlayer.getName()).orElse(\"\"));\n\n        MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();\n        WorldServer worldServer = server.getWorldServer(0);\n        EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));\n        this.fakePlayer = entityPlayer.getBukkitEntity();\n        this.fakePlayer.loadData();\n\n        return this;\n    }\n\n    @Override\n    public Player getFakeOnlinePlayer() {\n        return this.fakePlayer;\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle();\n        entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle();\n        entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    @Override\n    public void applyChanges() {\n        this.fakePlayer.saveData();\n    }\n\n    @Override\n    public void release() {\n        this.fakePlayer = null;\n        POOL.release(this);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/spawners/MobSpawnerAbstractNotifier.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.spawners;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.MobSpawnerAbstract;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.World;\n\nimport java.util.function.IntFunction;\n\npublic class MobSpawnerAbstractNotifier extends MobSpawnerAbstract {\n\n    private final MobSpawnerAbstract mobSpawnerAbstract;\n    private final IntFunction<Integer> delayChangeCallback;\n\n    public MobSpawnerAbstractNotifier(MobSpawnerAbstract mobSpawnerAbstract, IntFunction<Integer> delayChangeCallback) {\n        this.mobSpawnerAbstract = mobSpawnerAbstract;\n        this.delayChangeCallback = delayChangeCallback;\n\n        // Copy data from original spawner to this\n        NBTTagCompound spawnerCompound = new NBTTagCompound();\n        mobSpawnerAbstract.b(spawnerCompound);\n        this.a(spawnerCompound);\n    }\n\n    @Nullable\n    @Override\n    public String getMobName() {\n        return mobSpawnerAbstract.getMobName();\n    }\n\n    @Override\n    public void setMobName(String name) {\n        mobSpawnerAbstract.setMobName(name);\n    }\n\n    @Override\n    public void c() {\n        int startDelay = mobSpawnerAbstract.spawnDelay;\n        try {\n            mobSpawnerAbstract.c();\n        } finally {\n            int newDelay = mobSpawnerAbstract.spawnDelay;\n            if (newDelay > startDelay)\n                updateDelay();\n        }\n    }\n\n    @Override\n    public void a(NBTTagCompound nbttagcompound) {\n        mobSpawnerAbstract.a(nbttagcompound);\n    }\n\n    @Override\n    public void b(NBTTagCompound nbttagcompound) {\n        mobSpawnerAbstract.b(nbttagcompound);\n    }\n\n    @Override\n    public boolean b(int i) {\n        return mobSpawnerAbstract.b(i);\n    }\n\n    @Override\n    public void a(a mobspawnerabstract_a) {\n        mobSpawnerAbstract.a(mobspawnerabstract_a);\n    }\n\n    @Override\n    public void a(int i) {\n        mobSpawnerAbstract.a(i);\n    }\n\n    @Override\n    public World a() {\n        return mobSpawnerAbstract.a();\n    }\n\n    @Override\n    public BlockPosition b() {\n        return mobSpawnerAbstract.b();\n    }\n\n    public void updateDelay() {\n        mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world;\n\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.IContainer;\nimport net.minecraft.server.v1_8_R3.MinecraftServer;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.TileEntity;\nimport net.minecraft.server.v1_8_R3.World;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class BlockEntityCache {\n\n    private static final Map<Block, String> BLOCK_TO_ID = new IdentityHashMap<>();\n\n    private BlockEntityCache() {\n\n    }\n\n    public static String getTileEntityId(IBlockData blockData) {\n        return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> {\n            if (block instanceof IContainer) {\n                World world = MinecraftServer.getServer().getWorld();\n                TileEntity tileEntity = ((IContainer) block).a(world, block.toLegacyData(blockData));\n                if (tileEntity != null) {\n                    NBTTagCompound nbtTagCompound = new NBTTagCompound();\n                    tileEntity.b(nbtTagCompound);\n                    return nbtTagCompound.getString(\"id\");\n                }\n            }\n\n            return \"\";\n        });\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.Chunk;\nimport net.minecraft.server.v1_8_R3.ChunkSection;\nimport net.minecraft.server.v1_8_R3.Entity;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.NBTTagFloat;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.InventoryHolder;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ChunkReaderImpl implements ChunkReader {\n\n    private static final short[] EMPTY_BLOCKS = new short[4096];\n    private static final byte[] EMPTY_DATA = new byte[2048];\n    private static final byte[] EMPTY_LIGHT = new byte[2048];\n\n    private final int x;\n    private final int z;\n\n    private final Map<BlockPosition, CompoundTag> tileEntities = new HashMap<>();\n    private final List<CachedEntity> entities = new LinkedList<>();\n    private final short[][] blockids;\n    private final byte[][] blockdata;\n    private final byte[][] skylight;\n    private final byte[][] emitlight;\n\n    public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) {\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n\n        this.x = chunk.locX;\n        this.z = chunk.locZ;\n\n        ChunkSection[] chunkSections = chunk.getSections();\n        this.blockids = new short[chunkSections.length][];\n        this.blockdata = new byte[chunkSections.length][];\n        this.skylight = new byte[chunkSections.length][];\n        this.emitlight = new byte[chunkSections.length][];\n\n        for (int i = 0; i < this.blockids.length; ++i) {\n            ChunkSection chunkSection = chunkSections[i];\n\n            if (chunkSection == null) {\n                this.blockids[i] = EMPTY_BLOCKS;\n                this.blockdata[i] = EMPTY_DATA;\n                this.skylight[i] = EMPTY_LIGHT;\n                this.emitlight[i] = EMPTY_LIGHT;\n            } else {\n                copyBlockIds(chunkSection.getIdArray(), i);\n\n                if (chunkSection.getSkyLightArray() == null) {\n                    skylight[i] = EMPTY_LIGHT;\n                } else {\n                    skylight[i] = new byte[2048];\n                    System.arraycopy(chunkSection.getSkyLightArray().a(), 0, skylight[i], 0, 2048);\n                }\n\n                emitlight[i] = new byte[2048];\n                System.arraycopy(chunkSection.getEmittedLightArray().a(), 0, emitlight[i], 0, 2048);\n            }\n        }\n\n        chunk.getTileEntities().forEach((blockPosition, tileEntity) -> {\n            NBTTagCompound tileEntityCompound = new NBTTagCompound();\n            tileEntity.b(tileEntityCompound);\n\n            tileEntityCompound.remove(\"x\");\n            tileEntityCompound.remove(\"y\");\n            tileEntityCompound.remove(\"z\");\n\n            InventoryHolder inventoryHolder = tileEntity.getOwner();\n            if (inventoryHolder != null)\n                tileEntityCompound.setString(\"inventoryType\", inventoryHolder.getInventory().getType().name());\n\n            tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound));\n        });\n\n        for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities())\n            entities.add(new CachedEntity(((CraftEntity) entity).getHandle()));\n    }\n\n    @Override\n    public int getX() {\n        return this.x;\n    }\n\n    @Override\n    public int getZ() {\n        return this.z;\n    }\n\n    @Override\n    public Material getType(int x, int y, int z) {\n        return Material.getMaterial(this.getBlockId(x, y, z));\n    }\n\n    @Override\n    public short getData(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15);\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag getTileEntity(int x, int y, int z) {\n        try (ObjectsPools.Wrapper<BlockPosition.MutableBlockPosition> wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) {\n            BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle();\n            blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z);\n            return this.tileEntities.get(blockPosition);\n        }\n    }\n\n    @Override\n    @Nullable\n    public CompoundTag readBlockStates(int x, int y, int z) {\n        // Doesn't exist\n        return null;\n    }\n\n    @Override\n    public byte[] getLightLevels(int x, int y, int z) {\n        int off = (y & 15) << 7 | z << 3 | x >> 1;\n        int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15;\n        return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel};\n    }\n\n    @Override\n    public void forEachEntity(EntityConsumer consumer) {\n        if (entities.isEmpty())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = wrapper.getHandle();\n            for (CachedEntity cachedEntity : entities) {\n                location.setX(cachedEntity.x);\n                location.setY(cachedEntity.y);\n                location.setZ(cachedEntity.z);\n                location.setYaw(cachedEntity.yaw);\n                location.setPitch(cachedEntity.pitch);\n                consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location);\n            }\n        }\n    }\n\n    private int getBlockId(int x, int y, int z) {\n        return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x];\n    }\n\n    private void copyBlockIds(char[] baseids, int i) {\n        short[] blockids = this.blockids[i] = new short[4096];\n        byte[] dataValues = this.blockdata[i] = new byte[2048];\n\n        for (int j = 0; j < 4096; ++j) {\n            if (baseids[j] != 0) {\n                IBlockData blockData = Block.d.a(baseids[j]);\n                if (blockData != null) {\n                    blockids[j] = (short) Block.getId(blockData.getBlock());\n                    int data = blockData.getBlock().toLegacyData(blockData);\n                    int k = j >> 1;\n                    if ((j & 1) == 0) {\n                        dataValues[k] = (byte) (dataValues[k] & 240 | data & 15);\n                    } else {\n                        dataValues[k] = (byte) (dataValues[k] & 15 | (data & 15) << 4);\n                    }\n                }\n            }\n        }\n    }\n\n    private static class CachedEntity {\n\n        private final double x;\n        private final double y;\n        private final double z;\n        private final float yaw;\n        private final float pitch;\n        private final EntityType entityType;\n        private final CompoundTag entityTag;\n\n        CachedEntity(Entity entity) {\n            this.x = entity.locX;\n            this.y = entity.locY;\n            this.z = entity.locZ;\n            this.yaw = entity.yaw;\n            this.pitch = entity.pitch;\n            this.entityType = entity.getBukkitEntity().getType();\n\n            NBTTagCompound nbtTagCompound = new NBTTagCompound();\n            entity.c(nbtTagCompound);\n            nbtTagCompound.set(\"Yaw\", new NBTTagFloat(entity.yaw));\n            nbtTagCompound.set(\"Pitch\", new NBTTagFloat(entity.pitch));\n\n            this.entityTag = CompoundTag.fromNBT(nbtTagCompound);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class KeyBlocksCache {\n\n    private static final Map<IBlockData, Key> BLOCK_TO_KEY = new IdentityHashMap<>();\n\n    private KeyBlocksCache() {\n\n    }\n\n    public static Key getBlockKey(IBlockData blockData) {\n        return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> {\n            Block block = blockData.getBlock();\n            Material blockType = CraftMagicNumbers.getMaterial(block);\n            if (blockType == null)\n                return null;\n            byte data = (byte) block.toLegacyData(blockData);\n            return Keys.of(blockType, data);\n        });\n    }\n\n    public static void cacheAllBlocks() {\n        Block.d.forEach(KeyBlocksCache::getBlockKey);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport org.bukkit.Location;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class WorldEditSessionDataImpl implements WorldEditSession.Data {\n\n    private final List<PositionedObject<WorldEditSessionImpl.ChunkData>> chunks = new LinkedList<>();\n    private final List<PositionedObject<IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<PositionedObject<CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<PositionedObject<Void>> lights = new LinkedList<>();\n\n    public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks,\n                                    List<Pair<BlockPosition, IBlockData>> blocksToUpdate,\n                                    List<Pair<BlockPosition, CompoundTag>> blockEntities,\n                                    List<BlockPosition> lights) {\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // Convert chunk data\n        Iterator<Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData>> chunksIterator = chunks.entryIterator();\n        while (chunksIterator.hasNext()) {\n            Long2ObjectMapView.Entry<WorldEditSessionImpl.ChunkData> entry = chunksIterator.next();\n            int currChunkPosXAxis = getChunkCoordX(entry.getKey());\n            int currChunkPosZAxis = getChunkCoordZ(entry.getKey());\n            this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis,\n                    currChunkPosZAxis - baseChunkPosZAxis, entry.getValue()));\n        }\n\n        // Convert blocksToUpdate\n        blocksToUpdate.forEach(blockToUpdate -> {\n            BlockPosition blockPosition = blockToUpdate.getKey();\n            this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis,\n                    blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis,\n                    blockToUpdate.getValue()));\n        });\n\n        // Convert blockEntities\n        blockEntities.forEach(blockEntity -> {\n            BlockPosition blockPosition = blockEntity.getKey();\n            this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis,\n                    blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis,\n                    blockEntity.getValue()));\n        });\n\n        // Convert lights\n        lights.forEach(lightPosition -> {\n            this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis,\n                    lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis,\n                    null));\n        });\n    }\n\n    public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView<WorldEditSessionImpl.ChunkData> chunks) {\n        this.chunks.forEach(chunkDataPositioned -> {\n            long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset,\n                    baseChunkPosZAxis + chunkDataPositioned.zOffset);\n            chunks.put(newPos, chunkDataPositioned.object);\n        });\n    }\n\n    public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, IBlockData>> blocksToUpdate) {\n        this.blocksToUpdate.forEach(blockToUpdatePositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset,\n                    baseBlockPosYAxis + blockToUpdatePositioned.yOffset,\n                    baseBlockPosZAxis + blockToUpdatePositioned.zOffset);\n            blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object));\n        });\n    }\n\n    public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<Pair<BlockPosition, CompoundTag>> blockEntities) {\n        this.blockEntities.forEach(blockEntityPositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset,\n                    baseBlockPosYAxis + blockEntityPositioned.yOffset,\n                    baseBlockPosZAxis + blockEntityPositioned.zOffset);\n            blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object));\n        });\n    }\n\n    public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List<BlockPosition> lights) {\n        this.lights.forEach(lightPositioned -> {\n            BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset,\n                    baseBlockPosYAxis + lightPositioned.yOffset,\n                    baseBlockPosZAxis + lightPositioned.zOffset);\n            lights.add(newPos);\n        });\n    }\n\n    private static int getChunkCoordX(long i) {\n        return (int) (i & 4294967295L);\n    }\n\n    private static int getChunkCoordZ(long i) {\n        return (int) (i >>> 32 & 4294967295L);\n    }\n\n    private static class PositionedObject<V> {\n\n        private final int xOffset;\n        private final int yOffset;\n        private final int zOffset;\n        private final V object;\n\n        PositionedObject(int xOffset, int zOffset, V object) {\n            this(xOffset, 0, zOffset, object);\n        }\n\n        PositionedObject(int xOffset, int yOffset, int zOffset, V object) {\n            this.xOffset = xOffset;\n            this.yOffset = yOffset;\n            this.zOffset = zOffset;\n            this.object = object;\n        }\n\n    }\n\n}"
  },
  {
    "path": "NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v1_8_R3.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.google.common.base.Preconditions;\nimport net.minecraft.server.v1_8_R3.BiomeBase;\nimport net.minecraft.server.v1_8_R3.Block;\nimport net.minecraft.server.v1_8_R3.BlockBed;\nimport net.minecraft.server.v1_8_R3.BlockPosition;\nimport net.minecraft.server.v1_8_R3.Chunk;\nimport net.minecraft.server.v1_8_R3.ChunkCoordIntPair;\nimport net.minecraft.server.v1_8_R3.ChunkSection;\nimport net.minecraft.server.v1_8_R3.EnumSkyBlock;\nimport net.minecraft.server.v1_8_R3.IBlockData;\nimport net.minecraft.server.v1_8_R3.NBTTagCompound;\nimport net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;\nimport net.minecraft.server.v1_8_R3.TileEntity;\nimport net.minecraft.server.v1_8_R3.WorldServer;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.craftbukkit.v1_8_R3.CraftChunk;\nimport org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock;\nimport org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator;\nimport org.bukkit.generator.ChunkGenerator;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class WorldEditSessionImpl implements WorldEditSession {\n\n    private static final ReflectMethod<Boolean> WORLD_SERVER_UPDATE_LIGHT_PAPER = new ReflectMethod<>(\n            net.minecraft.server.v1_8_R3.World.class, \"updateLight\", EnumSkyBlock.class, BlockPosition.class);\n\n    private static final ObjectsPool<WorldEditSessionImpl> POOL = new ObjectsPool<>(WorldEditSessionImpl::new);\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Long2ObjectMapView<ChunkData> chunks = CollectionsFactory.createLong2ObjectArrayMap();\n    private final List<Pair<BlockPosition, IBlockData>> blocksToUpdate = new LinkedList<>();\n    private final List<Pair<BlockPosition, CompoundTag>> blockEntities = new LinkedList<>();\n    private final List<BlockPosition> lights = new LinkedList<>();\n\n    private Dimension dimension;\n\n    @Nullable\n    private WorldServer worldServer;\n\n    public static WorldEditSessionImpl obtain(WorldServer worldServer) {\n        return POOL.obtain().initialize(worldServer);\n    }\n\n    public static WorldEditSessionImpl obtain(Dimension dimension) {\n        return POOL.obtain().initialize(dimension);\n    }\n\n    private WorldEditSessionImpl() {\n    }\n\n    private WorldEditSessionImpl initialize(WorldServer worldServer) {\n        this.worldServer = worldServer;\n        this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld());\n        return this;\n    }\n\n    private WorldEditSessionImpl initialize(Dimension dimension) {\n        this.worldServer = null;\n        this.dimension = dimension;\n        return this;\n    }\n\n    @Override\n    public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag,\n                         @Nullable CompoundTag blockEntityData) {\n        BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n\n        if (!isValidPosition(blockPosition))\n            return;\n\n        IBlockData blockData = Block.getByCombinedId(combinedId);\n        Block block = blockData.getBlock();\n\n        if ((block.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || block instanceof BlockBed) {\n            blocksToUpdate.add(new Pair<>(blockPosition, blockData));\n            return;\n        }\n\n        int chunkX = blockPosition.getX() >> 4;\n        int chunkZ = blockPosition.getZ() >> 4;\n\n        if (blockEntityData != null)\n            blockEntities.add(new Pair<>(blockPosition, blockEntityData));\n\n        if (plugin.getSettings().isLightsUpdate() && block.r() > 0)\n            this.lights.add(blockPosition);\n\n        ChunkData chunkData = this.chunks.computeIfAbsent(ChunkCoordIntPair.a(chunkX, chunkZ), ChunkData::new);\n\n        ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4];\n\n        int blockX = blockPosition.getX() & 15;\n        int blockY = blockPosition.getY();\n        int blockZ = blockPosition.getZ() & 15;\n\n        chunkSection.setType(blockX, blockY & 15, blockZ, blockData);\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#getAffectedChunks on partial initialized session\");\n\n        if (chunks.isEmpty())\n            return Collections.emptyList();\n\n        List<ChunkPosition> chunkPositions = new LinkedList<>();\n        World bukkitWorld = worldServer.getWorld();\n        LongIterator iterator = chunks.keyIterator();\n        while (iterator.hasNext()) {\n            long chunkKey = iterator.next();\n            int chunkX = (int) chunkKey;\n            int chunkZ = (int) (chunkKey >> 32);\n            chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false));\n        }\n        return chunkPositions;\n    }\n\n    @Override\n    public void applyBlocks(org.bukkit.Chunk bukkitChunk) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#applyBlocks on partial initialized session\");\n\n        Chunk chunk = ((CraftChunk) bukkitChunk).getHandle();\n\n        ChunkData chunkData = this.chunks.get(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));\n\n        if (chunkData == null)\n            return;\n\n        int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length);\n        for (int i = 0; i < chunkSectionsCount; ++i) {\n            chunk.getSections()[i] = chunkData.chunkSections[i];\n        }\n\n        // Update the biome for the chunk\n        BiomeBase biome = CraftBlock.biomeToBiomeBase(IslandUtils.getDefaultWorldBiome(this.dimension));\n        Arrays.fill(chunk.getBiomeIndex(), (byte) biome.id);\n\n        if (plugin.getSettings().isLightsUpdate()) {\n            // initLightning calculates the light emitted from sky to the chunk.\n            chunk.initLighting();\n        }\n\n        chunk.e();\n    }\n\n    @Override\n    public void finish(Island island) {\n        Preconditions.checkState(this.worldServer != null, \"Cannot call WorldEditSession#finish on partial initialized session\");\n\n        // Update blocks\n        blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3));\n\n        // Update block entities\n        blockEntities.forEach(data -> {\n            NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT();\n            if (blockEntityCompound != null) {\n                BlockPosition blockPosition = data.getKey();\n                blockEntityCompound.setInt(\"x\", blockPosition.getX());\n                blockEntityCompound.setInt(\"y\", blockPosition.getY());\n                blockEntityCompound.setInt(\"z\", blockPosition.getZ());\n                TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition);\n                if (worldTileEntity != null)\n                    worldTileEntity.a(blockEntityCompound);\n            }\n        });\n\n        if (plugin.getSettings().isLightsUpdate() && !lights.isEmpty()) {\n            // For each light block, we calculate its light\n            // We only update the lights after all the chunks were loaded.\n            BukkitExecutor.sync(() -> {\n                if (WORLD_SERVER_UPDATE_LIGHT_PAPER.isValid()) {\n                    lights.forEach(blockPosition -> WORLD_SERVER_UPDATE_LIGHT_PAPER.invoke(worldServer, EnumSkyBlock.BLOCK, blockPosition));\n                } else {\n                    lights.forEach(blockPosition -> worldServer.c(EnumSkyBlock.BLOCK, blockPosition));\n                }\n\n                LongIterator iterator = this.chunks.keyIterator();\n                while (iterator.hasNext()) {\n                    long chunkKey = iterator.next();\n                    ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32));\n                    NMSUtils.sendPacketToRelevantPlayers(worldServer, chunkCoord.x, chunkCoord.z,\n                            new PacketPlayOutMapChunk(worldServer.getChunkAt(chunkCoord.x, chunkCoord.z), true, 65535));\n                }\n            }, 5L);\n        }\n\n        release();\n    }\n\n    @Override\n    public Data readData(Location baseLocation) {\n        return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights);\n    }\n\n    @Override\n    public void applyData(Data data, Location baseLocation) {\n        WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data;\n\n        int baseBlockPosXAxis = baseLocation.getBlockX();\n        int baseBlockPosYAxis = baseLocation.getBlockY();\n        int baseBlockPosZAxis = baseLocation.getBlockZ();\n        int baseChunkPosXAxis = baseBlockPosXAxis >> 4;\n        int baseChunkPosZAxis = baseBlockPosZAxis >> 4;\n\n        // We need to transform all data to the new base location values\n\n        dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks);\n        dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate);\n        dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities);\n        dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights);\n    }\n\n    @Override\n    public void release() {\n        this.chunks.clear();\n        this.blocksToUpdate.clear();\n        this.blockEntities.clear();\n        this.lights.clear();\n        this.worldServer = null;\n        this.dimension = null;\n        POOL.release(this);\n    }\n\n    private boolean isValidPosition(BlockPosition blockPosition) {\n        return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 &&\n                blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 &&\n                blockPosition.getY() >= 0 && blockPosition.getY() < 256;\n    }\n\n    public class ChunkData {\n\n        private final ChunkSection[] chunkSections = new ChunkSection[16];\n\n        private ChunkData(long chunkKey) {\n            ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32));\n            createChunkSections();\n            if (worldServer != null)\n                runCustomWorldGenerator(chunkCoord);\n        }\n\n        private void createChunkSections() {\n            boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END;\n\n            for (int i = 0; i < this.chunkSections.length; ++i) {\n                int chunkSectionPos = i << 4;\n                this.chunkSections[i] = new ChunkSection(chunkSectionPos, hasSkyLight);\n            }\n        }\n\n        private void runCustomWorldGenerator(ChunkCoordIntPair chunkCoord) {\n            ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator();\n\n            if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n                return;\n\n            CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getSeed(), bukkitGenerator);\n            Chunk generatedChunk = chunkGenerator.getOrCreateChunk(chunkCoord.x, chunkCoord.z);\n\n            for (int i = 0; i < this.chunkSections.length; ++i) {\n                ChunkSection generatorChunkSection = generatedChunk.getSections()[i];\n                if (generatorChunkSection != null)\n                    this.chunkSections[i] = generatorChunkSection;\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/build.gradle",
    "content": "plugins {\n    id(\"io.papermc.paperweight.userdev\") version \"2.0.0-beta.21\"\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(25))\n    }\n}\n\npaperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.getMOJANG_PRODUCTION()\n\ngroup 'NMS:v26_1'\n\ndependencies {\n    paperweight.paperDevBundle(\"26.1.1.build.+\")\n    compileOnly project(\":NMS:Spigot-1_20_3\")\n    compileOnly project(\":NMS:Paper-1_20_3\")\n    compileOnly project(\":API\")\n    compileOnly project(\":\")\n}\n\nif (project.hasProperty('nms.compile_v26_1') && !Boolean.valueOf(project.findProperty(\"nms.compile_v26_1\").toString())) {\n    project.tasks.all { task -> task.enabled = false }\n}"
  },
  {
    "path": "NMS/v26_1/properties",
    "content": "NMS_VERSION=v26_1\nCRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit\nCOMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3\nPAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController\nREGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries\nCHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus\nSERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource\nSTAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface\nABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart\nGET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED)\nEND_DRAGON_FIGHT_CLASS=EnderDragonFight\nSPIKE_FEATURE_CLASS=EndSpikeFeature"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParseException;\nimport com.mojang.serialization.JsonOps;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.network.chat.ComponentSerialization;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.NamespacedKey;\nimport org.bukkit.Registry;\nimport org.bukkit.block.Biome;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.inventory.ItemRarity;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ArmorMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.trim.ArmorTrim;\nimport org.bukkit.inventory.meta.trim.TrimMaterial;\nimport org.bukkit.inventory.meta.trim.TrimPattern;\n\nimport java.lang.reflect.Modifier;\nimport java.util.Locale;\n\npublic class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms {\n\n    public static final ReflectField<double[]> SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class,\n            double[].class, Modifier.PUBLIC | Modifier.FINAL, 1);\n\n    private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create();\n\n    @Override\n    public String parseSignLine(String original) {\n        RegistryOps<JsonElement> context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE);\n        JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0])\n                .getOrThrow(JsonParseException::new);\n        return COMPONENT_GSON.toJson(jsonElement);\n    }\n\n    @Override\n    public void setItemModel(ItemMeta itemMeta, String itemModel) {\n        itemMeta.setItemModel(NamespacedKey.fromString(itemModel));\n    }\n\n    @Override\n    public void setRarity(ItemMeta itemMeta, String rarity) {\n        itemMeta.setRarity(ItemRarity.valueOf(rarity));\n    }\n\n    @Override\n    public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) {\n        if (itemMeta instanceof ArmorMeta armorMeta) {\n            Registry<TrimMaterial> materialRegistry = Bukkit.getRegistry(TrimMaterial.class);\n            Registry<TrimPattern> patternRegistry = Bukkit.getRegistry(TrimPattern.class);\n\n            if (materialRegistry == null || patternRegistry == null) {\n                return;\n            }\n\n            TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial));\n            TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern));\n\n            if (material == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimMaterial.toUpperCase(Locale.ENGLISH) +\n                        \" into trim material, skipping...\");\n            if (pattern == null)\n                throw new IllegalArgumentException(\"Couldn't convert \" + trimPattern.toUpperCase(Locale.ENGLISH) +\n                        \" into trim pattern, skipping...\");\n\n            ArmorTrim armorTrim = new ArmorTrim(material, pattern);\n            armorMeta.setTrim(armorTrim);\n        }\n    }\n\n    @Override\n    public void setHideTooltip(ItemMeta itemMeta) {\n        itemMeta.setHideTooltip(true);\n    }\n\n    @Override\n    public String getMinecraftKey(ItemStack itemStack) {\n        return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString();\n    }\n\n    @Override\n    public void makeItemGlow(ItemMeta itemMeta) {\n        itemMeta.setEnchantmentGlintOverride(true);\n    }\n\n    @Override\n    public double getCurrentTps() {\n        return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0];\n    }\n\n    @Override\n    public Biome getBiome(String biomeName) {\n        NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH));\n        if (key == null) {\n            return null;\n        }\n\n        Registry<Biome> registry = Bukkit.getRegistry(Biome.class);\n        if (registry == null) {\n            return null;\n        }\n\n        return registry.get(key);\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.mojang.logging.LogUtils;\nimport com.mojang.serialization.Codec;\nimport com.mojang.serialization.DataResult;\nimport com.mojang.serialization.Dynamic;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;\nimport net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.util.datafix.DataFixers;\nimport net.minecraft.util.datafix.fixes.References;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.lighting.LevelLightEngine;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.entity.CraftPlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\n\nimport static com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY;\n\npublic class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSChunks {\n\n    private static final ReflectMethod<Codec<PalettedContainer<Holder<Biome>>>> CONTAINER_FACTORY_BIOME_RW_CODEC =\n            new ReflectMethod<>(PalettedContainerFactory.class, \"biomeContainerCodecRW\");\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    public NMSChunksImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection<Player> playersToUpdate) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                ChunkPos chunkPos = levelChunk.getPos();\n\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    LevelChunkSection currentSection = chunkSections[i];\n                    if (currentSection != null) {\n                        PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                        chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer);\n                    }\n                }\n\n                levelChunk.markUnsaved();\n\n                ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos);\n                ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket(\n                        levelChunk, levelChunk.level.getLightEngine(), null, null);\n\n                playersToUpdate.forEach(player -> {\n                    ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();\n                    serverPlayer.connection.send(forgetLevelChunkPacket);\n                    serverPlayer.connection.send(mapChunkPacket);\n                });\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome);\n\n                PalettedContainer<Holder<Biome>> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome);\n                DataResult<Tag> dataResult = getBiomeContainerRWCodec()\n                        .encodeStart(NbtOps.INSTANCE, biomesContainer);\n                Tag biomesCompound = dataResult.getOrThrow();\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n\n                for (int i = 0; i < sectionsList.size(); ++i)\n                    sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"biomes\", biomesCompound));\n            }\n\n            @Override\n            public void onFinish() {\n                // Do nothing.\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                LevelChunkSection[] chunkSections = levelChunk.getSections();\n                for (int i = 0; i < chunkSections.length; ++i) {\n                    chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY);\n                }\n\n                removeEntities(levelChunk);\n                removeBlockEntities(levelChunk);\n                removeBlocks(levelChunk);\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n\n                ListTag tileEntities = new ListTag();\n\n                chunkCompound.put(\"Entities\", new ListTag());\n                chunkCompound.put(\"block_entities\", tileEntities);\n\n                if (serverLevel.generator instanceof IslandsGenerator) {\n                    PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                    DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                            .encodeStart(NbtOps.INSTANCE, statesContainer);\n                    Tag blockStatesCompound = dataResult.getOrThrow();\n\n                    ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                    for (int i = 0; i < sectionsList.size(); ++i)\n                        sectionsList.getCompound(i).ifPresent(compound -> compound.put(\"block_states\", blockStatesCompound));\n                } else {\n                    ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel);\n\n                    try {\n                        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk);\n                    } catch (Exception ignored) {\n                    }\n\n                    LevelLightEngine lightEngine = serverLevel.getLightEngine();\n                    LevelChunkSection[] chunkSections = protoChunk.getSections();\n\n                    ListTag sectionsList = new ListTag();\n\n                    // Save blocks\n                    for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) {\n                        int chunkSectionIndex = serverLevel.getSectionIndex(i);\n\n                        CompoundTag sectionCompound = new CompoundTag();\n\n                        if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) {\n                            LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex];\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates());\n                                sectionCompound.put(\"block_states\", dataResult.getOrThrow());\n                            }\n\n                            {\n                                DataResult<Tag> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec()\n                                        .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes());\n                                sectionCompound.put(\"biomes\", dataResult.getOrThrow());\n                            }\n                        }\n\n                        if (!sectionCompound.isEmpty()) {\n                            sectionCompound.putByte(\"Y\", (byte) i);\n                            sectionsList.add(sectionCompound);\n                        }\n                    }\n\n                    for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) {\n                        CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos,\n                                MinecraftServer.getServer().registryAccess());\n                        if (blockEntityCompound != null)\n                            tileEntities.add(blockEntityCompound);\n                    }\n\n                    chunkCompound.put(\"sections\", sectionsList);\n                }\n            }\n\n            @Override\n            public void onFinish() {\n                if (onFinish != null)\n                    onFinish.run();\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture<List<CalculatedChunk.Blocks>> completableFuture,\n                                                               Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache,\n                                                               List<CalculatedChunk.Blocks> allCalculatedChunks) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false);\n                allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections()));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition();\n                ServerLevel serverLevel = unloadedChunkCompound.serverLevel();\n                CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound();\n\n                LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()];\n\n                ListTag sectionsList = chunkCompound.getListOrEmpty(\"sections\");\n                for (int i = 0; i < sectionsList.size(); ++i) {\n                    CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i);\n                    byte yPosition = sectionCompound.getByteOr(\"Y\", (byte) 0);\n                    int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition);\n\n                    if (sectionIndex >= 0 && sectionIndex < chunkSections.length) {\n                        PalettedContainer<BlockState> blocksPalettedContainer;\n                        Optional<CompoundTag> blockStatesCompound = sectionCompound.getCompound(\"block_states\");\n                        if (blockStatesCompound.isPresent()) {\n                            DataResult<PalettedContainer<BlockState>> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY\n                                    .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            blocksPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n                        }\n\n                        PalettedContainer<Holder<Biome>> biomesPalettedContainer;\n                        Optional<CompoundTag> biomesCompound = sectionCompound.getCompound(\"biomes\");\n                        if (biomesCompound.isPresent()) {\n                            DataResult<PalettedContainer<Holder<Biome>>> dataResult = getBiomeContainerRWCodec()\n                                    .parse(NbtOps.INSTANCE, biomesCompound.get())\n                                    .promotePartial((sx) -> {\n                                    });\n                            biomesPalettedContainer = dataResult.getOrThrow();\n                        } else {\n                            biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes();\n                        }\n\n                        chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer);\n                    }\n\n                }\n\n                CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections);\n                allCalculatedChunks.add(calculatedChunk);\n                unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                completableFuture.complete(allCalculatedChunks);\n            }\n        };\n    }\n\n    @Override\n    protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List<CalculatedChunk.Entities> allCalculatedChunks,\n                                                              List<NMSUtils.UnloadedChunkCompound> unloadedChunkCompounds,\n                                                              CompletableFuture<List<CalculatedChunk.Entities>> completableFuture) {\n        return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) {\n            @Override\n            public void onLoadedChunk(LevelChunk levelChunk) {\n                ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false);\n                allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk));\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) {\n                unloadedChunkCompounds.add(unloadedChunkCompound);\n\n                latchCountDown();\n            }\n\n            @Override\n            public void onFinish() {\n                BukkitExecutor.ensureMain(() -> {\n                    for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) {\n                        ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty(\"Entities\");\n                        allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(),\n                                unloadedChunkCompound.serverLevel(), entitiesTag));\n                    }\n\n                    completableFuture.complete(allCalculatedChunks);\n                });\n            }\n        };\n    }\n\n    @Override\n    protected Optional<Entity> createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) {\n        int dataVersion = compoundTag.getIntOr(\"DataVersion\", 0);\n        if (dataVersion < com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION) {\n            compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK,\n                    new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion,\n                    com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION).getValue();\n        }\n\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag);\n            return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL);\n        }\n    }\n\n    private static void removeBlocks(ChunkAccess chunk) {\n        ServerLevel serverLevel = ((LevelChunk) chunk).level;\n        ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator();\n\n        if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator)\n            return;\n\n        NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk);\n    }\n\n    private static Codec<PalettedContainer<Holder<Biome>>> getBiomeContainerRWCodec() {\n        if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) {\n            return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY);\n        } else {\n            return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec();\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1;\n\nimport net.minecraft.tags.ItemTags;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.PortalProcessor;\nimport org.bukkit.craftbukkit.entity.CraftMinecartFurnace;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.bukkit.entity.minecart.PoweredMinecart;\n\npublic class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSEntities {\n\n    @Override\n    public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) {\n        return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 &&\n                CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL);\n    }\n\n    @Override\n    protected int getPortalTicks(Entity entity) {\n        PortalProcessor portalProcessor = entity.portalProcess;\n        return portalProcessor == null ? 0 : portalProcessor.getPortalTime();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1;\n\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.google.common.collect.HashMultimap;\nimport com.google.common.collect.Multimap;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.Property;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.component.DataComponents;\nimport net.minecraft.nbt.ByteArrayTag;\nimport net.minecraft.nbt.IntArrayTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.nbt.NumericTag;\nimport net.minecraft.nbt.StringTag;\nimport net.minecraft.nbt.Tag;\nimport net.minecraft.resources.RegistryOps;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.util.Util;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.EntityType;\nimport net.minecraft.world.item.ItemStack;\nimport net.minecraft.world.item.component.CustomData;\nimport net.minecraft.world.item.component.ResolvableProfile;\nimport org.bukkit.Location;\nimport org.bukkit.craftbukkit.inventory.CraftItemStack;\nimport org.slf4j.Logger;\n\nimport java.util.Set;\n\npublic class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSTags {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    @Override\n    public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) {\n        ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);\n\n        Multimap<String, Property> properties = HashMultimap.create();\n        properties.put(\"textures\", new Property(\"textures\", texture));\n\n        GameProfile gameProfile = new GameProfile(Util.NIL_UUID, \"\", new PropertyMap(properties));\n\n        ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile);\n\n        itemStack.set(DataComponents.PROFILE, resolvableProfile);\n\n        return CraftItemStack.asBukkitCopy(itemStack);\n    }\n\n    @Override\n    protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) {\n        RegistryOps<Tag> context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag)\n                ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow();\n        tagCompound.putInt(\"DataVersion\", com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION);\n\n        return CompoundTag.fromNBT(tagCompound);\n    }\n\n    @Override\n    protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) {\n        return compoundTag.getIntOr(key, def);\n    }\n\n    @Override\n    protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) {\n        RegistryOps<Tag> context =\n                MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE);\n\n        return ItemStack.CODEC.parse(context, compoundTag)\n                .resultOrPartial((itemId) -> LOGGER.error(\"Tried to load invalid item: '{}'\", itemId))\n                .orElseThrow();\n    }\n\n    @Override\n    protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) {\n        itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag));\n    }\n\n    @Override\n    protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) {\n        EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> {\n            entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot());\n            return !serverLevel.addWithUUID(entity) ? null : entity;\n        });\n    }\n\n    @Override\n    public byte[] getNBTByteArrayValue(Object object) {\n        return ((ByteArrayTag) object).getAsByteArray();\n    }\n\n    @Override\n    public byte getNBTByteValue(Object object) {\n        return ((NumericTag) object).byteValue();\n    }\n\n    @Override\n    public Set<String> getNBTCompoundValue(Object object) {\n        return ((net.minecraft.nbt.CompoundTag) object).keySet();\n    }\n\n    @Override\n    public double getNBTDoubleValue(Object object) {\n        return ((NumericTag) object).doubleValue();\n    }\n\n    @Override\n    public float getNBTFloatValue(Object object) {\n        return ((NumericTag) object).floatValue();\n    }\n\n    @Override\n    public int[] getNBTIntArrayValue(Object object) {\n        return ((IntArrayTag) object).getAsIntArray();\n    }\n\n    @Override\n    public int getNBTIntValue(Object object) {\n        return ((NumericTag) object).intValue();\n    }\n\n    @Override\n    public Object getNBTListIndexValue(Object object, int index) {\n        return ((net.minecraft.nbt.ListTag) object).get(index);\n    }\n\n    @Override\n    public long getNBTLongValue(Object object) {\n        return ((NumericTag) object).longValue();\n    }\n\n    @Override\n    public short getNBTShortValue(Object object) {\n        return ((NumericTag) object).shortValue();\n    }\n\n    @Override\n    public String getNBTStringValue(Object object) {\n        return ((StringTag) object).value();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1;\n\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.trial.IslandPlayerDetector;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.vibration.IslandVibrationUser;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.world.BlockLevelTicksTracker;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.world.CollectingNeighborUpdaterTracker;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.block.entity.SignBlockEntity;\nimport net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\nimport net.minecraft.world.level.block.entity.trialspawner.TrialSpawner;\nimport net.minecraft.world.level.block.entity.vault.VaultBlockEntity;\nimport net.minecraft.world.level.block.entity.vault.VaultConfig;\nimport net.minecraft.world.level.border.WorldBorder;\nimport net.minecraft.world.level.chunk.ChunkGenerator;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\nimport net.minecraft.world.level.levelgen.FlatLevelSource;\nimport net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;\nimport net.minecraft.world.level.levelgen.NoiseGeneratorSettings;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.data.type.HangingSign;\nimport org.bukkit.block.data.type.WallHangingSign;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\n\nimport java.lang.reflect.Modifier;\n\npublic class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSWorld {\n\n    private static final ReflectField<VibrationSystem.User> SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField<VibrationSystem.User>(\n            SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<CollectingNeighborUpdater> COLLECTING_NEIGHBOR_UPDATER = new ReflectField<CollectingNeighborUpdater>(\n            Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal();\n    private static final ReflectField<LevelTicks<Block>> BLOCK_TICKS = new ReflectField<LevelTicks<Block>>(\n            ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal();\n\n    public NMSWorldImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) {\n        worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime());\n    }\n\n    @Override\n    protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) {\n        return signBlockEntity.getFrontText().getMessages(false);\n    }\n\n    @Override\n    protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) {\n        return chunkGenerator.getDelegate();\n    }\n\n    @Override\n    protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) {\n        return new FlatLevelSource(original.settings()) {\n            @Override\n            public int getSeaLevel() {\n                return seaLevel;\n            }\n        };\n    }\n\n    @Override\n    protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) {\n        return noiseBasedChunkGenerator.settings.value();\n    }\n\n    @Override\n    public void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class);\n        if (blockEntity == null)\n            return;\n\n        if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) {\n            VaultConfig vaultConfig = vaultBlockEntity.getConfig();\n\n            PlayerDetector playerDetector = vaultConfig.playerDetector();\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            VaultConfig newConfig = new VaultConfig(\n                    vaultConfig.lootTable(),\n                    vaultConfig.activationRange(),\n                    vaultConfig.deactivationRange(),\n                    vaultConfig.keyItem(),\n                    vaultConfig.overrideLootTableToDisplay(),\n                    IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector),\n                    vaultConfig.entitySelector()\n            );\n\n            vaultBlockEntity.setConfig(newConfig);\n        } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) {\n            TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner();\n            PlayerDetector playerDetector = trialSpawner.getPlayerDetector();\n\n            if (playerDetector instanceof IslandPlayerDetector)\n                return;\n\n            trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector));\n        }\n    }\n\n    @Override\n    public void replaceSculkSensorListener(Island island, Location location) {\n        SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class);\n        if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser)\n            return;\n\n        SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity));\n    }\n\n    @Override\n    public SignType getSignType(Object sign) {\n        if (sign instanceof HangingSign)\n            return SignType.HANGING_SIGN;\n        else if (sign instanceof WallHangingSign)\n            return SignType.HANGING_WALL_SIGN;\n        else\n            return super.getSignType(sign);\n    }\n\n    @Override\n    public void listenBlockStateChanges(World world) {\n        ServerLevel serverLevel = ((CraftWorld) world).getHandle();\n        COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel));\n        BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel));\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.dragon;\n\nimport com.bgsoftware.superiorskyblock.nms.v26_1.dragon.EndWorldEndDragonFightHandler;\nimport it.unimi.dsi.fastutil.objects.ObjectArrayList;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.dimension.end.EnderDragonFight;\n\nimport java.util.List;\nimport java.util.Optional;\n\npublic class EndDragonFightWrapper extends EnderDragonFight {\n\n    public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler();\n\n    public EndDragonFightWrapper(ServerLevel serverLevel) {\n        super(true, false, false, Optional.empty(), 0, Optional.empty(), Optional.empty(), new ObjectArrayList(), List.of());\n    }\n\n    @Override\n    public void tick() {\n        HANDLER.tick();\n    }\n\n    protected BlockPos getPortalPos() {\n        return this.exitPortalLocation;\n    }\n\n    protected void setPortalPos(BlockPos blockPos) {\n        this.exitPortalLocation = blockPos;\n    }\n\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.world.DifficultyInstance;\nimport net.minecraft.world.entity.EntitySpawnReason;\nimport net.minecraft.world.entity.SpawnGroupData;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.ServerLevelAccessor;\nimport net.minecraft.world.level.storage.ValueInput;\n\npublic class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v26_1.dragon.AbstractIslandEntityEnderDragon {\n\n    public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) {\n        super(level, islandBlockPos);\n    }\n\n    public IslandEntityEnderDragon(Level level) {\n        super(level);\n    }\n\n    @Nullable\n    @Override\n    public SpawnGroupData finalizeSpawn(ServerLevelAccessor world,\n                                        DifficultyInstance difficulty,\n                                        EntitySpawnReason spawnReason,\n                                        @Nullable SpawnGroupData entityData) {\n        if (this.islandBlockPos == null)\n            finalizeIslandEnderDragon();\n\n        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        super.readAdditionalSaveData(input);\n        finalizeIslandEnderDragon();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.hologram;\n\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.InteractionHand;\nimport net.minecraft.world.InteractionResult;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.level.storage.ValueOutput;\nimport net.minecraft.world.phys.Vec3;\n\npublic class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v26_1.hologram.AbstractEntityHologram {\n\n    public EntityHologram(ServerLevel serverLevel, double x, double y, double z) {\n        super(serverLevel, x, y, z);\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) {\n        // Do not save NBT.\n    }\n\n    @Override\n    protected void readAdditionalSaveData(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public boolean saveAsPassenger(ValueOutput output) {\n        // Do not save NBT.\n        return false;\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void saveWithoutId(ValueOutput output) {\n        // Do not save NBT.\n    }\n\n    @Override\n    public void load(ValueInput input) {\n        // Do not load NBT.\n    }\n\n    @Override\n    public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) {\n        // Prevent stand being equipped\n        return InteractionResult.PASS;\n    }\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.trial;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.entity.trialspawner.PlayerDetector;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class IslandPlayerDetector implements PlayerDetector {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final PlayerDetector original;\n    private final Supplier<IslandPrivilege> requiredPrivilege;\n\n    public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT);\n    }\n\n    public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) {\n        return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege());\n    }\n\n    private IslandPlayerDetector(Island island, PlayerDetector original, Supplier<IslandPrivilege> requiredPrivilege) {\n        this.island = island;\n        this.original = original;\n        this.requiredPrivilege = requiredPrivilege;\n    }\n\n    @Override\n    public List<UUID> detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) {\n        List<UUID> players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight);\n        IslandPrivilege requiredPrivilege = this.requiredPrivilege.get();\n        if (requiredPrivilege != null && !players.isEmpty()) {\n            players = new LinkedList<>(players);\n            players.removeIf(uuid -> {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                return !island.hasPermission(superiorPlayer, requiredPrivilege);\n            });\n            players = Collections.unmodifiableList(players);\n        }\n        return players;\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.utils;\n\nimport ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableInt;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils;\nimport com.bgsoftware.superiorskyblock.nms.v26_1.utils.TickingBlockList;\nimport com.google.gson.JsonParseException;\nimport com.mojang.authlib.GameProfile;\nimport com.mojang.authlib.properties.PropertyMap;\nimport com.mojang.logging.LogUtils;\nimport net.minecraft.core.Holder;\nimport net.minecraft.core.HolderLookup;\nimport net.minecraft.core.Registry;\nimport net.minecraft.core.registries.BuiltInRegistries;\nimport net.minecraft.core.registries.Registries;\nimport net.minecraft.nbt.CompoundTag;\nimport net.minecraft.nbt.ListTag;\nimport net.minecraft.nbt.NbtOps;\nimport net.minecraft.network.chat.Component;\nimport net.minecraft.resources.Identifier;\nimport net.minecraft.resources.ResourceKey;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.server.level.ChunkMap;\nimport net.minecraft.server.level.ClientInformation;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.server.level.ServerPlayer;\nimport net.minecraft.server.level.ThreadedLevelLightEngine;\nimport net.minecraft.server.level.WorldGenRegion;\nimport net.minecraft.util.ProblemReporter;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.item.DyeColor;\nimport net.minecraft.world.level.ChunkPos;\nimport net.minecraft.world.level.LevelHeightAccessor;\nimport net.minecraft.world.level.biome.Biome;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.entity.BlockEntity;\nimport net.minecraft.world.level.block.entity.BlockEntityType;\nimport net.minecraft.world.level.block.entity.SignText;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.block.state.properties.Property;\nimport net.minecraft.world.level.chunk.ChunkAccess;\nimport net.minecraft.world.level.chunk.LevelChunk;\nimport net.minecraft.world.level.chunk.LevelChunkSection;\nimport net.minecraft.world.level.chunk.PalettedContainer;\nimport net.minecraft.world.level.chunk.PalettedContainerFactory;\nimport net.minecraft.world.level.chunk.ProtoChunk;\nimport net.minecraft.world.level.chunk.Strategy;\nimport net.minecraft.world.level.chunk.UpgradeData;\nimport net.minecraft.world.level.chunk.status.ChunkPyramid;\nimport net.minecraft.world.level.chunk.status.ChunkStatus;\nimport net.minecraft.world.level.chunk.status.ChunkStep;\nimport net.minecraft.world.level.chunk.storage.EntityStorage;\nimport net.minecraft.world.level.chunk.storage.SimpleRegionStorage;\nimport net.minecraft.world.level.dimension.DimensionType;\nimport net.minecraft.world.level.dimension.LevelStem;\nimport net.minecraft.world.level.dimension.end.EnderDragonFight;\nimport net.minecraft.world.level.entity.PersistentEntitySectionManager;\nimport net.minecraft.world.level.storage.TagValueInput;\nimport net.minecraft.world.level.storage.TagValueOutput;\nimport net.minecraft.world.level.storage.ValueInput;\nimport net.minecraft.world.ticks.ProtoChunkTicks;\nimport org.bukkit.Material;\nimport org.bukkit.craftbukkit.CraftWorld;\nimport org.bukkit.craftbukkit.block.CraftBiome;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.generator.CustomChunkGenerator;\nimport org.bukkit.craftbukkit.util.CraftChatMessage;\nimport org.bukkit.craftbukkit.util.CraftMagicNumbers;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.slf4j.Logger;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\npublic class NMSUtilsVersioned {\n\n    private static final Logger LOGGER = LogUtils.getLogger();\n\n    private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0];\n\n    private static final ReflectField<PersistentEntitySectionManager<Entity>> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>(\n            ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1);\n    private static final ReflectField<SimpleRegionStorage> ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>(\n            EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1);\n\n    public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create(\n            MinecraftServer.getServer().registryAccess());\n\n    public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) {\n        return chunkMap.read(chunkPos).join().orElse(null);\n    }\n\n    public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) {\n        return chunkMap.upgradeChunkTag(chunkCompoundTag);\n    }\n\n    public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) {\n        chunkMap.write(chunkPos, () -> chunkCompoundTag);\n    }\n\n    public static BukkitExecutor.NestedTask<Void> runActionOnUnloadedEntityChunks(\n            Collection<ChunkPosition> chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) {\n        if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) {\n            return BukkitExecutor.createTask().runSync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    PersistentEntitySectionManager<Entity> entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel);\n                    SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage);\n\n                    ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ());\n\n                    regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> {\n                        if (error != null) {\n                            countDownLatch.countDown();\n                            throw new RuntimeException(error);\n                        } else {\n                            CompoundTag entityData = entityDataOptional.orElse(null);\n                            if (entityData == null) {\n                                chunkCallback.onChunkNotExist(chunkPosition);\n                            } else {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                            }\n                        }\n                    });\n                });\n            });\n        } else {\n            return BukkitExecutor.createTask().runAsync(v -> {\n                chunks.forEach(chunkPosition -> {\n                    ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle();\n\n                    try {\n                        MoonriseRegionFileIO.RegionDataController regionDataController =\n                                serverLevel.moonrise$getEntityChunkDataController();\n                        int chunkX = chunkPosition.getX();\n                        int chunkZ = chunkPosition.getZ();\n                        MoonriseRegionFileIO.RegionDataController.ReadData readData =\n                                regionDataController.readData(chunkX, chunkZ);\n                        if (readData != null) {\n                            CompoundTag entityData = switch (readData.result()) {\n                                case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData);\n                                case SYNC_READ -> readData.syncRead();\n                                default -> null;\n                            };\n                            if (entityData != null) {\n                                NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData);\n                                chunkCallback.onUnloadedChunk(unloadedChunkCompound);\n                                return;\n                            }\n                        }\n\n                        chunkCallback.onChunkNotExist(chunkPosition);\n                    } catch (IOException error) {\n                        countDownLatch.countDown();\n                        Log.error(error, \"An unexpected error occurred while interacting with unloaded chunk \", chunkPosition, \":\");\n                    }\n                });\n            });\n        }\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos,\n                UpgradeData.EMPTY,\n                serverLevel,\n                DEFAULT_PALETTED_CONTAINER_FACTORY,\n                null);\n    }\n\n    public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections,\n                                              LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) {\n        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(),\n                new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null);\n    }\n\n    public static boolean isBlockStateLiquid(BlockState blockState) {\n        return blockState.liquid();\n    }\n\n    public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) {\n        return levelChunkSection.hasOnlyAir();\n    }\n\n    public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"block_entity@\" + blockEntity.getBlockPos(), LOGGER)) {\n            ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag);\n            blockEntity.loadWithComponents(valueInput);\n        }\n    }\n\n    public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set<ChunkPos> chunks) {\n        lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> {\n        }, completeCallback -> {\n        });\n    }\n\n    public static void rewriteSignLines(CompoundTag compoundTag) {\n        applySignTextLines(compoundTag, \"front_text\");\n        applySignTextLines(compoundTag, \"back_text\");\n        convertLegacySignTextLines(compoundTag);\n    }\n\n    public static DimensionType getDimensionTypeFromDimension(Dimension dimension) {\n        ResourceKey<LevelStem> resourceKey;\n        switch (dimension.getEnvironment()) {\n            case NETHER -> resourceKey = LevelStem.NETHER;\n            case THE_END -> resourceKey = LevelStem.END;\n            default -> resourceKey = LevelStem.OVERWORLD;\n        }\n        HolderLookup.RegistryLookup<LevelStem> registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM);\n        return registry.getOrThrow(resourceKey).value().type().value();\n    }\n\n    public static void createChunkSections(@Nullable ServerLevel serverLevel,\n                                           LevelHeightAccessor levelHeightAccessor,\n                                           LevelChunkSection[] chunkSections,\n                                           Dimension dimension) {\n        Holder<Biome> biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension));\n\n        for (int i = 0; i < chunkSections.length; ++i) {\n            PalettedContainer<Holder<Biome>> biomesContainer = createBiomesContainer(biome);\n            PalettedContainer<BlockState> statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n            chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer);\n        }\n    }\n\n    public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) {\n        CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel,\n                serverLevel.getChunkSource().getGenerator(), bukkitGenerator);\n\n        ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE);\n\n        // Unsafe: we do not provide chunks cache, even tho it is required.\n        // Should be fine in normal flow, as the only method that access the chunks cache\n        // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error:\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121\n        WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess);\n\n        customChunkGenerator.buildSurface(region,\n                serverLevel.structureManager().forWorldGenRegion(region),\n                serverLevel.getChunkSource().randomState(),\n                chunkAccess);\n    }\n\n    public static PalettedContainer<BlockState> createEmptyPlattedContainerStates() {\n        return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates();\n    }\n\n    public static PalettedContainer<BlockState> copyPalettedContainer(PalettedContainer<BlockState> original) {\n        return original.copy();\n    }\n\n    public static CompoundTag saveBlockEntity(BlockEntity blockEntity) {\n        return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess());\n    }\n\n    public static CompoundTag saveEntity(Entity entity) {\n        try (ProblemReporter.ScopedCollector scopedCollector =\n                     new ProblemReporter.ScopedCollector(() -> \"cached_entity@\" + entity.getUUID(), LOGGER)) {\n            TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess());\n            entity.save(valueOutput);\n            return valueOutput.buildResult();\n        }\n    }\n\n    public static Material getMaterialFromBlock(Block block) {\n        return CraftMagicNumbers.getMaterial(block);\n    }\n\n    public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) {\n        return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault());\n    }\n\n    public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) {\n        return new TickingBlockList() {\n            @Override\n            public int size() {\n                return levelChunkSection.moonrise$getTickingBlockList().size();\n            }\n\n            @Override\n            public int getRaw(int index) {\n                return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index);\n            }\n        };\n    }\n\n    public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {\n        serverLevel.addFreshEntity(entity, spawnReason);\n    }\n\n    public static PropertyMap getProfileProperties(GameProfile gameProfile) {\n        return gameProfile.properties();\n    }\n\n    public static String getPropertyValue(com.mojang.authlib.properties.Property property) {\n        return property.value();\n    }\n\n    public static EnderDragonFight getEndDragonFight(ServerLevel serverLevel) {\n        return serverLevel.getDragonFight();\n    }\n\n    public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) {\n        entity.absSnapTo(x, y, z, yaw, pitch);\n    }\n\n    public static int getMinSection(ServerLevel serverLevel) {\n        return serverLevel.getMinSectionY();\n    }\n\n    public static int getMinBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMinY();\n    }\n\n    public static int getMaxBuildHeight(ServerLevel serverLevel) {\n        return serverLevel.getMaxY();\n    }\n\n    public static void markUnsaved(LevelChunk levelChunk) {\n        levelChunk.markUnsaved();\n    }\n\n    public static PalettedContainer<Holder<Biome>> createBiomesContainer(Holder<Biome> biome) {\n        Registry<Biome> biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME);\n        Strategy<Holder<Biome>> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap());\n        return new PalettedContainerFactory(\n                null,\n                null,\n                null,\n                biomesStrategy,\n                biome,\n                null,\n                null\n        ).createForBiomes();\n    }\n\n    public static Optional<CompoundTag> loadPlayerData(ServerPlayer serverPlayer) {\n        try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) {\n            return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId())\n                    .map(playerData -> {\n                        ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData);\n                        serverPlayer.load(valueInput);\n                        return playerData;\n                    });\n        }\n    }\n\n    public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) {\n        return compoundTag.getLongOr(key, def);\n    }\n\n    private static void applySignTextLines(CompoundTag blockEntityCompound, String key) {\n        blockEntityCompound.getCompound(key).ifPresent(textCompound -> {\n            ListTag messages = textCompound.getListOrEmpty(\"messages\");\n            List<Component> textLines = new ArrayList<>();\n            for (net.minecraft.nbt.Tag lineTag : messages) {\n                try {\n                    textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()));\n                } catch (JsonParseException error) {\n                    textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]);\n                }\n            }\n\n            for (int i = 0; i < 4; i++) {\n                if (textLines.get(i) == null)\n                    textLines.set(i, Component.empty());\n            }\n\n            Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE);\n\n            SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(nbt -> blockEntityCompound.put(key, nbt));\n        });\n    }\n\n    private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) {\n        Component[] signLines = new Component[4];\n        Arrays.fill(signLines, Component.empty());\n        boolean hasAnySignLines = false;\n        // We try to convert old text sign lines\n        for (int i = 1; i <= 4; ++i) {\n            if (blockEntityCompound.contains(\"SSB.Text\" + i)) {\n                String signLine = blockEntityCompound.getString(\"SSB.Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromString(signLine)[0];\n                    hasAnySignLines = true;\n                }\n            } else {\n                String signLine = blockEntityCompound.getString(\"Text\" + i).orElse(null);\n                if (!Text.isBlank(signLine)) {\n                    signLines[i - 1] = CraftChatMessage.fromJSON(signLine);\n                    hasAnySignLines = true;\n                }\n            }\n        }\n\n        if (hasAnySignLines) {\n            SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false);\n            SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result()\n                    .ifPresent(frontTextNBT -> blockEntityCompound.put(\"front_text\", frontTextNBT));\n        }\n    }\n\n    public static BlockState getBlockState(org.bukkit.block.Block block) {\n        return ((CraftBlock) block).getBlockState();\n    }\n\n    public static boolean forEachProperty(BlockState blockState, BiConsumer<Property<?>, Comparable<?>> consumer) {\n        int[] count = new int[]{0};\n\n        blockState.getValues().forEach(value -> {\n            ++count[0];\n            consumer.accept(value.property(), value.value());\n        });\n\n        return count[0] > 0;\n    }\n\n    public static Identifier getBlockEntityTypeKey(BlockEntityType<?> type) {\n        return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type);\n    }\n\n    private NMSUtilsVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.vibration;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Holder;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.tags.TagKey;\nimport net.minecraft.world.entity.Entity;\nimport net.minecraft.world.entity.player.Player;\nimport net.minecraft.world.level.block.entity.SculkSensorBlockEntity;\nimport net.minecraft.world.level.gameevent.GameEvent;\nimport net.minecraft.world.level.gameevent.PositionSource;\nimport net.minecraft.world.level.gameevent.vibrations.VibrationSystem;\n\nimport javax.annotation.Nullable;\n\npublic class IslandVibrationUser implements VibrationSystem.User {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Island island;\n    private final VibrationSystem.User original;\n\n    public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) {\n        this.island = island;\n        this.original = sculkSensorBlockEntity.getVibrationUser();\n    }\n\n    @Override\n    public int getListenerRadius() {\n        return this.original.getListenerRadius();\n    }\n\n    @Override\n    public PositionSource getPositionSource() {\n        return this.original.getPositionSource();\n    }\n\n    @Override\n    public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, GameEvent.Context context) {\n        if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context))\n            return false;\n\n        if (context.sourceEntity() instanceof Player player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity());\n            return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR);\n        }\n\n        return true;\n    }\n\n    @Override\n    public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder<GameEvent> holder, @Nullable Entity entity, @Nullable Entity entity1, float v) {\n        this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v);\n    }\n\n    @Override\n    public TagKey<GameEvent> getListenableEvents() {\n        return this.original.getListenableEvents();\n    }\n\n    @Override\n    public boolean canTriggerAvoidVibration() {\n        return this.original.canTriggerAvoidVibration();\n    }\n\n    @Override\n    public boolean requiresAdjacentChunksToBeTicking() {\n        return this.original.requiresAdjacentChunksToBeTicking();\n    }\n\n    @Override\n    public int calculateTravelTimeInTicks(float distance) {\n        return this.original.calculateTravelTimeInTicks(distance);\n    }\n\n    @Override\n    public boolean isValidVibration(Holder<GameEvent> gameEvent, GameEvent.Context context) {\n        return this.original.isValidVibration(gameEvent, context);\n    }\n\n    @Override\n    public void onDataChanged() {\n        this.original.onDataChanged();\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.server.level.ServerLevel;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.ticks.LevelTicks;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\npublic class BlockLevelTicksTracker extends LevelTicks<Block> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ServerLevel serverLevel;\n\n    public BlockLevelTicksTracker(ServerLevel serverLevel) {\n        super(serverLevel::isPositionTickingWithEntitiesLoaded);\n        this.serverLevel = serverLevel;\n    }\n\n    @Override\n    public void tick(long gameTime, int maxAllowedTicks, BiConsumer<BlockPos, Block> ticker) {\n        super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> {\n            BlockState oldState = this.serverLevel.getBlockState(blockPos);\n            try {\n                // Only capture blocks related events\n                plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n                ticker.accept(blockPos, block);\n            } finally {\n                List<GameEvent<?>> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents();\n                // Remove BlockPhysicsEvent which we don't listen to\n                capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT);\n                // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method.\n                // This is to prevent blocks from being considered updated twice.\n                if (!capturedEvents.isEmpty())\n                    return;\n            }\n            BlockState newState = this.serverLevel.getBlockState(blockPos);\n            if (oldState.getBlock() != newState.getBlock()) {\n                // Block was changed, let's call an update\n                GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n                blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos);\n                blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null);\n                GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n                plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport net.minecraft.core.BlockPos;\nimport net.minecraft.core.Direction;\nimport net.minecraft.server.MinecraftServer;\nimport net.minecraft.world.level.Level;\nimport net.minecraft.world.level.block.Block;\nimport net.minecraft.world.level.block.state.BlockState;\nimport net.minecraft.world.level.redstone.CollectingNeighborUpdater;\nimport org.bukkit.craftbukkit.block.CraftBlock;\nimport org.bukkit.craftbukkit.block.CraftBlockStates;\n\npublic class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Level level;\n\n    public CollectingNeighborUpdaterTracker(Level level) {\n        super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates());\n        this.level = level;\n    }\n\n    @Override\n    public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) {\n        BlockState oldState = this.level.getBlockState(pos);\n        super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft);\n        BlockState newState = this.level.getBlockState(pos);\n        if (oldState.getBlock() != newState.getBlock()) {\n            // Block was changed, let's call an update\n            GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent();\n            blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos);\n            blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null);\n            GameEvent<GameEventArgs.BlockUpdateShapeEvent> gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent);\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.v26_1.world;\n\nimport net.minecraft.world.level.block.state.properties.BlockStateProperties;\n\nimport java.util.Map;\n\npublic class PropertiesMapperVersioned {\n\n    public static void initializeFields(Map<Object, String> fieldsToNames) {\n        fieldsToNames.put(BlockStateProperties.AGE_4, \"age4\");\n        fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, \"test-block-mode\");\n    }\n\n    private PropertiesMapperVersioned() {\n\n    }\n\n}\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n<img src=\"https://static.bg-software.com/imgs/superiorskyblock-logo.png\" />\n<h2 align=\"center\">The most optimized Skyblock core on the market.</h2>\n</p>\n<br>\n<p align=\"center\">\n<a href=\"https://bg-software.com/discord/\"><img src=\"https://img.shields.io/discord/293212540723396608?color=7289DA&label=Discord&logo=discord&logoColor=7289DA&link=https://bg-software.com/discord/\"></a>\n<a href=\"https://bg-software.com/patreon/\"><img src=\"https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white&link=https://bg-software.com/patreon/\"></a><br>\n<a href=\"\"><img src=\"https://img.shields.io/maintenance/yes/2025\"></a>\n<a href=\"https://www.codacy.com/gh/BG-Software-LLC/SuperiorSkyblock2/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=BG-Software-LLC/SuperiorSkyblock2&amp;utm_campaign=Badge_Grade\"><img src=\"https://app.codacy.com/project/badge/Grade/cf81db478cf74983abac6f3605dc53b4\"/></a>\n</p>\n\n## Compiling\n\nYou can compile the project using gradlew.<br>\nRun `gradlew build` in console to build the project.<br>\nYou can find already compiled jars on our [Jenkins](https://hub.bg-software.com/) hub!<br>\n\n## API\n\nThe plugin is packed with a rich API for interacting with islands, players and more. When hooking into the plugin, it's\nhighly recommended to only use the API and not the compiled plugin, as the API methods are not only commented, but also\nwill not get removed or changed unless they are marked as deprecated. This means that when using the API, you won't have\nto do any additional changes to your code between updates.\n\n### Maven\n\n```xml\n\n<repositories>\n    <repository>\n        <id>bg-repo</id>\n        <url>https://repo.bg-software.com/repository/api/</url>\n    </repository>\n</repositories>\n\n<dependencies>\n<dependency>\n    <groupId>com.bgsoftware</groupId>\n    <artifactId>SuperiorSkyblockAPI</artifactId>\n    <version>VERSION</version>\n    <scope>provided</scope>\n</dependency>\n</dependencies>\n```\n\n### Gradle\n\n```text\nrepositories {\n    maven { url 'https://repo.bg-software.com/repository/api/' }\n}\n\ndependencies {\n    compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:VERSION'\n}\n```\n\nMake sure you replace `VERSION` with the matching version.\n\n## Updates\n\nThis plugin is provided \"as is\", which means no updates or new features are guaranteed. We will do our best to keep\nupdating and pushing new updates, and you are more than welcome to contribute your time as well and make pull requests\nfor bug fixes.\n\n## License\n\nThis plugin is licensed under GNU GPL v3.0\n\nThis plugin uses HikariCP which you can find [here](https://github.com/brettwooldridge/HikariCP).\n"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n    id 'java'\n    id 'com.gradleup.shadow' version '9.4.1'\n    id 'maven-publish'\n}\n\ngroup 'SuperiorSkyblock'\nversion = \"2026.1\"\n\nproject.ext {\n    targetFolder = file(\"target/\")\n    buildVersion = System.getenv(\"BUILD_NUMBER\") == null || Boolean.parseBoolean(System.getenv(\"STABLE_BUILD\")) ?\n            version : version + \"-b\" + System.getenv(\"BUILD_NUMBER\")\n}\n\nallprojects {\n    apply plugin: 'java'\n    apply plugin: 'com.gradleup.shadow'\n\n    java {\n        toolchain {\n            languageVersion.set(JavaLanguageVersion.of(8))\n        }\n    }\n\n    repositories {\n        maven { url 'https://repo.bg-software.com/repository/nms/' }\n        maven { url 'https://repo.bg-software.com/repository/api/' }\n        maven { url 'https://repo.bg-software.com/repository/common/' }\n        maven { url 'https://repo.bg-software.com/repository/dependencies/' }\n    }\n\n    dependencies {\n        compileOnly 'com.bgsoftware.common.reflection:ReflectionUtils:b8'\n        compileOnly 'com.bgsoftware.common.annotations:Annotations:b2'\n    }\n\n    tasks.register('checkDebug') {\n        Set<File> filesWithDebug = fileTree('src/main/java').filter { file ->\n            file.text.contains('Bukkit.broadcastMessage')\n        }.getFiles()\n\n        if (!filesWithDebug.isEmpty())\n            throw new GradleException(\"Found debug messages: \" + filesWithDebug)\n    }\n\n    shadowJar {\n        relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common'\n    }\n\n    build {\n        dependsOn checkDebug\n        dependsOn shadowJar\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation project(\":API\")\n\n    implementation 'com.bgsoftware.common.config:CommentedConfiguration:b1'\n    implementation 'com.bgsoftware.common.updater:Updater:b1'\n    implementation 'com.bgsoftware.common.reflection:ReflectionUtils:b8'\n    implementation 'com.bgsoftware.common.executors:Executors:b3'\n    implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar'\n    implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2'\n    implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b20'\n    implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2'\n\n    implementation 'org.bstats:bstats-bukkit:3.0.0'\n\n    // Spigot jars\n    compileOnly \"org.spigotmc:v1_8_R3-Taco:latest\"\n    compileOnly 'org.spigotmc:v1_16_R3-Tuinity:latest'\n}\n\nprocessResources {\n    outputs.upToDateWhen { false }\n    eachFile { details ->\n        if (details.name.contentEquals('plugin.yml')) {\n            filter { String line ->\n                line.replace('${project.version}', rootProject.buildVersion)\n            }\n        }\n    }\n}\n\nsubprojects.each { evaluationDependsOn(it.path) }\n\nshadowJar {\n    relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats'\n\n    archiveClassifier.set('')\n\n    from sourceSets.main.output\n\n    from(project.configurations.runtimeClasspath.filter { it.name.endsWith('.jar') }.collect { zipTree(it) }) {\n        exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'\n    }\n\n    duplicatesStrategy = DuplicatesStrategy.EXCLUDE\n\n    subprojects.each { sub ->\n        if (sub.path.startsWith(':NMS:v1')) {\n            try {\n                def reobfTask = sub.tasks.named('reobfJar')\n                dependsOn(reobfTask)\n                from(reobfTask.map { it.outputJar }) {\n                    exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'\n                    rename { sub.name }\n                    into(\"nms\")\n                }\n                return;\n            } catch (Exception ignored) {\n            }\n        }\n\n        if (sub.path.startsWith(':NMS:v')) {\n            def shadowJarTask = sub.tasks.named(\"shadowJar\")\n            dependsOn(shadowJarTask)\n\n            from(shadowJarTask.map { it.archiveFile }) {\n                exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'\n                rename { sub.name }\n                into(\"nms\")\n            }\n        } else {\n            from sub.sourceSets.main.output\n        }\n    }\n\n    def missionsProject = project(':Missions');\n\n    missionsProject.subprojects.forEach { sub ->\n        def shadowJarTask = sub.tasks.named(\"shadowJar\")\n        dependsOn(shadowJarTask)\n\n        from(shadowJarTask.map { it.archiveFile }) {\n            exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'\n            rename { sub.name }\n            into(\"modules/missions\")\n        }\n    }\n\n    dependencies {\n        // This includes the API and all sub-modules in the final JAR\n        include project(':API')\n\n        // Use a loop to include all NMS and Hook subprojects automatically\n        subprojects.findAll { it.path.startsWith(':NMS:') || it.path.startsWith(':Hooks:') }.each { sub ->\n            include project(sub.path)\n        }\n    }\n}\n\ntasks.register('cleanTarget', Delete) {\n    delete rootProject.targetFolder\n}\n\ntasks.register('collectArtifacts', Copy) {\n    group = 'build'\n\n    dependsOn('cleanTarget')\n    dependsOn(tasks.named('shadowJar'))\n    dependsOn(project(':API').tasks.named('shadowJar'))\n\n    from(tasks.named('shadowJar').map { it.archiveFile }) {\n        rename { rootProject.name + \"-\" + rootProject.buildVersion + \".jar\" }\n    }\n\n    from(project(':API').tasks.named('shadowJar').map { it.archiveFile }) {\n        rename { rootProject.name + \"-API.jar\" }\n    }\n\n    into(rootProject.targetFolder)\n}\n\ntasks.named('build') {\n    dependsOn(tasks.named('shadowJar'))\n}\n\ntasks.named('shadowJar') {\n    finalizedBy('collectArtifacts')\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-9.4.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "pluginManagement {\n    repositories {\n        gradlePluginPortal()\n        maven { url \"https://repo.papermc.io/repository/maven-public/\" }\n    }\n}\n\nrootProject.name = 'SuperiorSkyblock2'\n\ninclude 'API'\ninclude 'Hooks'\ninclude 'Hooks:AdvancedSlimePaper'\ninclude 'Hooks:AdvancedSpawners'\ninclude 'Hooks:CandcSilkSpawners'\ninclude 'Hooks:ChangeSkin'\ninclude 'Hooks:CMI'\ninclude 'Hooks:CoreProtect'\ninclude 'Hooks:CraftEngine'\ninclude 'Hooks:EpicSpawners6'\ninclude 'Hooks:EpicSpawners7'\ninclude 'Hooks:EpicSpawners8'\ninclude 'Hooks:EpicSpawners9'\ninclude 'Hooks:Essentials'\ninclude 'Hooks:FastAsyncWorldEdit'\ninclude 'Hooks:ItemsAdder'\ninclude 'Hooks:JetsMinions'\ninclude 'Hooks:LuckPerms'\ninclude 'Hooks:MergedSpawner'\ninclude 'Hooks:MiniMessage'\ninclude 'Hooks:MVdWPlaceholderAPI'\ninclude 'Hooks:Nexo'\ninclude 'Hooks:OpenJdkNashornEngine'\ninclude 'Hooks:Oraxen'\ninclude 'Hooks:Plan'\ninclude 'Hooks:PaperMC'\ninclude 'Hooks:PlaceholderAPI'\ninclude 'Hooks:ProtocolLib'\ninclude 'Hooks:PvpingSpawners'\ninclude 'Hooks:RoseStacker'\ninclude 'Hooks:SkinsRestorer'\ninclude 'Hooks:SkinsRestorer14'\ninclude 'Hooks:SkinsRestorer15'\ninclude 'Hooks:Slimefun'\ninclude 'Hooks:Slimefun:ProtectionModule_RC13'\ninclude 'Hooks:Slimefun:ProtectionModule_Dev999'\ninclude 'Hooks:SlimeWorldManager'\ninclude 'Hooks:SmoothTimber'\ninclude 'Hooks:SuperVanish'\ninclude 'Hooks:TimbruSilkSpawners'\ninclude 'Hooks:UltimateStacker'\ninclude 'Hooks:UltimateStacker3'\ninclude 'Hooks:UltimateStacker4'\ninclude 'Hooks:VanishNoPacket'\ninclude 'Hooks:Vault'\ninclude 'Hooks:WildStacker'\ninclude 'Missions'\ninclude 'Missions:BlocksMissions'\ninclude 'Missions:BrewingMissions'\ninclude 'Missions:CraftingMissions'\ninclude 'Missions:EnchantingMissions'\ninclude 'Missions:FarmingMissions'\ninclude 'Missions:FishingMissions'\ninclude 'Missions:IslandMissions'\ninclude 'Missions:ItemsMissions'\ninclude 'Missions:KillsMissions'\ninclude 'Missions:StatisticsMissions'\ninclude 'NMS'\ninclude 'NMS:Spigot'\ninclude 'NMS:Spigot-1_20_3'\ninclude 'NMS:Paper'\ninclude 'NMS:Paper-1_20_3'\ninclude 'NMS:v1_8_R3'\ninclude 'NMS:v1_12_R1'\ninclude 'NMS:v1_16_R3'\ninclude 'NMS:v1_17'\ninclude 'NMS:v1_18'\ninclude 'NMS:v1_19'\ninclude 'NMS:v1_20_3'\ninclude 'NMS:v1_20_4'\ninclude 'NMS:v1_21'\ninclude 'NMS:v1_21_3'\ninclude 'NMS:v1_21_4'\ninclude 'NMS:v1_21_5'\ninclude 'NMS:v1_21_7'\ninclude 'NMS:v1_21_9'\ninclude 'NMS:v1_21_10'\ninclude 'NMS:v26_1'"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java",
    "content": "package com.bgsoftware.superiorskyblock;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.dependencies.DependenciesManager;\nimport com.bgsoftware.common.nmsloader.INMSLoader;\nimport com.bgsoftware.common.nmsloader.NMSHandlersFactory;\nimport com.bgsoftware.common.nmsloader.NMSLoadException;\nimport com.bgsoftware.common.nmsloader.config.NMSConfiguration;\nimport com.bgsoftware.common.updater.Updater;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime;\nimport com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandsManagerImpl;\nimport com.bgsoftware.superiorskyblock.commands.admin.AdminCommandsMap;\nimport com.bgsoftware.superiorskyblock.commands.player.PlayerCommandsMap;\nimport com.bgsoftware.superiorskyblock.config.SettingsManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PluginLoadingStage;\nimport com.bgsoftware.superiorskyblock.core.PluginReloadReason;\nimport com.bgsoftware.superiorskyblock.core.database.DataManager;\nimport com.bgsoftware.superiorskyblock.core.engine.EnginesFactory;\nimport com.bgsoftware.superiorskyblock.core.engine.NashornEngineDownloader;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls;\nimport com.bgsoftware.superiorskyblock.core.key.KeysManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.MenusManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlocksManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.container.DefaultStackedBlocksContainer;\nimport com.bgsoftware.superiorskyblock.core.stats.StatsClient;\nimport com.bgsoftware.superiorskyblock.core.task.CalcTask;\nimport com.bgsoftware.superiorskyblock.core.task.ShutdownTask;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValuesManagerImpl;\nimport com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer;\nimport com.bgsoftware.superiorskyblock.external.ProvidersManagerImpl;\nimport com.bgsoftware.superiorskyblock.island.GridManagerImpl;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys;\nimport com.bgsoftware.superiorskyblock.island.container.DefaultIslandsContainer;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.preview.DefaultIslandPreviews;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.purge.DefaultIslandsPurger;\nimport com.bgsoftware.superiorskyblock.island.role.RolesManagerImpl;\nimport com.bgsoftware.superiorskyblock.island.role.container.DefaultRolesContainer;\nimport com.bgsoftware.superiorskyblock.island.top.SortingComparators;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.bgsoftware.superiorskyblock.island.upgrade.UpgradesManagerImpl;\nimport com.bgsoftware.superiorskyblock.island.upgrade.container.DefaultUpgradesContainer;\nimport com.bgsoftware.superiorskyblock.island.upgrade.loaders.PlaceholdersUpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.island.upgrade.loaders.VaultUpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.listener.BukkitListeners;\nimport com.bgsoftware.superiorskyblock.mission.MissionsManagerImpl;\nimport com.bgsoftware.superiorskyblock.mission.container.DefaultMissionsContainer;\nimport com.bgsoftware.superiorskyblock.module.ModulesManagerImpl;\nimport com.bgsoftware.superiorskyblock.module.container.DefaultModulesContainer;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.nms.NMSChunks;\nimport com.bgsoftware.superiorskyblock.nms.NMSDragonFight;\nimport com.bgsoftware.superiorskyblock.nms.NMSDragonFightChooser;\nimport com.bgsoftware.superiorskyblock.nms.NMSEntities;\nimport com.bgsoftware.superiorskyblock.nms.NMSHolograms;\nimport com.bgsoftware.superiorskyblock.nms.NMSPlayers;\nimport com.bgsoftware.superiorskyblock.nms.NMSTags;\nimport com.bgsoftware.superiorskyblock.nms.NMSWorld;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.player.PlayersManagerImpl;\nimport com.bgsoftware.superiorskyblock.player.container.DefaultPlayersContainer;\nimport com.bgsoftware.superiorskyblock.player.inventory.ClearActions;\nimport com.bgsoftware.superiorskyblock.player.respawn.RespawnActions;\nimport com.bgsoftware.superiorskyblock.service.ServicesHandler;\nimport com.bgsoftware.superiorskyblock.world.WorldGenerator;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport com.bgsoftware.superiorskyblock.world.schematic.SchematicsManagerImpl;\nimport com.bgsoftware.superiorskyblock.world.schematic.container.DefaultSchematicsContainer;\nimport org.bstats.bukkit.Metrics;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.bukkit.plugin.java.JavaPlugin;\n\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblock {\n\n    private static SuperiorSkyblockPlugin plugin;\n\n    /* Managers */\n    private final DataManager dataHandler = new DataManager(this);\n    private final FactoriesManagerImpl factoriesHandler = new FactoriesManagerImpl();\n    private final GridManagerImpl gridHandler = new GridManagerImpl(this, new DefaultIslandsPurger(), new DefaultIslandPreviews());\n    private final StackedBlocksManagerImpl stackedBlocksHandler = new StackedBlocksManagerImpl(this, new DefaultStackedBlocksContainer());\n    private final BlockValuesManagerImpl blockValuesHandler = new BlockValuesManagerImpl(this, new BlockValuesContainer(), new BlockValuesContainer());\n    private final SchematicsManagerImpl schematicsHandler = new SchematicsManagerImpl(this, new DefaultSchematicsContainer());\n    private final PlayersManagerImpl playersHandler = new PlayersManagerImpl(this);\n    private final RolesManagerImpl rolesHandler = new RolesManagerImpl(this, new DefaultRolesContainer());\n    private final MissionsManagerImpl missionsHandler = new MissionsManagerImpl(this, new DefaultMissionsContainer());\n    private final MenusManagerImpl menusHandler = new MenusManagerImpl(this);\n    private final KeysManagerImpl keysHandler = new KeysManagerImpl(this);\n    private final ProvidersManagerImpl providersHandler = new ProvidersManagerImpl(this);\n    private final UpgradesManagerImpl upgradesHandler = new UpgradesManagerImpl(this, new DefaultUpgradesContainer());\n    private final CommandsManagerImpl commandsHandler = new CommandsManagerImpl(this, new PlayerCommandsMap(this), new AdminCommandsMap(this));\n    private final ModulesManagerImpl modulesHandler = new ModulesManagerImpl(this, new DefaultModulesContainer(this));\n    private final ServicesHandler servicesHandler = new ServicesHandler(this);\n    private final SettingsManagerImpl settingsHandler = new SettingsManagerImpl(this);\n\n    /* Global handlers */\n    private final Updater updater = new Updater(this, \"superiorskyblock2\");\n    private final BukkitListeners bukkitListeners = new BukkitListeners(this);\n    private final PluginEventsDispatcher pluginEventsDispatcher = new PluginEventsDispatcher(this);\n    private final GameEventsDispatcher gameEventsDispatcher = new GameEventsDispatcher(this);\n    private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine();\n    @Nullable\n    private IEventsDispatcher eventsDispatcher = null;\n\n    /* NMS */\n    @Nullable\n    private NMSAlgorithms nmsAlgorithms;\n    private NMSChunks nmsChunks;\n    private NMSDragonFight nmsDragonFight;\n    private NMSEntities nmsEntities;\n    private NMSHolograms nmsHolograms;\n    private NMSPlayers nmsPlayers;\n    private NMSTags nmsTags;\n    private NMSWorld nmsWorld;\n\n    private PluginLoadingStage loadingStage = PluginLoadingStage.START;\n\n    public static SuperiorSkyblockPlugin getPlugin() {\n        return plugin;\n    }\n\n    @Override\n    public void onLoad() {\n        plugin = this;\n        pluginEventsDispatcher.registerDefaultListeners();\n\n        DependenciesManager.inject(this);\n\n        bukkitListeners.registerListenerFailureFilter();\n\n        try {\n            SuperiorSkyblockAPI.setPluginInstance(this);\n        } catch (UnsupportedOperationException error) {\n            Log.error(\"The API instance was already initialized. This can be caused by a reload or another plugin initializing it.\");\n            return;\n        }\n\n        loadingStage = PluginLoadingStage.API_INITIALIZED;\n\n        String serverVersion = Bukkit.getVersion();\n        if (serverVersion.toLowerCase(Locale.ENGLISH).contains(\"arclight\")) {\n            Log.error(\"The plugin does not support this server software: \" + serverVersion);\n            return;\n        }\n\n        loadingStage = PluginLoadingStage.SUPPORTED_SERVER_SOFTWARE;\n\n        if (!loadNMSAdapter()) {\n            return;\n        }\n\n        loadingStage = PluginLoadingStage.NMS_INITIALIZED;\n\n        Runtime.getRuntime().addShutdownHook(new ShutdownTask(this));\n\n        IslandPrivileges.registerPrivileges();\n        SortingTypes.registerSortingTypes(this);\n        IslandFlags.registerFlags();\n        ClearActions.registerActions();\n        RespawnActions.registerActions();\n        IslandCacheKeys.registerCacheKeys();\n\n        try {\n            SortingComparators.initializeTopIslandMembersSorting();\n        } catch (IllegalArgumentException error) {\n            Log.error(\"The TopIslandMembersSorting was already initialized. This can be caused by a reload or another plugin initializing it.\");\n            return;\n        }\n\n        this.servicesHandler.loadDefaultServices(this);\n\n        new Metrics(this, 4119);\n        StatsClient client = StatsClient.getInstance();\n        client.start();\n\n        loadingStage = PluginLoadingStage.LOADED;\n    }\n\n    @Override\n    public void onEnable() {\n        try {\n            if (loadingStage != PluginLoadingStage.LOADED) {\n                ManagerLoadException.handle(new ManagerLoadException(\"Failed to load \" + getDescription().getName() + \".\\n\" +\n                        \"Failed on \" + loadingStage.next() + \"\\n\\n\" +\n                        \"Shutting down the server...\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN));\n                return;\n            }\n\n            loadingStage = PluginLoadingStage.START_ENABLE;\n\n            BukkitExecutor.init(this);\n\n            loadUpgradeCostLoaders();\n\n            try {\n                settingsHandler.loadData();\n            } catch (ManagerLoadException ex) {\n                if (!ManagerLoadException.handle(ex)) {\n                    return;\n                }\n            }\n\n            loadingStage = PluginLoadingStage.SETTINGS_INITIALIZED;\n\n            modulesHandler.loadData();\n\n            loadingStage = PluginLoadingStage.MODULES_INITIALIZED;\n\n            commandsHandler.loadData();\n\n            loadingStage = PluginLoadingStage.COMMANDS_INITIALIZED;\n\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, false);\n\n            PluginEvent<PluginEventArgs.PluginInitialize> event = PluginEventsFactory.callPluginInitializeEvent();\n\n            this.playersHandler.setPlayersContainer(Optional.ofNullable(event.getArgs().playersContainer).orElse(new DefaultPlayersContainer()));\n            this.gridHandler.setIslandsContainer(Optional.ofNullable(event.getArgs().islandsContainer).orElse(new DefaultIslandsContainer(this)));\n\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, false);\n\n            try {\n                providersHandler.getWorldsProvider().prepareWorlds();\n            } catch (RuntimeException ex) {\n                ManagerLoadException handlerError = new ManagerLoadException(ex, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n                Log.error(handlerError, \"An error occurred while preparing worlds:\");\n                Bukkit.shutdown();\n                return;\n            }\n\n            loadingStage = PluginLoadingStage.WORLDS_PREPARED;\n\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.NORMAL, false);\n\n            try {\n                reloadPlugin(PluginReloadReason.STARTUP);\n            } catch (ManagerLoadException error) {\n                Log.error(error, \"An unexpected error occurred while starting up the plugin:\");\n                ManagerLoadException.handle(error);\n                return;\n            }\n\n            loadingStage = PluginLoadingStage.MANAGERS_INITIALIZED;\n\n            ChunksProvider.start();\n\n            loadingStage = PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED;\n\n            // Check for updates asynchronously\n            BukkitExecutor.async(() -> {\n                if (updater.isOutdated()) {\n                    Log.info(\"\");\n                    Log.info(\"A new version is available (v\", updater.getLatestVersion(), \")!\");\n                    Log.info(\"Version's description: \\\"\", updater.getVersionDescription(), \"\\\"\");\n                    Log.info(\"\");\n                }\n            });\n\n            // Calculate the maximum amount of islands that fit into the world.\n            long maxIslands = calculateMaxPossibleIslands();\n            if (maxIslands < 1000) {\n                Log.warn(\"It seems like you configured your max-world-size in server.properties to be a small number (\", nmsAlgorithms.getMaxWorldSize(), \").\");\n                Log.warn(\"This can lead to weird behaviors when new islands are generated beyond this limit.\");\n                Log.warn(\"Increase the value to for better experience (Default: 29999984)\");\n            }\n\n            BukkitExecutor.sync(() -> {\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    for (Player player : Bukkit.getOnlinePlayers()) {\n                        SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player);\n                        superiorPlayer.updateLastTimeStatus();\n\n                        Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle()));\n                        Island playerIsland = superiorPlayer.getIsland();\n\n                        if (superiorPlayer.hasIslandFlyEnabled()) {\n                            if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) {\n                                player.setAllowFlight(true);\n                                player.setFlying(true);\n                            } else {\n                                superiorPlayer.toggleIslandFly();\n                            }\n                        }\n\n                        if (playerIsland != null)\n                            playerIsland.setCurrentlyActive(true);\n\n                        if (island != null)\n                            island.setPlayerInside(superiorPlayer, true);\n                    }\n                }\n            }, 1L);\n\n            PluginEventsFactory.callPluginInitializedEvent();\n\n            loadingStage = PluginLoadingStage.ENABLED;\n\n            PluginEventsFactory.callSettingsUpdateEvent();\n        } catch (Throwable error) {\n            Log.error(error, \"An unexpected error occurred while enabling the plugin:\");\n            Bukkit.shutdown();\n        }\n    }\n\n    @Override\n    public void onDisable() {\n        try {\n            if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE))\n                BukkitExecutor.prepareShutdown();\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED))\n                ChunksProvider.stop();\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) {\n                dataHandler.saveDatabase(false);\n                gridHandler.disablePlugin();\n\n                for (Island island : gridHandler.getIslandsToPurge())\n                    island.disbandIsland();\n\n                playersHandler.savePlayers();\n                gridHandler.saveIslands();\n            }\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.MODULES_INITIALIZED)) {\n                modulesHandler.getModules().forEach(modulesHandler::unregisterModule);\n            }\n\n            // Shutdown task is running from another thread, causing closing of inventories to cause errors.\n            // This check should prevent it.\n            if (Bukkit.isPrimaryThread()) {\n                Bukkit.getOnlinePlayers().forEach(player -> {\n                    SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player);\n                    player.closeInventory();\n                    superiorPlayer.updateWorldBorder(null);\n                    if (superiorPlayer.hasIslandFlyEnabled()) {\n                        player.setAllowFlight(false);\n                        player.setFlying(false);\n                    }\n                });\n            }\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while disabling the plugin:\");\n        } finally {\n            Log.info(\"Shutting down stats client...\");\n            StatsClient.getIfExists().ifPresent(StatsClient::shutdown);\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) {\n                Log.info(\"Shutting down calculation task...\");\n                CalcTask.cancelTask();\n            }\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.NMS_INITIALIZED))\n                nmsChunks.shutdown();\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) {\n                Log.info(\"Shutting down executor\");\n                BukkitExecutor.close(plugin);\n            }\n\n            if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) {\n                Log.info(\"Closing database. This may hang the server. Do not shut it down, or data may get lost.\");\n                dataHandler.closeConnection();\n            }\n        }\n    }\n\n    @Override\n    public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {\n        return WorldGenerator.getWorldGenerator(settingsHandler.getWorlds().getDefaultWorldDimension());\n    }\n\n    public Updater getUpdater() {\n        return updater;\n    }\n\n    public ClassLoader getPluginClassLoader() {\n        return super.getClassLoader();\n    }\n\n    private boolean loadNMSAdapter() {\n        try {\n            INMSLoader nmsLoader = NMSHandlersFactory.createNMSLoader(this, NMSConfiguration.forPlugin(this));\n\n            this.nmsAlgorithms = nmsLoader.loadNMSHandler(NMSAlgorithms.class);\n            this.nmsChunks = nmsLoader.loadNMSHandler(NMSChunks.class);\n            this.nmsEntities = nmsLoader.loadNMSHandler(NMSEntities.class);\n            this.nmsHolograms = nmsLoader.loadNMSHandler(NMSHolograms.class);\n            this.nmsPlayers = nmsLoader.loadNMSHandler(NMSPlayers.class);\n            this.nmsTags = nmsLoader.loadNMSHandler(NMSTags.class);\n            this.nmsWorld = nmsLoader.loadNMSHandler(NMSWorld.class);\n            this.nmsDragonFight = new NMSDragonFightChooser(plugin, () -> nmsLoader.loadNMSHandler(NMSDragonFight.class));\n\n            return true;\n        } catch (NMSLoadException error) {\n            new ManagerLoadException(error, \"The plugin doesn't support your minecraft version.\\n\" + \"Please try a different version.\",\n                    ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN).printStackTrace();\n\n            return false;\n        }\n    }\n\n    private boolean checkScriptEngine() {\n        return testScriptEngine() || (NashornEngineDownloader.downloadEngine(this) && testScriptEngine());\n    }\n\n    private boolean testScriptEngine() {\n        try {\n            scriptEngine.eval(\"1+1\");\n            return true;\n        } catch (Exception ex) {\n            return false;\n        }\n    }\n\n    public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadException {\n        if (reloadReason == PluginReloadReason.COMMAND) {\n            bukkitListeners.unregisterListeners();\n        }\n\n        providersHandler.loadData();\n\n        ItemSkulls.readTextures(this);\n\n        if (reloadReason == PluginReloadReason.COMMAND) {\n            // The reload was requested by a command. We want to reload the commands, settings and call the\n            // module lifecycles that are not called regularly. If the reload was due to a startup, then\n            // all of that is called already in the onEnable callback of the plugin.\n            settingsHandler.loadData();\n\n            commandsHandler.loadData();\n\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, true);\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, true);\n            modulesHandler.runModuleLifecycle(ModuleLoadTime.NORMAL, true);\n        }\n\n        if (!checkScriptEngine()) {\n            throw new ManagerLoadException(\"It seems like the script engine of the plugin is corrupted.\\n\" + \"This may occur by one of the following reasons:\\n\" + \"1. You have a module/plugin that sets a custom script that doesn't work well.\\n\" + \"2. You're using Java 16 without installing an external module engine.\\n\" + \"If that's the case, check out the following link:\\n\" + \"https://github.com/BG-Software-LLC/SuperiorSkyblock2-NashornEngine\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        blockValuesHandler.loadData();\n        upgradesHandler.loadData();\n        rolesHandler.loadData();\n\n        Message.reload();\n\n        if (reloadReason == PluginReloadReason.STARTUP) {\n            playersHandler.loadData();\n            gridHandler.loadData();\n            schematicsHandler.loadData();\n        } else {\n            BukkitExecutor.sync(gridHandler::updateSpawn, 1L);\n            gridHandler.syncUpgrades();\n            schematicsHandler.loadSchematics();\n        }\n\n        menusHandler.loadData();\n        missionsHandler.loadData();\n\n        if (reloadReason == PluginReloadReason.STARTUP) {\n            dataHandler.loadData();\n            stackedBlocksHandler.loadData();\n        }\n\n        BukkitExecutor.sync(schematicsHandler::cacheSchematics);\n\n        modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_MODULE_DATA_LOAD, reloadReason == PluginReloadReason.COMMAND);\n\n        BukkitExecutor.sync(() -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                for (Player player : Bukkit.getOnlinePlayers()) {\n                    SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player);\n                    Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle()));\n                    superiorPlayer.updateWorldBorder(island);\n                    if (island != null) island.applyEffects(superiorPlayer);\n                }\n            }\n        });\n\n        CalcTask.startTask();\n\n        modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_HANDLERS_LOADING, reloadReason == PluginReloadReason.COMMAND);\n\n        if (reloadReason == PluginReloadReason.STARTUP) {\n            modulesHandler.loadModulesData(this);\n        }\n\n        try {\n            bukkitListeners.registerListeners();\n        } catch (RuntimeException ex) {\n            throw new ManagerLoadException(\"Cannot load plugin due to a missing event: \" + ex.getMessage() + \" - contact @Ome_R!\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n    }\n\n    @Override\n    public GridManagerImpl getGrid() {\n        return gridHandler;\n    }\n\n    @Override\n    public StackedBlocksManagerImpl getStackedBlocks() {\n        return stackedBlocksHandler;\n    }\n\n    @Override\n    public BlockValuesManagerImpl getBlockValues() {\n        return blockValuesHandler;\n    }\n\n    @Override\n    public SchematicsManagerImpl getSchematics() {\n        return schematicsHandler;\n    }\n\n    @Override\n    public PlayersManagerImpl getPlayers() {\n        return playersHandler;\n    }\n\n    @Override\n    public RolesManagerImpl getRoles() {\n        return rolesHandler;\n    }\n\n    @Override\n    public MissionsManagerImpl getMissions() {\n        return missionsHandler;\n    }\n\n    @Override\n    public MenusManagerImpl getMenus() {\n        return menusHandler;\n    }\n\n    @Override\n    public KeysManagerImpl getKeys() {\n        return keysHandler;\n    }\n\n    @Override\n    public ProvidersManagerImpl getProviders() {\n        return providersHandler;\n    }\n\n    @Override\n    public UpgradesManagerImpl getUpgrades() {\n        return upgradesHandler;\n    }\n\n    @Override\n    public CommandsManagerImpl getCommands() {\n        return commandsHandler;\n    }\n\n    @Override\n    public SettingsManagerImpl getSettings() {\n        return settingsHandler;\n    }\n\n    @Override\n    public FactoriesManagerImpl getFactory() {\n        return factoriesHandler;\n    }\n\n    @Override\n    public ModulesManagerImpl getModules() {\n        return modulesHandler;\n    }\n\n    @Override\n    public IScriptEngine getScriptEngine() {\n        return scriptEngine;\n    }\n\n    @Override\n    public void setScriptEngine(@Nullable IScriptEngine scriptEngine) {\n        this.scriptEngine = scriptEngine == null ? EnginesFactory.createDefaultEngine() : scriptEngine;\n    }\n\n    @Nullable\n    @Override\n    public IEventsDispatcher getEventsDispatcher() {\n        return this.eventsDispatcher;\n    }\n\n    @Override\n    public void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher) {\n        this.eventsDispatcher = eventsDispatcher;\n    }\n\n    public PluginEventsDispatcher getPluginEventsDispatcher() {\n        return pluginEventsDispatcher;\n    }\n\n    public GameEventsDispatcher getGameEventsDispatcher() {\n        return gameEventsDispatcher;\n    }\n\n    public ServicesHandler getServices() {\n        return servicesHandler;\n    }\n\n    public NMSAlgorithms getNMSAlgorithms() {\n        return nmsAlgorithms;\n    }\n\n    public NMSChunks getNMSChunks() {\n        return nmsChunks;\n    }\n\n    public NMSDragonFight getNMSDragonFight() {\n        return nmsDragonFight;\n    }\n\n    public NMSEntities getNMSEntities() {\n        return nmsEntities;\n    }\n\n    public NMSHolograms getNMSHolograms() {\n        return nmsHolograms;\n    }\n\n    public NMSPlayers getNMSPlayers() {\n        return nmsPlayers;\n    }\n\n    public NMSTags getNMSTags() {\n        return nmsTags;\n    }\n\n    public NMSWorld getNMSWorld() {\n        return nmsWorld;\n    }\n\n    public String getFileName() {\n        return getFile().getName();\n    }\n\n    private void loadUpgradeCostLoaders() {\n        upgradesHandler.registerUpgradeCostLoader(\"money\", new VaultUpgradeCostLoader());\n        upgradesHandler.registerUpgradeCostLoader(\"placeholders\", new PlaceholdersUpgradeCostLoader());\n    }\n\n    private long calculateMaxPossibleIslands() {\n        int islandDistance = settingsHandler.getMaxIslandSize() * 3;\n        long worldDistance = nmsAlgorithms.getMaxWorldSize() * 2L;\n        long islandsPerSide = worldDistance / islandDistance;\n        return islandsPerSide * islandsPerSide;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.nms.NMSAlgorithms;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport org.bukkit.Bukkit;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.function.BiPredicate;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.IntStream;\nimport java.util.stream.Stream;\n\npublic class CommandTabCompletes {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private CommandTabCompletes() {\n\n    }\n\n    public static List<String> getPlayerIslandsExceptSender(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument, boolean hideVanish) {\n        return getPlayerIslandsExceptSender(plugin, sender, argument, hideVanish, (onlinePlayer, onlineIsland) -> true);\n    }\n\n    public static List<String> getPlayerIslandsExceptSender(SuperiorSkyblockPlugin plugin, CommandSender sender,\n                                                            String argument, boolean hideVanish,\n                                                            BiPredicate<SuperiorPlayer, Island> islandPredicate) {\n        SuperiorPlayer superiorPlayer = sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null;\n        Island island = superiorPlayer == null ? null : superiorPlayer.getIsland();\n        return getOnlinePlayersAndIslands(plugin, argument, hideVanish, (onlinePlayer, onlineIsland) ->\n                onlineIsland != null && (superiorPlayer == null || island == null || !island.equals(onlineIsland)) &&\n                        islandPredicate.test(onlinePlayer, onlineIsland));\n    }\n\n    public static List<String> getIslandMembersWithLowerRole(Island island, String argument, PlayerRole maxRole) {\n        return getIslandMembers(island, argument, islandMember -> islandMember.getPlayerRole().isLessThan(maxRole));\n    }\n\n    public static List<String> getIslandMembers(Island island, String argument, Predicate<SuperiorPlayer> predicate) {\n        return getPlayers(island.getIslandMembers(false), argument, predicate);\n    }\n\n    public static List<String> getIslandMembers(Island island, String argument) {\n        return getPlayers(island.getIslandMembers(false), argument);\n    }\n\n    public static List<String> getOnlinePlayersWithIsland(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanished,\n                                                          Predicate<SuperiorPlayer> predicate) {\n        return getOnlinePlayers(plugin, argument, hideVanished, (onlinePlayer) ->\n                onlinePlayer != null && onlinePlayer.hasIsland() && predicate.test(onlinePlayer));\n    }\n\n    public static List<String> getOnlinePlayers(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<SuperiorPlayer>()\n                .filter(onlinePlayer -> (!hideVanish || onlinePlayer.isShownAsOnline()) &&\n                        onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(getOnlineSuperiorPlayers(plugin), SuperiorPlayer::getName);\n    }\n\n    public static List<String> getOnlinePlayers(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish, Predicate<SuperiorPlayer> predicate) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<SuperiorPlayer>()\n                .filter(onlinePlayer -> (!hideVanish || onlinePlayer.isShownAsOnline()) &&\n                        predicate.test(onlinePlayer) && onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(getOnlineSuperiorPlayers(plugin), SuperiorPlayer::getName);\n    }\n\n    public static List<String> getOnlinePlayersAndIslands(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish,\n                                                          @Nullable BiPredicate<SuperiorPlayer, Island> predicate) {\n        List<String> tabArguments = new LinkedList<>();\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n\n        for (Player player : Bukkit.getOnlinePlayers()) {\n            SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(player);\n            if (!hideVanish || onlinePlayer.isShownAsOnline()) {\n                Island onlineIsland = onlinePlayer.getIsland();\n                if (onlineIsland != null && (predicate == null || predicate.test(onlinePlayer, onlineIsland))) {\n                    if (onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                        tabArguments.add(onlinePlayer.getName());\n                    if (onlineIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                        tabArguments.add(onlineIsland.getStrippedName());\n                }\n            }\n        }\n\n        return Collections.unmodifiableList(tabArguments);\n    }\n\n    public static List<String> getIslandWarps(Island island, String argument) {\n        return filterByArgument(island.getIslandWarps().keySet(), argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getIslandVisitors(Island island, String argument, boolean hideVanish) {\n        return getPlayers(island.getIslandVisitors(!hideVanish), argument);\n    }\n\n    public static List<String> getCustomComplete(String argument, String... tabVariables) {\n        return getCustomComplete(argument, Arrays.asList(tabVariables));\n    }\n\n    public static List<String> getCustomComplete(String argument, Collection<String> tabVariables) {\n        return filterByArgument(tabVariables, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getCustomComplete(String argument, Predicate<String> predicate, String... tabVariables) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(var -> var.contains(lowerArgument) && predicate.test(var))\n                .build(Arrays.asList(tabVariables));\n    }\n\n    public static List<String> getCustomComplete(String argument, IntStream tabVariables) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(var -> var.contains(lowerArgument))\n                .build(Stream.of(tabVariables).map(i -> i + \"\"));\n    }\n\n    public static List<String> getSchematics(SuperiorSkyblockPlugin plugin, String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(schematic -> !schematic.endsWith(\"_nether\") && !schematic.endsWith(\"_normal\") &&\n                        !schematic.endsWith(\"_the_end\") && schematic.toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .build(plugin.getSchematics().getSchematics());\n    }\n\n    public static List<String> getIslandBannedPlayers(Island island, String argument) {\n        return getPlayers(island.getBannedPlayers(), argument);\n    }\n\n    public static List<String> getUpgrades(SuperiorSkyblockPlugin plugin, String argument) {\n        return filterByArgument(plugin.getUpgrades().getUpgrades(), Upgrade::getName, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument, Predicate<PlayerRole> predicate) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<PlayerRole>()\n                .filter(playerRole -> (predicate == null || predicate.test(playerRole)) &&\n                        playerRole.toString().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(plugin.getRoles().getRoles(), PlayerRole::getName);\n    }\n\n    public static List<String> getMaterials(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(Materials.getBlocksNonLegacy().stream()\n                .filter(material -> material.isBlock() && !Materials.isLegacy(material))\n                .map(material -> material.name().toLowerCase(Locale.ENGLISH))\n                .filter(materialName -> materialName.contains(lowerArgument)));\n    }\n\n    public static List<String> getPotionEffects(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<PotionEffectType>()\n                .filter(potionEffectType -> {\n                    try {\n                        return potionEffectType != null && potionEffectType.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument);\n                    } catch (Exception ex) {\n                        return false;\n                    }\n                })\n                .map(PotionEffectType.values(), potionEffectType -> {\n                    String name = potionEffectType.getName();\n                    if (name.startsWith(\"minecraft:\")) {\n                        name = name.substring(\"minecraft:\".length()).toLowerCase(Locale.ENGLISH);\n                    } else {\n                        name = name.toLowerCase(Locale.ENGLISH);\n                    }\n                    return name;\n                });\n    }\n\n    public static List<String> getEntitiesForLimit(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(Stream.of(EntityType.values())\n                .filter(BukkitEntities::canHaveLimit)\n                .map(entityType -> entityType.name().toLowerCase(Locale.ENGLISH))\n                .filter(entityTypeName -> entityTypeName.contains(lowerArgument)));\n    }\n\n    public static List<String> getMaterialsForGenerators(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(Materials.getSolids().stream()\n                .map(material -> material.name().toLowerCase(Locale.ENGLISH))\n                .filter(materialName -> materialName.contains(lowerArgument)));\n    }\n\n    public static List<String> getMissions(SuperiorSkyblockPlugin plugin, String argument, Predicate<Mission<?>> predicate) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(plugin.getMissions().getAllMissions().stream()\n                .filter(mission -> predicate.test(mission) &&\n                        mission.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(mission -> mission.getName().toLowerCase(Locale.ENGLISH)));\n    }\n\n    public static List<String> getMissionCategories(SuperiorSkyblockPlugin plugin, String argument, Predicate<MissionCategory> predicate) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(plugin.getMissions().getMissionCategories().stream()\n                .filter(category -> predicate.test(category) &&\n                        category.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(category -> category.getName().toLowerCase(Locale.ENGLISH)));\n    }\n\n    public static List<String> getCustomMenus(SuperiorSkyblockPlugin plugin, String argument) {\n        return filterByArgument(plugin.getMenus().getCustomMenus().values(), menu ->\n                        menu.getIdentifier().substring(MenuIdentifiers.MENU_CUSTOM_PREFIX.length()),\n                argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getBiomes(String argument) {\n        NMSAlgorithms.EnumBridge<Biome> biomeEnumBridge = plugin.getNMSAlgorithms().getBiomeBridge();\n        return filterByArgument(biomeEnumBridge.getValues(), biomeEnumBridge::getName, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getWorlds(String argument) {\n        return filterByArgument(Bukkit.getWorlds(), World::getName, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getIslandPrivileges(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.contains(lowerArgument))\n                .build(IslandPrivilege.values(), islandPrivilege -> islandPrivilege.getName().toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getRatedPlayers(SuperiorSkyblockPlugin plugin, Island island, String argument) {\n        return filterByArgument(island.getRatings().keySet(),\n                playerUUID -> plugin.getPlayers().getSuperiorPlayer(playerUUID).getName(),\n                argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getRatings(String argument) {\n        return getFromEnum(Arrays.asList(Rating.values()), argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getIslandFlags(String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.contains(lowerArgument))\n                .build(IslandFlag.values(), islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getDimensions(SuperiorSkyblockPlugin plugin, String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>().build(Dimension.values().stream()\n                .filter(dimension -> plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) &&\n                        dimension.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(dimension -> dimension.getName().toLowerCase(Locale.ENGLISH)));\n    }\n\n    public static List<String> getBorderColors(String argument) {\n        return getFromEnum(Arrays.asList(BorderColor.values()), argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    public static List<String> getModules(SuperiorSkyblockPlugin plugin, String argument) {\n        return filterByArgument(plugin.getModules().getModules(), PluginModule::getName, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    private static List<String> getPlayers(Collection<SuperiorPlayer> players, String argument) {\n        return filterByArgument(players, SuperiorPlayer::getName, argument.toLowerCase(Locale.ENGLISH));\n    }\n\n    private static List<String> getPlayers(Collection<SuperiorPlayer> players, String argument, Predicate<SuperiorPlayer> predicate) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<SuperiorPlayer>()\n                .filter(player -> predicate.test(player) && player.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument))\n                .map(players, SuperiorPlayer::getName);\n    }\n\n    private static List<SuperiorPlayer> getOnlineSuperiorPlayers(SuperiorSkyblockPlugin plugin) {\n        return new SequentialListBuilder<SuperiorPlayer>()\n                .mutable()\n                .build(Bukkit.getOnlinePlayers(), player -> plugin.getPlayers().getSuperiorPlayer(player));\n    }\n\n    private static List<String> filterByArgument(Collection<String> collection, String argument) {\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument))\n                .build(collection);\n    }\n\n    private static <E> List<String> filterByArgument(Collection<E> collection, Function<E, String> mapper, String argument) {\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument))\n                .build(collection, mapper);\n    }\n\n    private static <E> List<String> filterByArgument(E[] collection, Function<E, String> mapper, String argument) {\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument))\n                .build(collection, mapper);\n    }\n\n    private static List<String> getFromEnum(Collection<Enum<?>> enums, String argument) {\n        String lowerArgument = argument.toLowerCase(Locale.ENGLISH);\n        return new SequentialListBuilder<String>()\n                .filter(name -> name.contains(lowerArgument))\n                .build(enums, enumElement -> enumElement.name().toLowerCase(Locale.ENGLISH));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport org.bukkit.command.CommandSender;\n\npublic class CommandsHelper {\n\n    private CommandsHelper() {\n\n    }\n\n    public static boolean shouldDisplayCommandForPlayer(SuperiorCommand superiorCommand, CommandSender executor) {\n        return superiorCommand.displayCommand() && hasCommandAccess(superiorCommand, executor);\n    }\n\n    public static boolean hasCommandAccess(SuperiorCommand superiorCommand, CommandSender executor) {\n        String permission = superiorCommand.getPermission();\n        return Text.isBlank(permission) || executor.hasPermission(permission);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.handlers.CommandsManager;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.FileClassLoader;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.JarFiles;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport org.bukkit.entity.Player;\n\nimport java.io.File;\nimport java.lang.reflect.Constructor;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class CommandsManagerImpl extends Manager implements CommandsManager {\n\n    private final Map<UUID, Map<String, Long>> commandsCooldown = new HashMap<>();\n\n    private final CommandsMap playerCommandsMap;\n    private final CommandsMap adminCommandsMap;\n\n    private Set<Runnable> pendingCommands = new HashSet<>();\n\n    private PluginCommand pluginCommand;\n    private String label = null;\n\n    public CommandsManagerImpl(SuperiorSkyblockPlugin plugin, CommandsMap playerCommandsMap, CommandsMap adminCommandsMap) {\n        super(plugin);\n        this.playerCommandsMap = playerCommandsMap;\n        this.adminCommandsMap = adminCommandsMap;\n    }\n\n    @Override\n    public void loadData() {\n        String islandCommand = plugin.getSettings().getIslandCommand();\n        label = islandCommand.split(\",\")[0];\n\n        pluginCommand = new PluginCommand(label);\n\n        String[] commandSections = islandCommand.split(\",\");\n\n        if (commandSections.length > 1) {\n            pluginCommand.setAliases(Arrays.asList(Arrays.copyOfRange(commandSections, 1, commandSections.length)));\n        }\n\n        plugin.getNMSAlgorithms().registerCommand(pluginCommand);\n\n        playerCommandsMap.loadDefaultCommands();\n        adminCommandsMap.loadDefaultCommands();\n\n        loadCommands();\n\n        if (this.pendingCommands != null) {\n            Set<Runnable> pendingCommands = new HashSet<>(this.pendingCommands);\n            this.pendingCommands = null;\n            pendingCommands.forEach(Runnable::run);\n        }\n    }\n\n    @Override\n    public void registerCommand(SuperiorCommand superiorCommand) {\n        Preconditions.checkNotNull(superiorCommand, \"superiorCommand parameter cannot be null.\");\n\n        if (pendingCommands != null) {\n            pendingCommands.add(() -> registerCommand(superiorCommand));\n            return;\n        }\n\n        playerCommandsMap.registerCommand(superiorCommand);\n    }\n\n    @Override\n    public void unregisterCommand(SuperiorCommand superiorCommand) {\n        playerCommandsMap.unregisterCommand(superiorCommand);\n    }\n\n    @Override\n    public void registerAdminCommand(SuperiorCommand superiorCommand) {\n        if (pendingCommands != null) {\n            pendingCommands.add(() -> registerAdminCommand(superiorCommand));\n            return;\n        }\n\n        Preconditions.checkNotNull(superiorCommand, \"superiorCommand parameter cannot be null.\");\n        adminCommandsMap.registerCommand(superiorCommand);\n    }\n\n    @Override\n    public void unregisterAdminCommand(SuperiorCommand superiorCommand) {\n        Preconditions.checkNotNull(superiorCommand, \"superiorCommand parameter cannot be null.\");\n        adminCommandsMap.unregisterCommand(superiorCommand);\n    }\n\n    @Override\n    public List<SuperiorCommand> getSubCommands() {\n        return getSubCommands(false);\n    }\n\n    @Override\n    public List<SuperiorCommand> getSubCommands(boolean includeDisabled) {\n        return playerCommandsMap.getSubCommands(includeDisabled);\n    }\n\n    @Nullable\n    @Override\n    public SuperiorCommand getCommand(String commandLabel) {\n        return playerCommandsMap.getCommand(commandLabel);\n    }\n\n    @Override\n    public List<SuperiorCommand> getAdminSubCommands() {\n        return adminCommandsMap.getSubCommands(true);\n    }\n\n    @Nullable\n    @Override\n    public SuperiorCommand getAdminCommand(String commandLabel) {\n        return adminCommandsMap.getCommand(commandLabel);\n    }\n\n    @Override\n    public void dispatchSubCommand(CommandSender sender, String subCommand) {\n        dispatchSubCommand(sender, subCommand, null);\n    }\n\n    @Override\n    public void dispatchSubCommand(CommandSender sender, String subCommand, @Nullable String args) {\n        // We first check that the sub command is enabled.\n        if (getCommand(subCommand) == null) {\n            Bukkit.dispatchCommand(sender, this.label + \" \" + subCommand + (args == null ? \"\" : \" \" + args));\n            return;\n        }\n\n        String[] argsSplit = args == null ? null : args.split(\" \");\n        String[] commandArguments;\n\n        if (argsSplit == null || (argsSplit.length == 1 && argsSplit[0].isEmpty())) {\n            commandArguments = new String[1];\n            commandArguments[0] = subCommand;\n        } else {\n            commandArguments = new String[argsSplit.length + 1];\n            commandArguments[0] = subCommand;\n            System.arraycopy(argsSplit, 0, commandArguments, 1, argsSplit.length);\n        }\n\n        pluginCommand.execute(sender, \"\", commandArguments);\n    }\n\n    public String getLabel() {\n        return label;\n    }\n\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    private void loadCommands() {\n        File commandsFolder = new File(plugin.getDataFolder(), \"commands\");\n\n        if (!commandsFolder.exists()) {\n            commandsFolder.mkdirs();\n            return;\n        }\n\n        List<File> folderFiles = Files.listFolderFiles(commandsFolder, false, file -> file.getName().endsWith(\".jar\"));\n        if (folderFiles.isEmpty())\n            return;\n\n        try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(commandsFolder)) {\n            for (File file : folderFiles) {\n                try {\n                    String fileName = file.getName();\n                    file = filesLookup.getFile(fileName);\n\n                    FileClassLoader classLoader = new FileClassLoader(file, plugin.getPluginClassLoader(),\n                            plugin.getNMSAlgorithms().getClassProcessor());\n\n                    //noinspection deprecation\n                    Class<?> commandClass = JarFiles.getClass(file.toURL(), SuperiorCommand.class, classLoader).getLeft();\n\n                    if (commandClass == null)\n                        continue;\n\n                    SuperiorCommand superiorCommand = createInstance(commandClass);\n\n                    if (file.getName().toLowerCase(Locale.ENGLISH).contains(\"admin\")) {\n                        registerAdminCommand(superiorCommand);\n                        Log.info(\"Successfully loaded external admin command: \", file.getName().split(\"\\\\.\")[0]);\n                    } else {\n                        registerCommand(superiorCommand);\n                        Log.info(\"Successfully loaded external command: \", file.getName().split(\"\\\\.\")[0]);\n                    }\n\n                } catch (Exception error) {\n                    Log.error(error, \"An unexpected error occurred while loading an external command \", file.getName(), \":\");\n                }\n            }\n        }\n\n    }\n\n    private SuperiorCommand createInstance(Class<?> clazz) throws Exception {\n        Preconditions.checkArgument(SuperiorCommand.class.isAssignableFrom(clazz), \"Class \" + clazz + \" is not a SuperiorCommand.\");\n\n        for (Constructor<?> constructor : clazz.getConstructors()) {\n            if (constructor.getParameterCount() == 0) {\n                if (!constructor.isAccessible())\n                    constructor.setAccessible(true);\n\n                return (SuperiorCommand) constructor.newInstance();\n            }\n        }\n\n        throw new IllegalArgumentException(\"Class \" + clazz + \" has no valid constructors.\");\n    }\n\n    private class PluginCommand extends BukkitCommand {\n\n        PluginCommand(String islandCommandLabel) {\n            super(islandCommandLabel);\n        }\n\n        @Override\n        public boolean execute(CommandSender sender, String label, String[] args) {\n            java.util.Locale locale = PlayerLocales.getLocale(sender);\n\n            String executedSubCommand;\n\n            if (args.length > 0) {\n                executedSubCommand = args[0];\n\n                Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), executedSubCommand);\n\n                SuperiorCommand command = playerCommandsMap.getCommand(executedSubCommand);\n                if (command != null) {\n                    if (!(sender instanceof Player) && !command.canBeExecutedByConsole()) {\n                        Message.CUSTOM.send(sender, \"&cCan be executed only by players!\", true);\n                        return false;\n                    }\n\n                    if (!CommandsHelper.hasCommandAccess(command, sender)) {\n                        Log.debugResult(Debug.EXECUTE_COMMAND, \"Return Missing Permission\", command.getPermission());\n\n                        if (!plugin.getSettings().isHelpOnNoPermission())\n                            Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission());\n                        else if (!\"help\".equalsIgnoreCase(executedSubCommand))\n                            dispatchSubCommand(sender, \"help\");\n\n                        return false;\n                    }\n\n                    if (args.length < command.getMinArgs() || args.length > command.getMaxArgs()) {\n                        Log.debugResult(Debug.EXECUTE_COMMAND, \"Return Incorrect Usage\", command.getUsage(locale));\n                        Message.COMMAND_USAGE.send(sender, locale, getLabel() + \" \" + command.getUsage(locale));\n                        return false;\n                    }\n\n                    if (sender instanceof Player) {\n                        UUID uuid = ((Player) sender).getUniqueId();\n                        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid);\n                        if (!superiorPlayer.hasPermission(\"superior.admin.bypass.cooldowns\")) {\n                            Pair<Integer, String> commandCooldown = getCooldown(command);\n                            if (commandCooldown != null) {\n                                String commandLabel = command.getAliases().get(0);\n\n                                Map<String, Long> playerCooldowns = commandsCooldown.get(uuid);\n                                long timeNow = System.currentTimeMillis();\n\n                                if (playerCooldowns != null) {\n                                    Long timeToExecute = playerCooldowns.get(commandLabel);\n                                    if (timeToExecute != null) {\n                                        if (timeNow < timeToExecute) {\n                                            String formattedTime = Formatters.TIME_FORMATTER.format(Duration.ofMillis(timeToExecute - timeNow), locale);\n                                            Log.debugResult(Debug.EXECUTE_COMMAND, \"Return Cooldown\", formattedTime);\n                                            Message.COMMAND_COOLDOWN_FORMAT.send(sender, locale, formattedTime);\n                                            return false;\n                                        }\n                                    }\n                                }\n\n                                commandsCooldown.computeIfAbsent(uuid, u -> new HashMap<>()).put(commandLabel,\n                                        timeNow + commandCooldown.getKey());\n                            }\n                        }\n                    }\n\n                    command.execute(plugin, sender, args);\n                    return false;\n                }\n\n                if (!plugin.getSettings().isHelpOnInvalidCommand())\n                    Message.INVALID_COMMAND.send(sender, locale, executedSubCommand);\n                else if (!\"help\".equalsIgnoreCase(executedSubCommand))\n                    dispatchSubCommand(sender, \"help\");\n\n                return false;\n            }\n\n            if (sender instanceof Player) {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n                if (superiorPlayer != null) {\n                    String subCommandToExecute;\n\n                    if (!superiorPlayer.hasIsland())\n                        subCommandToExecute = \"create\";\n                    else if (superiorPlayer.hasToggledPanel())\n                        subCommandToExecute = \"panel\";\n                    else\n                        subCommandToExecute = \"tp\";\n\n                    dispatchSubCommand(sender, subCommandToExecute);\n                    return false;\n                }\n            }\n\n            return false;\n        }\n\n        @Override\n        public List<String> tabComplete(CommandSender sender, String label, String[] args) {\n            if (args.length > 0) {\n                SuperiorCommand command = playerCommandsMap.getCommand(args[0]);\n                if (command != null) {\n                    return CommandsHelper.shouldDisplayCommandForPlayer(command, sender) ?\n                            command.tabComplete(plugin, sender, args) : Collections.emptyList();\n                }\n            }\n\n            List<String> list = new LinkedList<>();\n\n            for (SuperiorCommand subCommand : getSubCommands()) {\n                if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) {\n                    List<String> aliases = new LinkedList<>(subCommand.getAliases());\n                    aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList()));\n                    for (String alias : aliases) {\n                        if (alias.contains(args[0].toLowerCase(Locale.ENGLISH))) {\n                            list.add(alias);\n                        }\n                    }\n                }\n            }\n\n            return list;\n        }\n\n    }\n\n    @Nullable\n    private Pair<Integer, String> getCooldown(SuperiorCommand command) {\n        for (String alias : command.getAliases()) {\n            Pair<Integer, String> commandCooldown = plugin.getSettings().getCommandsCooldown().get(alias);\n            if (commandCooldown != null)\n                return commandCooldown;\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\npublic abstract class CommandsMap {\n\n    private static Set<String> DISABLED_COMMANDS_CACHE;\n\n    private static void onSettingsUpdate() {\n        DISABLED_COMMANDS_CACHE = new HashSet<>();\n        SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n        plugin.getSettings().getDisabledCommands().forEach(commandLabel -> {\n            SuperiorCommand superiorCommand = plugin.getCommands().getCommand(commandLabel);\n            if (superiorCommand != null && !(superiorCommand instanceof IAdminIslandCommand))\n                DISABLED_COMMANDS_CACHE.add(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH));\n        });\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CommandsMap::onSettingsUpdate);\n    }\n\n    private final Map<String, SuperiorCommand> subCommands = new TreeMap<>();\n    private final Map<String, List<SuperiorCommand>> aliasesToCommand = new HashMap<>();\n\n    protected final SuperiorSkyblockPlugin plugin;\n\n    protected CommandsMap(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public abstract void loadDefaultCommands();\n\n    public void registerCommand(SuperiorCommand superiorCommand) {\n        List<String> aliases = new LinkedList<>(superiorCommand.getAliases());\n        String label = aliases.remove(0).toLowerCase(Locale.ENGLISH);\n        aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList()));\n\n        removeCommand(label);\n        subCommands.put(label, superiorCommand);\n\n        for (String alias : aliases) {\n            aliasesToCommand.computeIfAbsent(alias.toLowerCase(Locale.ENGLISH), a -> new LinkedList<>()).add(superiorCommand);\n        }\n\n        PluginEventsFactory.callCommandsUpdateEvent();\n    }\n\n    public void unregisterCommand(SuperiorCommand superiorCommand) {\n        Preconditions.checkNotNull(superiorCommand, \"superiorCommand parameter cannot be null.\");\n\n        List<String> aliases = new LinkedList<>(superiorCommand.getAliases());\n        String label = aliases.remove(0).toLowerCase(Locale.ENGLISH);\n        aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList()));\n\n        removeCommand(label);\n\n        PluginEventsFactory.callCommandsUpdateEvent();\n    }\n\n    @Nullable\n    public SuperiorCommand getCommand(String label) {\n        label = label.toLowerCase(Locale.ENGLISH);\n        SuperiorCommand superiorCommand = subCommands.get(label);\n        if (superiorCommand != null && isCommandEnabled(superiorCommand))\n            return superiorCommand;\n\n        List<SuperiorCommand> commandAliases = aliasesToCommand.getOrDefault(label, Collections.emptyList());\n        for (SuperiorCommand commandAlias : commandAliases) {\n            if (isCommandEnabled(commandAlias)) {\n                return commandAlias;\n            }\n        }\n\n        return null;\n    }\n\n    public List<SuperiorCommand> getSubCommands(boolean includeDisabled) {\n        SequentialListBuilder<SuperiorCommand> listBuilder = new SequentialListBuilder<>();\n\n        if (!includeDisabled)\n            listBuilder.filter(this::isCommandEnabled);\n\n        return listBuilder.build(this.subCommands.values());\n    }\n\n    protected void clearCommands() {\n        this.subCommands.clear();\n        this.aliasesToCommand.clear();\n    }\n\n    private boolean isCommandEnabled(SuperiorCommand superiorCommand) {\n        return superiorCommand instanceof IAdminIslandCommand ||\n                !DISABLED_COMMANDS_CACHE.contains(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH));\n    }\n\n    private void removeCommand(String label) {\n        if (subCommands.remove(label) != null) {\n            aliasesToCommand.values().forEach(commandsList ->\n                    commandsList.removeIf(sC -> sC.getAliases().get(0).equalsIgnoreCase(label)));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandsListArgument;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic interface IAdminIslandCommand extends ISuperiorCommand {\n\n    @Override\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (!supportMultipleIslands()) {\n            IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[2]);\n            if (arguments.getIsland() != null)\n                execute(plugin, sender, arguments.getSuperiorPlayer(), arguments.getIsland(), args);\n        } else {\n            IslandsListArgument arguments = CommandArguments.getMultipleIslands(plugin, sender, args[2]);\n            if (!arguments.getIslands().isEmpty())\n                execute(plugin, sender, arguments.getSuperiorPlayer(), arguments.getIslands(), args);\n        }\n    }\n\n    @Override\n    default List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        List<String> tabVariables = new LinkedList<>();\n\n        if (args.length == 3) {\n            if (supportMultipleIslands() && \"*\".contains(args[2]))\n                tabVariables.add(\"*\");\n            tabVariables.addAll(CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, null));\n        } else if (args.length > 3) {\n            if (supportMultipleIslands()) {\n                tabVariables = adminTabComplete(plugin, sender, null, args);\n            } else {\n                SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]);\n                Island island = targetPlayer == null ? plugin.getGrid().getIsland(args[2]) : targetPlayer.getIsland();\n                if (island != null) {\n                    tabVariables = adminTabComplete(plugin, sender, island, args);\n                    if (tabVariables.isEmpty())\n                        tabVariables = adminTabComplete(plugin, sender, island, args);\n                }\n            }\n        }\n\n        return tabVariables == null ? Collections.emptyList() : Collections.unmodifiableList(tabVariables);\n    }\n\n    boolean supportMultipleIslands();\n\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer,\n                         Island island, String[] args) {\n        // Not all commands should implement this method.\n    }\n\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer,\n                         List<Island> islands, String[] args) {\n        // Not all commands should implement this method.\n    }\n\n    default List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminPlayerCommand.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic interface IAdminPlayerCommand extends ISuperiorCommand {\n\n    @Override\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (!supportMultiplePlayers()) {\n            SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[2]);\n            if (targetPlayer != null) {\n                Island playerIsland = targetPlayer.getIsland();\n\n                if (requireIsland() && playerIsland == null) {\n                    Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n                    return;\n                }\n\n                execute(plugin, sender, targetPlayer, args);\n            }\n        } else {\n            List<SuperiorPlayer> players = CommandArguments.getMultiplePlayers(plugin, sender, args[2]);\n            if (!players.isEmpty())\n                execute(plugin, sender, players, args);\n        }\n    }\n\n    @Override\n    default List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        List<String> tabVariables = new LinkedList<>();\n\n        if (args.length == 3) {\n            if (supportMultiplePlayers() && \"*\".contains(args[2]))\n                tabVariables.add(\"*\");\n            tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[2], false));\n        } else if (args.length > 3) {\n            if (supportMultiplePlayers()) {\n                tabVariables = adminTabComplete(plugin, sender, null, args);\n            } else {\n                SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]);\n                if (targetPlayer != null) {\n                    tabVariables = adminTabComplete(plugin, sender, targetPlayer, args);\n                }\n            }\n        }\n\n        return Collections.unmodifiableList(tabVariables);\n    }\n\n    boolean supportMultiplePlayers();\n\n    default boolean requireIsland() {\n        return false;\n    }\n\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        // Not all commands should implement this method.\n    }\n\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List<SuperiorPlayer> targetPlayers, String[] args) {\n        // Not all commands should implement this method.\n    }\n\n    default List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/IPermissibleCommand.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic interface IPermissibleCommand extends ISuperiorCommand {\n\n    @Override\n    default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = null;\n        SuperiorPlayer superiorPlayer = null;\n\n        if (!canBeExecutedByConsole() || sender instanceof Player) {\n            IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n            island = arguments.getIsland();\n\n            if (island == null)\n                return;\n\n            superiorPlayer = arguments.getSuperiorPlayer();\n\n            if (!superiorPlayer.hasPermission(getPrivilege())) {\n                getPermissionLackMessage().send(superiorPlayer, island.getRequiredPlayerRole(getPrivilege()));\n                return;\n            }\n        }\n\n        execute(plugin, superiorPlayer, island, args);\n    }\n\n    @Override\n    default List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = null;\n        SuperiorPlayer superiorPlayer = null;\n\n        if (!canBeExecutedByConsole() || sender instanceof Player) {\n            superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n            island = superiorPlayer.getIsland();\n        }\n\n        return superiorPlayer == null || (island != null && superiorPlayer.hasPermission(getPrivilege())) ?\n                tabComplete(plugin, superiorPlayer, island, args) : Collections.emptyList();\n    }\n\n    IslandPrivilege getPrivilege();\n\n    Message getPermissionLackMessage();\n\n    void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args);\n\n    default List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/ISuperiorCommand.java",
    "content": "package com.bgsoftware.superiorskyblock.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.List;\n\npublic interface ISuperiorCommand extends SuperiorCommand {\n\n    @Override\n    default boolean displayCommand() {\n        return true;\n    }\n\n    default void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args) {\n        execute((SuperiorSkyblockPlugin) plugin, sender, args);\n    }\n\n    default List<String> tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args) {\n        return tabComplete((SuperiorSkyblockPlugin) plugin, sender, args);\n    }\n\n    void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args);\n\n    List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.CommandsMap;\n\npublic class AdminCommandsMap extends CommandsMap {\n\n    public AdminCommandsMap(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadDefaultCommands() {\n        clearCommands();\n\n        registerCommand(new CmdAdminAdd());\n        registerCommand(new CmdAdminAddBonus());\n        if (plugin.getSettings().isCoopMembers())\n            registerCommand(new CmdAdminAddCoopLimit());\n        registerCommand(new CmdAdminAddDisbands());\n        registerCommand(new CmdAdminAddSize());\n        registerCommand(new CmdAdminAddTeamLimit());\n        registerCommand(new CmdAdminAddWarpsLimit());\n        registerCommand(new CmdAdminBypass());\n        registerCommand(new CmdAdminChest());\n        registerCommand(new CmdAdminClose());\n        registerCommand(new CmdAdminCmdAll());\n        registerCommand(new CmdAdminCount());\n        registerCommand(new CmdAdminData());\n        registerCommand(new CmdAdminDebug());\n        registerCommand(new CmdAdminDelWarp());\n        registerCommand(new CmdAdminDemote());\n        registerCommand(new CmdAdminDisband());\n        registerCommand(new CmdAdminFly());\n        registerCommand(new CmdAdminIgnore());\n        registerCommand(new CmdAdminJoin());\n        registerCommand(new CmdAdminKick());\n        registerCommand(new CmdAdminModules());\n        registerCommand(new CmdAdminMsg());\n        registerCommand(new CmdAdminMsgAll());\n        registerCommand(new CmdAdminName());\n        registerCommand(new CmdAdminOpen());\n        registerCommand(new CmdAdminOpenMenu());\n        registerCommand(new CmdAdminPromote());\n        registerCommand(new CmdAdminPurge());\n        registerCommand(new CmdAdminRecalc());\n        registerCommand(new CmdAdminReload());\n        registerCommand(new CmdAdminRemoveRatings());\n        registerCommand(new CmdAdminResetPermissions());\n        registerCommand(new CmdAdminResetSettings());\n        registerCommand(new CmdAdminResetWorld());\n        registerCommand(new CmdAdminSchematic());\n        registerCommand(new CmdAdminSetBiome());\n        registerCommand(new CmdAdminSetBlockAmount());\n        registerCommand(new CmdAdminSetBonus());\n        registerCommand(new CmdAdminSetChestRow());\n        if (plugin.getSettings().isCoopMembers())\n            registerCommand(new CmdAdminSetCoopLimit());\n        registerCommand(new CmdAdminSetDisbands());\n        registerCommand(new CmdAdminSetIslandPreview());\n        registerCommand(new CmdAdminSetLeader());\n        registerCommand(new CmdAdminSetPermission());\n        registerCommand(new CmdAdminSetRate());\n        registerCommand(new CmdAdminSetRoleLimit());\n        registerCommand(new CmdAdminSetSettings());\n        registerCommand(new CmdAdminSetSize());\n        registerCommand(new CmdAdminSetSpawn());\n        registerCommand(new CmdAdminSetTeamLimit());\n        registerCommand(new CmdAdminSettings());\n        registerCommand(new CmdAdminSetWarpsLimit());\n        registerCommand(new CmdAdminShow());\n        registerCommand(new CmdAdminSpawn());\n        registerCommand(new CmdAdminSpy());\n        registerCommand(new CmdAdminStats());\n        registerCommand(new CmdAdminSyncBonus());\n        registerCommand(new CmdAdminTeleport());\n        registerCommand(new CmdAdminTitle());\n        registerCommand(new CmdAdminTitleAll());\n        registerCommand(new CmdAdminUnignore());\n        registerCommand(new CmdAdminUnlockWorld());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAdd implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"add\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.add\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin add <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[3]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (targetPlayer.getIsland() != null) {\n            Message.PLAYER_ALREADY_IN_ISLAND.send(sender);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandJoinEvent(island, targetPlayer, IslandJoinEvent.Cause.ADMIN))\n            return;\n\n        IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName());\n\n        island.addMember(targetPlayer, SPlayerRole.defaultRole());\n\n        if (superiorPlayer == null) {\n            Message.JOINED_ISLAND_NAME.send(targetPlayer, island.getName());\n            Message.ADMIN_ADD_PLAYER_NAME.send(sender, targetPlayer.getName(), island.getName());\n        } else {\n            Message.JOINED_ISLAND.send(targetPlayer, superiorPlayer.getName());\n            Message.ADMIN_ADD_PLAYER.send(sender, targetPlayer.getName(), superiorPlayer.getName());\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getOnlinePlayers(plugin, args[3], false,\n                superiorPlayer -> superiorPlayer.getIsland() == null) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdminAddBonus implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addbonus\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addbonus\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addbonus <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <worth/level> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BONUS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        boolean isWorthBonus;\n\n        if (args[3].equalsIgnoreCase(\"worth\")) {\n            isWorthBonus = true;\n        } else if (args[3].equalsIgnoreCase(\"level\")) {\n            isWorthBonus = false;\n        } else {\n            Locale locale = PlayerLocales.getLocale(sender);\n            Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + \" \" + getUsage(locale));\n            return;\n        }\n\n        BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]);\n\n        if (bonus == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (isWorthBonus) {\n                PluginEvent<PluginEventArgs.IslandChangeWorthBonus> event = PluginEventsFactory.callIslandChangeWorthBonusEvent(\n                        island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, island.getBonusWorth().add(bonus));\n                if (!event.isCancelled()) {\n                    island.setBonusWorth(event.getArgs().worthBonus);\n                    ++islandsChangedCount;\n                }\n            } else {\n                PluginEvent<PluginEventArgs.IslandChangeLevelBonus> event = PluginEventsFactory.callIslandChangeLevelBonusEvent(\n                        island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, island.getBonusLevel().add(bonus));\n                if (!event.isCancelled()) {\n                    island.setBonusLevel(event.getArgs().levelBonus);\n                    ++islandsChangedCount;\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (isWorthBonus) {\n            if (islandsChangedCount > 1)\n                Message.CHANGED_BONUS_WORTH_ALL.send(sender);\n            else if (targetPlayer == null)\n                Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName());\n            else\n                Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName());\n        } else {\n            if (islandsChangedCount > 1)\n                Message.CHANGED_BONUS_LEVEL_ALL.send(sender);\n            else if (targetPlayer == null)\n                Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName());\n            else\n                Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName());\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"worth\", \"level\") : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddCoopLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addcooplimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addcooplimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addcooplimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeCoopLimit> event = PluginEventsFactory.callIslandChangeCoopLimitEvent(\n                    island, sender, island.getCoopLimit() + limit);\n            if (!event.isCancelled()) {\n                island.setCoopLimit(event.getArgs().coopLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_COOP_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_COOP_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdAdminAddDisbands implements IAdminPlayerCommand {\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"adddisbands\", \"givedisbands\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.givedisbands\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin adddisbands <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_PLAYERS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List<SuperiorPlayer> targetPlayers, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int amount = arguments.getNumber();\n\n        targetPlayers.forEach(superiorPlayer -> superiorPlayer.setDisbands(superiorPlayer.getDisbands() + amount));\n\n        if (targetPlayers.size() > 1) {\n            Message.DISBAND_GIVE_ALL.send(sender, amount);\n        } else if (!sender.equals(targetPlayers.get(0).asPlayer()))\n            Message.DISBAND_GIVE_OTHER.send(sender, targetPlayers.get(0).getName(), amount);\n\n        targetPlayers.forEach(superiorPlayer -> Message.DISBAND_GIVE.send(superiorPlayer, amount));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddSize implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addsize\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addsize\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addsize <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_SIZE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_SIZE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getSize(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int size = arguments.getNumber();\n\n        if (size > plugin.getSettings().getMaxIslandSize()) {\n            Message.SIZE_BIGGER_MAX.send(sender);\n            return;\n        }\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBorderSize> event = PluginEventsFactory.callIslandChangeBorderSizeEvent(\n                    island, sender, island.getIslandSize() + size);\n            if (!event.isCancelled()) {\n                island.setIslandSize(event.getArgs().borderSize);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ISLAND_SIZE_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_ISLAND_SIZE.send(sender, targetPlayer.getName());\n\n        if (plugin.getSettings().isBuildOutsideIsland())\n            Message.CHANGED_ISLAND_SIZE_BUILD_OUTSIDE.send(sender);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddTeamLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addteamlimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addteamlimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addteamlimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeMembersLimit> event = PluginEventsFactory.callIslandChangeMembersLimitEvent(\n                    island, sender, island.getTeamLimit() + limit);\n            if (!event.isCancelled()) {\n                island.setTeamLimit(event.getArgs().membersLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_TEAM_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_TEAM_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddWarpsLimit implements IAdminIslandCommand {\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addwarpslimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addwarpslimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addwarpslimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        if (limit <= 0) {\n            Message.INVALID_AMOUNT.send(sender);\n            return;\n        }\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeWarpsLimit> event = PluginEventsFactory.callIslandChangeWarpsLimitEvent(\n                    island, sender, island.getWarpsLimit() + limit);\n            if (!event.isCancelled()) {\n                island.setWarpsLimit(event.getArgs().warpsLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_WARPS_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_WARPS_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminBypass implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"bypass\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.bypass\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin bypass\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_BYPASS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (!PluginEventsFactory.callPlayerToggleBypassEvent(superiorPlayer))\n            return;\n\n        if (superiorPlayer.hasBypassModeEnabled()) {\n            Message.TOGGLED_BYPASS_OFF.send(superiorPlayer);\n        } else {\n            Message.TOGGLED_BYPASS_ON.send(superiorPlayer);\n        }\n\n        superiorPlayer.toggleBypassMode();\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminChest implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"chest\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.chest\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin chest <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_CHEST.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminClose implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"close\", \"lock\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.close\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin close <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_CLOSE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        if (island.isLocked()) {\n            Message.ISLAND_ALREADY_CLOSED.send(sender);\n        } else if (PluginEventsFactory.callIslandCloseEvent(island, sender)) {\n            island.setLocked(true);\n            Message.ISLAND_CLOSED.send(sender);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false,\n                (superiorPlayer, island) -> !island.isLocked()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCmdAll.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminCmdAll implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"cmdall\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.cmdall\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin cmdall <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <online-filter[true/false]> <\" +\n                Message.COMMAND_ARGUMENT_COMMAND.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_CMD_ALL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        String command = CommandArguments.buildLongString(args, 4, false);\n        boolean onlyOnline = Boolean.parseBoolean(args[3]);\n\n        islands.forEach(island -> island.executeCommand(command, onlyOnline));\n\n        if (targetPlayer == null)\n            Message.GLOBAL_COMMAND_EXECUTED_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : \"all\");\n        else\n            Message.GLOBAL_COMMAND_EXECUTED.send(sender, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"true\", \"false\") : null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.Material;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class CmdAdminCount implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"count\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.count\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin count <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> [\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_MATERIALS.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_COUNT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        if (args.length == 3) {\n            if (!(sender instanceof Player)) {\n                Message.CUSTOM.send(sender, \"&cYou must be a player in order to open the counts menu.\", true);\n                return;\n            }\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n            plugin.getMenus().openCounts(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n            return;\n        }\n\n        String materialName = args[3].toUpperCase(Locale.ENGLISH);\n\n        if (materialName.equals(\"*\")) {\n            StringBuilder materialsBuilder = new StringBuilder();\n\n            java.util.Locale locale = PlayerLocales.getLocale(sender);\n\n            if (!Message.BLOCK_COUNTS_CHECK_MATERIAL.isEmpty(locale)) {\n                for (Map.Entry<Key, BigInteger> entry : island.getBlockCountsAsBigInteger().entrySet()) {\n                    materialsBuilder.append(\", \").append(Message.BLOCK_COUNTS_CHECK_MATERIAL\n                            .getMessage(locale, Formatters.NUMBER_FORMATTER.format(entry.getValue()),\n                                    Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().toString())));\n                }\n            }\n\n            if (materialsBuilder.length() == 0) {\n                Message.BLOCK_COUNTS_CHECK_EMPTY.send(sender);\n            } else {\n                Message.BLOCK_COUNTS_CHECK.send(sender, materialsBuilder.substring(1));\n            }\n        } else {\n            Material material = CommandArguments.getMaterial(sender, materialName);\n\n            if (material == null)\n                return;\n\n            BigInteger blockCount = island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(materialName));\n\n            if (blockCount.compareTo(BigInteger.ONE) > 0)\n                materialName = materialName + \"s\";\n\n            Message.BLOCK_COUNT_CHECK.send(sender, Formatters.NUMBER_FORMATTER.format(blockCount),\n                    Formatters.CAPITALIZED_FORMATTER.format(materialName));\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        if (args.length != 4)\n            return Collections.emptyList();\n\n        List<String> list = new LinkedList<>(CommandTabCompletes.getMaterials(args[3]));\n\n        if (\"*\".contains(args[3]))\n            list.add(\"*\");\n\n        return Collections.unmodifiableList(list);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.PersistentDataSerializer;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.google.common.collect.ImmutableMap;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class CmdAdminData implements ISuperiorCommand {\n\n    private static final Map<String, SubCommand> subCommands = new ImmutableMap.Builder<String, SubCommand>()\n            .put(\"set\", new SetSubCommand())\n            .put(\"get\", new GetSubCommand())\n            .put(\"remove\", new RemoveSubCommand())\n            .build();\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"data\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.data\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin data <get/set/remove> <player/island> <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DATA.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH));\n\n        if (subCommand == null) {\n            Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(PlayerLocales.getLocale(sender)));\n            return;\n        }\n\n        if (args.length < subCommand.getMinArgs() || args.length > subCommand.getMaxArgs()) {\n            Locale senderLocale = PlayerLocales.getLocale(sender);\n            Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(senderLocale) + subCommand.getUsage(senderLocale));\n            return;\n        }\n\n        IPersistentDataHolder persistentDataHolder;\n\n        if (args[3].equalsIgnoreCase(\"island\")) {\n            IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[4]);\n            persistentDataHolder = arguments.getIsland();\n        } else if (args[3].equalsIgnoreCase(\"player\")) {\n            persistentDataHolder = CommandArguments.getPlayer(plugin, sender, args[4]);\n        } else {\n            Locale senderLocale = PlayerLocales.getLocale(sender);\n            Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(senderLocale) + subCommand.getUsage(senderLocale));\n            return;\n        }\n\n        if (persistentDataHolder != null)\n            subCommand.execute(plugin, sender, persistentDataHolder, args);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        switch (args.length) {\n            case 3:\n                return CommandTabCompletes.getCustomComplete(args[2], \"get\", \"set\", \"remove\");\n            case 4: {\n                SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH));\n                return subCommand == null ? Collections.emptyList() :\n                        CommandTabCompletes.getCustomComplete(args[3], \"island\", \"player\");\n            }\n            case 5: {\n                SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH));\n                if (subCommand != null && args[3].equalsIgnoreCase(\"island\"))\n                    return CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[4], false, null);\n                else if (subCommand != null && args[3].equalsIgnoreCase(\"player\"))\n                    CommandTabCompletes.getOnlinePlayers(plugin, args[4], false);\n                else\n                    return Collections.emptyList();\n            }\n            default: {\n                return Collections.emptyList();\n            }\n        }\n    }\n\n    interface SubCommand {\n\n        String getUsage(Locale locale);\n\n        int getMinArgs();\n\n        int getMaxArgs();\n\n        void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder,\n                     String[] args);\n\n    }\n\n    private static class GetSubCommand implements SubCommand {\n\n        @Override\n        public String getUsage(Locale locale) {\n            return \" [\" + Message.COMMAND_ARGUMENT_PATH.getMessage(locale) + \"]\";\n        }\n\n        @Override\n        public int getMinArgs() {\n            return 5;\n        }\n\n        @Override\n        public int getMaxArgs() {\n            return 6;\n        }\n\n        @Override\n        public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) {\n            if (persistentDataHolder.isPersistentDataContainerEmpty()) {\n                Message.PERSISTENT_DATA_EMPTY.send(sender);\n                return;\n            }\n\n            Locale locale = PlayerLocales.getLocale(sender);\n\n            PersistentDataSerializer serializer = new PersistentDataSerializer(locale);\n\n            PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer();\n\n            String serializedValue;\n\n            if (args.length == 6) {\n                if (!dataContainer.has(args[5])) {\n                    Message.PERSISTENT_DATA_EMPTY.send(sender);\n                    return;\n                }\n\n                serializedValue = serializer.serialize(dataContainer.get(args[5]));\n            } else {\n                if (dataContainer.isEmpty()) {\n                    Message.PERSISTENT_DATA_EMPTY.send(sender);\n                    return;\n                }\n\n                StringBuilder dataMessageBuilder = new StringBuilder();\n\n                dataContainer.forEach((key, value) -> {\n                    String valueSerialized = serializer.serialize(value);\n\n                    if (valueSerialized.isEmpty())\n                        return;\n\n                    if (dataMessageBuilder.length() != 0)\n                        dataMessageBuilder.append(Message.PERSISTENT_DATA_SHOW_SPACER.getMessage(locale));\n\n                    dataMessageBuilder.append(Message.PERSISTENT_DATA_SHOW_PATH.getMessage(locale, key)).append(valueSerialized);\n                });\n\n                if (dataMessageBuilder.length() < 2) {\n                    Message.PERSISTENT_DATA_EMPTY.send(sender);\n                    return;\n                }\n\n                serializedValue = dataMessageBuilder.toString();\n            }\n\n            Message.PERSISTENT_DATA_SHOW.send(sender, args[4], serializedValue);\n        }\n\n    }\n\n    private static class SetSubCommand implements SubCommand {\n\n        @Override\n        public String getUsage(Locale locale) {\n            return \" <path> <value...>\";\n        }\n\n        @Override\n        public int getMinArgs() {\n            return 7;\n        }\n\n        @Override\n        public int getMaxArgs() {\n            return Integer.MAX_VALUE;\n        }\n\n        @Override\n        public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) {\n            PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer();\n\n            PersistentDataSerializer serializer = new PersistentDataSerializer(PlayerLocales.getLocale(sender));\n\n            String path = args[5];\n\n            // noinspection unchecked\n            Pair<Object, PersistentDataType<Object>> value = (Pair<Object, PersistentDataType<Object>>)\n                    serializer.deserialize(String.join(\" \", Arrays.copyOfRange(args, 6, args.length)));\n\n            assert value != null;\n\n            dataContainer.remove(path);\n            Object oldValue = dataContainer.put(path, value.getValue(), value.getKey());\n\n            if (!value.getKey().equals(oldValue))\n                persistentDataHolder.savePersistentDataContainer();\n\n            Message.PERSISTENT_DATA_MODIFY.send(sender, args[4], path,\n                    serializer.serialize(value.getKey()));\n        }\n\n    }\n\n    private static class RemoveSubCommand implements SubCommand {\n\n        @Override\n        public String getUsage(Locale locale) {\n            return \" <path>\";\n        }\n\n        @Override\n        public int getMinArgs() {\n            return 6;\n        }\n\n        @Override\n        public int getMaxArgs() {\n            return 6;\n        }\n\n        @Override\n        public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) {\n            if (persistentDataHolder.isPersistentDataContainerEmpty()) {\n                Message.PERSISTENT_DATA_EMPTY.send(sender);\n                return;\n            }\n\n            PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer();\n\n            if (!dataContainer.has(args[5])) {\n                Message.PERSISTENT_DATA_EMPTY.send(sender);\n                return;\n            }\n\n            Object oldValue = dataContainer.remove(args[5]);\n\n            if (oldValue != null)\n                persistentDataHolder.savePersistentDataContainer();\n\n            Message.PERSISTENT_DATA_REMOVED.send(sender, args[4], args[5]);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDebug.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdminDebug implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"debug\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.debug\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin debug [filter]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DEBUG.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean displayCommand() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        boolean originalDebugMode = Log.isDebugMode();\n        Debug debugFilter;\n\n        if (args.length == 2) {\n            if (originalDebugMode) {\n                debugFilter = null;\n            } else {\n                Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(PlayerLocales.getLocale(sender)));\n                return;\n            }\n        } else {\n            debugFilter = EnumHelper.getEnum(Debug.class, args[2].toUpperCase(Locale.ENGLISH));\n        }\n\n        boolean newDebugMode = debugFilter != null;\n\n        if (originalDebugMode != newDebugMode) {\n            Log.toggleDebugMode();\n            if (newDebugMode) {\n                Message.DEBUG_MODE_ENABLED.send(sender);\n            } else {\n                Message.DEBUG_MODE_DISABLED.send(sender);\n            }\n        }\n\n        if (debugFilter != null) {\n            if (Log.isDebugged(debugFilter)) {\n                Message.DEBUG_MODE_FILTER_REMOVE.send(sender, Formatters.CAPITALIZED_FORMATTER.format(debugFilter.name()));\n            } else {\n                Message.DEBUG_MODE_FILTER_ADD.send(sender, Formatters.CAPITALIZED_FORMATTER.format(debugFilter.name()));\n            }\n        } else {\n            Message.DEBUG_MODE_FILTER_CLEAR.send(sender);\n        }\n\n        Log.setDebugFilter(debugFilter);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length <= 2 ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[2], Debug.getDebugNames());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.warp.SignWarp;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminDelWarp implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"delwarp\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.delwarp\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin delwarp <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + \"...>\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DEL_WARP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        IslandWarp islandWarp = CommandArguments.getWarp(sender, island, args, 3);\n\n        if (islandWarp == null)\n            return;\n\n        if (!PluginEventsFactory.callIslandDeleteWarpEvent(islandWarp.getIsland(), sender, islandWarp))\n            return;\n\n        island.deleteWarp(islandWarp.getName());\n        Message.DELETE_WARP.send(sender, islandWarp.getName());\n\n        SignWarp.trySignWarpBreak(islandWarp, sender);\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getIslandWarps(island, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminDemote implements IAdminPlayerCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"demote\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.demote\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin demote <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DEMOTE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        Island island = targetPlayer.getIsland();\n\n        if (island == null) {\n            Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n            return;\n        }\n\n        PlayerRole currentRole = targetPlayer.getPlayerRole();\n\n        if (currentRole.isLastRole()) {\n            Message.DEMOTE_LEADER.send(sender);\n            return;\n        }\n\n        PlayerRole previousRole = currentRole;\n        int roleLimit;\n\n        do {\n            previousRole = previousRole.getPreviousRole();\n            roleLimit = previousRole == null ? -1 : island.getRoleLimit(previousRole);\n        } while (previousRole != null && !previousRole.isFirstRole() && roleLimit >= 0 && roleLimit >= island.getIslandMembers(previousRole).size());\n\n        if (previousRole == null) {\n            Message.LAST_ROLE_DEMOTE.send(sender);\n            return;\n        }\n\n        if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole))\n            return;\n\n        targetPlayer.setPlayerRole(previousRole);\n\n        Message.DEMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole());\n        Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false,\n                superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) &&\n                        !superiorPlayer.getPlayerRole().isFirstRole()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminDisband implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"disband\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.disband\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin disband <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DISBAND.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        if (!PluginEventsFactory.callIslandDisbandEvent(island, targetPlayer))\n            return;\n\n        IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), sender.getName());\n\n        if (targetPlayer == null)\n            Message.DISBANDED_ISLAND_OTHER_NAME.send(sender, island.getName());\n        else\n            Message.DISBANDED_ISLAND_OTHER.send(sender, targetPlayer.getName());\n\n        if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) {\n            BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund();\n            Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(),\n                    Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance().multiply(disbandRefund)));\n        }\n\n        island.disbandIsland();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminFly implements IAdminPlayerCommand {\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"fly\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.fly\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin fly <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> [flying[true/false]]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_FLY.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        if (args.length == 4) {\n            boolean enableFlying = Boolean.parseBoolean(args[3]);\n\n            if (enableFlying == targetPlayer.hasIslandFlyEnabled()) {\n                // Nothing changes, let's just send message to sender and return\n                if (enableFlying) {\n                    Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName());\n                } else {\n                    Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName());\n                }\n                return;\n            }\n        }\n\n        if (!PluginEventsFactory.callPlayerToggleFlyEvent(targetPlayer))\n            return;\n\n        if (targetPlayer.hasIslandFlyEnabled()) {\n            targetPlayer.runIfOnline(player -> {\n                player.setAllowFlight(false);\n                player.setFlying(false);\n            });\n\n            Message.TOGGLED_FLY_OFF.send(targetPlayer);\n            Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName());\n        } else {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(targetPlayer.getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null && island.hasPermission(targetPlayer, IslandPrivileges.FLY)) {\n                targetPlayer.runIfOnline(player -> {\n                    player.setAllowFlight(true);\n                    player.setFlying(true);\n                });\n            }\n\n            Message.TOGGLED_FLY_ON.send(targetPlayer);\n            Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName());\n        }\n\n        targetPlayer.toggleIslandFly();\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"true\", \"false\") : null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminIgnore.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminIgnore implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"ignore\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.ignore\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin ignore <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_IGNORE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        island.setIgnored(true);\n\n        if (targetPlayer == null)\n            Message.IGNORED_ISLAND_NAME.send(sender, island.getName());\n        else\n            Message.IGNORED_ISLAND.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminJoin implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"join\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.join\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin join <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_JOIN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (superiorPlayer.getIsland() != null) {\n            Message.ALREADY_IN_ISLAND.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.ADMIN))\n            return;\n\n        IslandUtils.sendMessage(island, Message.JOIN_ADMIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName());\n\n        island.addMember(superiorPlayer, SPlayerRole.defaultRole());\n\n        if (targetPlayer == null)\n            Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName());\n        else\n            Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminKick implements IAdminPlayerCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"kick\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.kick\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin kick <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_KICK.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        Island targetIsland = targetPlayer.getIsland();\n\n        if (targetIsland == null) {\n            Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n            return;\n        }\n\n        if (targetIsland.getOwner() == targetPlayer) {\n            Message.KICK_ISLAND_LEADER.send(sender);\n            return;\n        }\n\n        IslandUtils.handleKickPlayer(sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null,\n                sender.getName(), targetIsland, targetPlayer);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false,\n                superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer)) :\n                Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminModules.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdminModules implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"modules\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.modules\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin modules [<\" + Message.COMMAND_ARGUMENT_MODULE_NAME.getMessage(locale) + \"> [load/unload]]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_MODULES.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args.length == 2) {\n            StringBuilder modulesList = new StringBuilder();\n            java.util.Locale senderLocale = PlayerLocales.getLocale(sender);\n            String moduleSeparator = Message.MODULES_LIST_SEPARATOR.getMessage(senderLocale);\n\n            for (PluginModule pluginModule : plugin.getModules().getModules()) {\n                modulesList.append(moduleSeparator).append(Message.MODULES_LIST_MODULE_NAME\n                        .getMessage(senderLocale, pluginModule.getName(), pluginModule.getAuthor()));\n            }\n\n            Message.MODULES_LIST.send(sender, plugin.getModules().getModules().size(), modulesList.substring(moduleSeparator.length()));\n        } else {\n            PluginModule pluginModule = plugin.getModules().getModule(args[2]);\n\n            if (args.length == 3) {\n                if (pluginModule == null) {\n                    Message.INVALID_MODULE.send(sender, args[2]);\n                    return;\n                }\n\n                Message.MODULE_INFO.send(sender, pluginModule.getName(), pluginModule.getAuthor(), \"\");\n            } else {\n                String command = args[3].toLowerCase(Locale.ENGLISH);\n\n                switch (command) {\n                    case \"load\":\n                        pluginModule = BuiltinModules.getBuiltinModule(args[2]);\n\n                        if (pluginModule == null) {\n                            File moduleFile = new File(plugin.getDataFolder(), \"modules/\" + args[2] + \".jar\");\n                            try {\n                                pluginModule = plugin.getModules().registerModule(moduleFile);\n                            } catch (Exception error) {\n                                Log.error(error, \"An unexpected error occurred while loading the module \", args[2], \":\");\n                                Message.MODULE_LOADED_FAILURE.send(sender, args[2]);\n                                return;\n                            }\n                        } else {\n                            if (pluginModule.isInitialized()) {\n                                Message.MODULE_ALREADY_INITIALIZED.send(sender);\n                                return;\n                            }\n\n                            plugin.getModules().registerModule(pluginModule);\n                        }\n\n                        plugin.getModules().enableModule(pluginModule);\n                        Message.MODULE_LOADED_SUCCESS.send(sender, pluginModule.getName());\n\n                        break;\n                    case \"unload\":\n                        if (pluginModule == null) {\n                            Message.INVALID_MODULE.send(sender, args[2]);\n                            return;\n                        }\n\n                        plugin.getModules().unregisterModule(pluginModule);\n\n                        Message.MODULE_UNLOADED_SUCCESS.send(sender);\n                        break;\n                    default:\n                        Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(PlayerLocales.getLocale(sender)));\n                        break;\n                }\n            }\n        }\n\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length != 3 ? Collections.emptyList() : CommandTabCompletes.getModules(plugin, args[2]);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminMsg implements IAdminPlayerCommand {\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"msg\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.msg\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin msg <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_MSG.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        String message = CommandArguments.buildLongString(args, 3, true);\n        if (!Text.isBlank(message))\n            message = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), message);\n        Message.CUSTOM.send(targetPlayer, message, false);\n        Message.MESSAGE_SENT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsgAll.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminMsgAll implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"msgall\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.msgall\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin msgall <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_MSG_ALL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        String message = CommandArguments.buildLongString(args, 3, true);\n\n        islands.forEach(island -> island.sendMessage(message));\n\n        if (targetPlayer == null)\n            Message.GLOBAL_MESSAGE_SENT_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : \"all\");\n        else\n            Message.GLOBAL_MESSAGE_SENT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandNames;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdAdminName implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"name\", \"setname\", \"rename\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.name\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin name <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_NAME.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        PluginEvent<PluginEventArgs.IslandRename> event = PluginEventsFactory.callIslandRenameEvent(island, sender, args[3]);\n\n        if (event.isCancelled())\n            return;\n\n        String islandName = event.getArgs().islandName;\n\n        if (!IslandNames.isValidName(sender, island, islandName))\n            return;\n\n        String oldName = island.getName();\n        island.setName(islandName);\n\n        String coloredName = island.getName();\n\n        if (targetPlayer == null) {\n            IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER_NAME, sender.getName(), oldName, coloredName);\n            Message.CHANGED_NAME_OTHER_NAME.send(sender, oldName, coloredName);\n        } else {\n            IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER, sender.getName(), targetPlayer.getName(), coloredName);\n            Message.CHANGED_NAME_OTHER.send(sender, targetPlayer.getName(), coloredName);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminOpen implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"open\", \"unlock\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.open\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin open <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_OPEN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        if (!island.isLocked()) {\n            Message.ISLAND_ALREADY_OPENED.send(sender);\n        } else if (PluginEventsFactory.callIslandOpenEvent(island, sender)) {\n            island.setLocked(false);\n            Message.ISLAND_OPENED.send(sender);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false,\n                (superiorPlayer, island) -> island.isLocked()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminOpenMenu implements IAdminPlayerCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"openmenu\", \"menu\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.openmenu\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin openmenu <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MENU.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_OPEN_MENU.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        String menuIdentifier = MenuIdentifiers.MENU_CUSTOM_PREFIX + args[3];\n\n        Menu<BaseMenuView, EmptyViewArgs> menu = plugin.getMenus().getMenu(menuIdentifier);\n\n        if (!(menu instanceof MenuCustom)) {\n            Message.INVALID_MENU.send(sender, menuIdentifier);\n            return;\n        }\n\n        menu.createView(targetPlayer, EmptyViewArgs.INSTANCE);\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomMenus(plugin, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminPromote implements IAdminPlayerCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"promote\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.promote\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin promote <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_PROMOTE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public boolean requireIsland() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        Island island = targetPlayer.getIsland();\n\n        if (island == null) {\n            Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n            return;\n        }\n\n        PlayerRole currentRole = targetPlayer.getPlayerRole();\n\n        if (currentRole.isLastRole()) {\n            Message.LAST_ROLE_PROMOTE.send(sender);\n            return;\n        }\n\n        PlayerRole nextRole = currentRole;\n        int roleLimit;\n\n\n        do {\n            nextRole = nextRole.getNextRole();\n            roleLimit = nextRole == null ? -1 : island.getRoleLimit(nextRole);\n        } while (nextRole != null && !nextRole.isLastRole() &&\n                roleLimit >= 0 && island.getIslandMembers(nextRole).size() >= roleLimit);\n\n        if (nextRole == null || nextRole.isLastRole()) {\n            Message.LAST_ROLE_PROMOTE.send(sender);\n            return;\n        }\n\n        if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole))\n            return;\n\n        targetPlayer.setPlayerRole(nextRole);\n\n        Message.PROMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole());\n        Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false,\n                superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) &&\n                        !superiorPlayer.getPlayerRole().getNextRole().isLastRole()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPurge.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminPurge implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"purge\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.purge\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin purge <cancel/\" + Message.COMMAND_ARGUMENT_TIME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_PURGE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args[2].equalsIgnoreCase(\"cancel\")) {\n            plugin.getGrid().getIslandsToPurge().forEach(island -> plugin.getGrid().removeIslandFromPurge(island));\n            Message.PURGE_CLEAR.send(sender);\n        } else {\n            long timeToPurge = parseLongSafe(args[2]);\n            long currentTime = System.currentTimeMillis() / 1000;\n\n            List<Island> islands = new SequentialListBuilder<Island>().filter(island -> {\n                long lastTimeUpdate = island.getLastTimeUpdate();\n                return lastTimeUpdate != -1 && currentTime - lastTimeUpdate >= timeToPurge;\n            }).build(plugin.getGrid().getIslands());\n\n            if (islands.isEmpty()) {\n                Message.NO_ISLANDS_TO_PURGE.send(sender);\n            } else {\n                BukkitExecutor.async(() -> islands.forEach(island -> plugin.getGrid().addIslandToPurge(island)));\n                Message.PURGED_ISLANDS.send(sender, islands.size());\n            }\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getCustomComplete(args[2], \"cancel\") : Collections.emptyList();\n    }\n\n    private static long parseLongSafe(String value) {\n        try {\n            return Long.parseLong(value);\n        } catch (Exception error) {\n            return 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRecalc.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdAdminRecalc implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"recalc\", \"recalculate\", \"level\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.recalc\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin recalc <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RECALC.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        if (islands.size() > 1) {\n            Message.RECALC_ALL_ISLANDS.send(sender);\n            plugin.getGrid().calcAllIslands(() -> Message.RECALC_ALL_ISLANDS_DONE.send(sender));\n        } else {\n            Island island = islands.get(0);\n\n            if (island.isBeingRecalculated()) {\n                Message.RECALC_ALREADY_RUNNING_OTHER.send(sender);\n                return;\n            }\n\n            Message.RECALC_PROCCESS_REQUEST.send(sender);\n            island.calcIslandWorth(sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminReload.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.PluginReloadReason;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminReload implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"reload\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.reload\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin reload\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RELOAD.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Message.RELOAD_PROCCESS_REQUEST.send(sender);\n\n        try {\n            plugin.reloadPlugin(PluginReloadReason.COMMAND);\n        } catch (ManagerLoadException error) {\n            Log.error(error, \"An unexpected error occurred while reloading the plugin:\");\n            if (!ManagerLoadException.handle(error))\n                return;\n        }\n\n        Message.RELOAD_COMPLETED.send(sender);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\npublic class CmdAdminRemoveRatings implements IAdminIslandCommand {\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"removeratings\", \"rratings\", \"rr\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.removeratings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin removeratings <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        boolean removingAllRatings = targetPlayer == null;\n        Collection<Island> iterIslands = removingAllRatings ? islands : plugin.getGrid().getIslands();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : iterIslands) {\n            if (removingAllRatings) {\n                if (PluginEventsFactory.callIslandClearRatingsEvent(island, sender)) {\n                    ++islandsChangedCount;\n                    island.removeRatings();\n                }\n            } else if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, targetPlayer)) {\n                ++islandsChangedCount;\n                island.removeRating(targetPlayer);\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (!removingAllRatings)\n            Message.RATE_REMOVE_ALL.send(sender, targetPlayer.getName());\n        else if (islands.size() == 1)\n            Message.RATE_REMOVE_ALL.send(sender, islands.get(0).getName());\n        else\n            Message.RATE_REMOVE_ALL_ISLANDS.send(sender);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminResetPermissions implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"resetpermissions\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.resetpermissions\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin resetpermissions <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, sender)) {\n                ++islandsChangedCount;\n                island.resetPermissions();\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.PERMISSIONS_RESET_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.PERMISSIONS_RESET_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.PERMISSIONS_RESET.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminResetSettings implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"resetsettings\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.resetsettings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin resetsettings <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (PluginEventsFactory.callIslandClearFlagsEvent(island, sender)) {\n                ++islandsChangedCount;\n                island.resetSettings();\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.SETTINGS_RESET_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.SETTINGS_RESET_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.SETTINGS_RESET.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdminResetWorld implements IAdminIslandCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final LazyReference<DragonBattleService> dragonBattleService = new LazyReference<DragonBattleService>() {\n        @Override\n        protected DragonBattleService create() {\n            return plugin.getServices().getService(DragonBattleService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"resetworld\", \"rworld\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.resetworld\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin resetworld <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RESET_WORLD.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Dimension dimension = CommandArguments.getDimension(sender, args[3]);\n\n        if (dimension == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (!PluginEventsFactory.callIslandWorldResetEvent(island, sender, dimension))\n                continue;\n\n            ++islandsChangedCount;\n\n            IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n                islandWorldResult.ifLeft(world -> resetChunksInternal(island, world, dimension));\n            });\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.RESET_WORLD_SUCCEED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]));\n        else if (targetPlayer == null)\n            Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0).getName());\n        else\n            Message.RESET_WORLD_SUCCEED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), targetPlayer.getName());\n    }\n\n    private static void resetChunksInternal(Island island, World world, Dimension dimension) {\n        boolean isDefaultDimension = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension();\n\n        try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) {\n            // Sending the players that are in that world to the main island.\n            // If the world that will be reset is the normal world, they will be teleported to spawn.\n            Island teleportIsland = isDefaultDimension ? plugin.getGrid().getSpawnIsland() : island;\n            for (SuperiorPlayer superiorPlayer : strategy.getSuperiorPlayers(WorldInfo.of(world))) {\n                superiorPlayer.teleport(teleportIsland);\n            }\n        }\n\n        // Resetting the chunks\n        island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED,\n                isDefaultDimension ? null : () -> island.calcIslandWorth(null));\n\n        if (isDefaultDimension) {\n            String islandSchematic = island.getSchematicName();\n            Schematic schematic = plugin.getSchematics().getSchematic(islandSchematic);\n            if (schematic != null) {\n                regenerateSchematicInternal(island, dimension, schematic);\n                return;\n            }\n        }\n\n        island.setSchematicGenerate(dimension, false);\n    }\n\n    private static void regenerateSchematicInternal(Island island, Dimension dimension, Schematic schematic) {\n        Location centerLocation = island.getCenter(dimension);\n        Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation();\n\n        schematic.pasteSchematic(island, schematicPlacementLocation, () -> {\n            island.setSchematicGenerate(dimension);\n\n            Location homeLocation = schematic.adjustRotation(centerLocation);\n            island.setIslandHome(homeLocation);\n\n            if (dimension.getEnvironment() == World.Environment.THE_END) {\n                dragonBattleService.get().resetEnderDragonBattle(island, dimension);\n            }\n\n            island.calcIslandWorth(null);\n        }, Throwable::printStackTrace);\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSchematic implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"schematic\", \"schem\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.schematic\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin schematic [\" +\n                Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + \"] [\" +\n                Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + \"[true/false]]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SCHEMATIC.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (args.length == 2) {\n            if (superiorPlayer.hasSchematicModeEnabled()) {\n                Message.TOGGLED_SCHEMATIC_OFF.send(superiorPlayer);\n            } else {\n                Message.TOGGLED_SCHEMATIC_ON.send(superiorPlayer);\n            }\n\n            superiorPlayer.toggleSchematicMode();\n        } else {\n            if (superiorPlayer.getSchematicPos1() == null || superiorPlayer.getSchematicPos2() == null) {\n                Message.SCHEMATIC_NOT_READY.send(superiorPlayer);\n                return;\n            }\n\n            String schematicName = args[2];\n            boolean saveAir = args.length == 4 && Boolean.parseBoolean(args[3]);\n\n            Message.SCHEMATIC_PROCCESS_REQUEST.send(superiorPlayer);\n            plugin.getSchematics().saveSchematic(superiorPlayer, schematicName, saveAir);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"true\", \"false\") :\n                Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.block.Biome;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetBiome implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setbiome\", \"biome\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setbiome\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setbiome <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_BIOME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_BIOME.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Biome biome = CommandArguments.getBiome(plugin, sender, args[3]);\n\n        if (biome == null)\n            return;\n\n        islands.forEach(island -> island.setBiome(biome));\n\n        if (islands.size() > 1)\n            Message.CHANGED_BIOME_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name()));\n        else if (targetPlayer == null)\n            Message.CHANGED_BIOME_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name()), islands.get(0).getName());\n        else\n            Message.CHANGED_BIOME_OTHER.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getBiomes(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class CmdAdminSetBlockAmount implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setblockamount\", \"setblocksize\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setblockamount\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setblockamount <\" +\n                Message.COMMAND_ARGUMENT_WORLD.getMessage(locale) + \"> <x> <y> <z> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 7;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 7;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        World world = CommandArguments.getWorld(sender, args[2]);\n\n        if (world == null)\n            return;\n\n        Location location = CommandArguments.getLocation(sender, world, args[3], args[4], args[5]);\n\n        if (location == null)\n            return;\n\n        NumberArgument<Integer> arguments = CommandArguments.getAmount(sender, args[6]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int amount = arguments.getNumber();\n\n        plugin.getStackedBlocks().setStackedBlock(location.getBlock(), amount);\n\n        String formattedLocation = args[2] + \", \" + args[3] + \", \" + args[4] + \", \" + args[5];\n        Message.CHANGED_BLOCK_AMOUNT.send(sender, formattedLocation, amount);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        List<String> list = new LinkedList<>();\n\n        if (args.length == 3) {\n            list = CommandTabCompletes.getWorlds(args[2]);\n        } else if (sender instanceof Player) {\n            String blockX;\n            String blockY;\n            String blockZ;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location location = ((Player) sender).getLocation(wrapper.getHandle());\n                blockX = String.valueOf(location.getBlockX());\n                blockY = String.valueOf(location.getBlockY());\n                blockZ = String.valueOf(location.getBlockZ());\n            }\n            if (args.length == 4) {\n                if (blockX.contains(args[3]))\n                    list.add(blockX);\n            } else if (args.length == 5) {\n                if (blockY.contains(args[4]))\n                    list.add(blockY);\n\n            } else if (args.length == 6) {\n                if (blockZ.contains(args[5]))\n                    list.add(blockZ);\n            }\n        }\n\n        return Collections.unmodifiableList(list);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdminSetBonus implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setbonus\", \"bonus\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.bonus\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setbonus <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <worth/level> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_BONUS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        boolean isWorthBonus;\n\n        if (args[3].equalsIgnoreCase(\"worth\")) {\n            isWorthBonus = true;\n        } else if (args[3].equalsIgnoreCase(\"level\")) {\n            isWorthBonus = false;\n        } else {\n            Locale locale = PlayerLocales.getLocale(sender);\n            Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + \" \" + getUsage(locale));\n            return;\n        }\n\n        BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]);\n\n        if (bonus == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (isWorthBonus) {\n                PluginEvent<PluginEventArgs.IslandChangeWorthBonus> event = PluginEventsFactory.callIslandChangeWorthBonusEvent(\n                        island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, bonus);\n                if (!event.isCancelled()) {\n                    island.setBonusWorth(event.getArgs().worthBonus);\n                    ++islandsChangedCount;\n                }\n            } else {\n                PluginEvent<PluginEventArgs.IslandChangeLevelBonus> event = PluginEventsFactory.callIslandChangeLevelBonusEvent(\n                        island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, bonus);\n                if (!event.isCancelled()) {\n                    island.setBonusLevel(event.getArgs().levelBonus);\n                    ++islandsChangedCount;\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (isWorthBonus) {\n            if (islandsChangedCount > 1)\n                Message.CHANGED_BONUS_WORTH_ALL.send(sender);\n            else if (targetPlayer == null)\n                Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName());\n            else\n                Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName());\n        } else {\n            if (islandsChangedCount > 1)\n                Message.CHANGED_BONUS_LEVEL_ALL.send(sender);\n            else if (targetPlayer == null)\n                Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName());\n            else\n                Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName());\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"worth\", \"level\") : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetChestRow.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.IntStream;\n\npublic class CmdAdminSetChestRow implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setchestrow\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setchestrow\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setchestrow <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ROWS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> pageArguments = CommandArguments.getPage(sender, args[3]);\n\n        if (!pageArguments.isSucceed())\n            return;\n\n        int page = pageArguments.getNumber();\n\n        NumberArgument<Integer> rowsArguments = CommandArguments.getRows(sender, args[4]);\n\n        if (!rowsArguments.isSucceed())\n            return;\n\n        int rows = rowsArguments.getNumber();\n\n        if (rows < 1 || rows > 6) {\n            Message.INVALID_ROWS.send(sender, args[4]);\n            return;\n        }\n\n        islands.forEach(island -> island.setChestRows(page - 1, rows));\n\n        if (islands.size() > 1)\n            Message.CHANGED_CHEST_SIZE_ALL.send(sender, page, rows);\n        else if (targetPlayer == null)\n            Message.CHANGED_CHEST_SIZE_NAME.send(sender, page, rows, islands.get(0).getName());\n        else\n            Message.CHANGED_CHEST_SIZE.send(sender, page, rows, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 && island != null ?\n                CommandTabCompletes.getCustomComplete(args[3], IntStream.range(1, island.getChestSize() + 1)) :\n                args.length == 5 && island != null ?\n                        CommandTabCompletes.getCustomComplete(args[4], IntStream.range(1, 7)) :\n                        Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetCoopLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setcooplimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setcooplimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setcooplimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeCoopLimit> event = PluginEventsFactory.callIslandChangeCoopLimitEvent(\n                    island, sender, island.getCoopLimit() + limit);\n            if (!event.isCancelled()) {\n                island.setCoopLimit(event.getArgs().coopLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_COOP_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_COOP_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetDisbands.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetDisbands implements IAdminPlayerCommand {\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setdisbands\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setdisbands\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setdisbands <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_PLAYERS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List<SuperiorPlayer> targetPlayers, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int amount = arguments.getNumber();\n\n        targetPlayers.forEach(superiorPlayer -> superiorPlayer.setDisbands(amount));\n\n        if (targetPlayers.size() > 1) {\n            Message.DISBAND_SET_ALL.send(sender, amount);\n        } else if (!sender.equals(targetPlayers.get(0).asPlayer()))\n            Message.DISBAND_SET_OTHER.send(sender, targetPlayers.get(0).getName(), amount);\n\n        targetPlayers.forEach(superiorPlayer -> Message.DISBAND_SET.send(superiorPlayer, amount));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetIslandPreview implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setislandpreview\", \"setschematicpreview\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setislandpreview\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setislandpreview <\" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Schematic schematic = CommandArguments.getSchematic(plugin, sender, args[2]);\n\n        if (schematic == null)\n            return;\n\n        Player player = (Player) sender;\n\n        String schematicPreviewLocation;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = player.getLocation(wrapper.getHandle());\n            location.setX(location.getBlockX());\n            location.setY(location.getBlockY());\n            location.setZ(location.getBlockZ());\n            // Fix to corner of a block\n            location.add(0.5, 0, 0.5);\n            schematicPreviewLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location);\n        }\n\n        try {\n            plugin.getSettings().updateValue(\"island-previews.locations.\" + schematic.getName(), schematicPreviewLocation);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", schematicPreviewLocation);\n            Log.error(error, \"An unexpected error occurred while setting schematic preview:\");\n        }\n\n        Message.ISLAND_PREVIEW_SET.send(sender, schematic.getName(), schematicPreviewLocation);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getSchematics(plugin, args[2]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetLeader.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetLeader implements IAdminPlayerCommand {\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setleader\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setleader\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setleader <\" +\n                Message.COMMAND_ARGUMENT_LEADER.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_NEW_LEADER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_LEADER.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public boolean requireIsland() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer leader, String[] args) {\n        SuperiorPlayer newLeader = CommandArguments.getPlayer(plugin, sender, args[3]);\n\n        if (newLeader == null)\n            return;\n\n        Island island = leader.getIsland();\n\n        assert island != null; // requireIsland is true\n\n        if (!island.getOwner().getUniqueId().equals(leader.getUniqueId())) {\n            Message.TRANSFER_ADMIN_NOT_LEADER.send(sender);\n            return;\n        }\n\n        if (leader.getUniqueId().equals(newLeader.getUniqueId())) {\n            Message.TRANSFER_ADMIN_ALREADY_LEADER.send(sender, newLeader.getName());\n            return;\n        }\n\n        if (!island.isMember(newLeader)) {\n            Message.TRANSFER_ADMIN_DIFFERENT_ISLAND.send(sender);\n            return;\n        }\n\n        if (island.transferIsland(newLeader)) {\n            Message.TRANSFER_ADMIN.send(sender, leader.getName(), newLeader.getName());\n            IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), newLeader.getName());\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        Island playerIsland = targetPlayer.getIsland();\n        return args.length != 4 ? Collections.emptyList() : CommandTabCompletes.getOnlinePlayers(plugin, args[2], false, onlinePlayer -> {\n            Island onlineIsland = onlinePlayer.getIsland();\n            return !onlinePlayer.equals(targetPlayer) && onlineIsland != null && !onlineIsland.equals(playerIsland) &&\n                    onlineIsland.getOwner().equals(onlinePlayer);\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetPermission implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setpermission\", \"setperm\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setpermission\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setpermission <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_PERMISSION.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        IslandPrivilege islandPrivilege = CommandArguments.getIslandPrivilege(sender, args[3]);\n        if (islandPrivilege == null)\n            return;\n\n        PlayerRole playerRole = islandPrivilege.getType() == IslandPrivilege.Type.COMMAND ?\n                CommandArguments.getPlayerRoleFromLadder(sender, args[4]) : CommandArguments.getPlayerRole(sender, args[4]);\n        if (playerRole == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, sender, playerRole)) {\n                island.setPermission(playerRole, islandPrivilege);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.PERMISSION_CHANGED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()));\n        else if (targetPlayer == null)\n            Message.PERMISSION_CHANGED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()), islands.get(0).getName());\n        else\n            Message.PERMISSION_CHANGED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        switch (args.length) {\n            case 4:\n                return CommandTabCompletes.getIslandPrivileges(args[3]);\n            case 5: {\n                IslandPrivilege islandPrivilege = getIslandPrivilegeSafe(args[3]);\n\n                if (islandPrivilege == null)\n                    return Collections.emptyList();\n                else if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND)\n                    return CommandTabCompletes.getPlayerRoles(plugin, args[4], PlayerRole::isRoleLadder);\n                else\n                    return CommandTabCompletes.getPlayerRoles(plugin, args[4], null);\n            }\n            default:\n                return Collections.emptyList();\n        }\n    }\n\n    @Nullable\n    private static IslandPrivilege getIslandPrivilegeSafe(String name) {\n        try {\n            return IslandPrivilege.getByName(name);\n        } catch (NullPointerException error) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class CmdAdminSetRate implements IAdminIslandCommand {\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setrate\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setrate\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setrate <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_RATING.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_RATE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[3]);\n\n        if (targetPlayer == null)\n            return;\n\n        Rating rating = CommandArguments.getRating(sender, args[4]);\n\n        if (rating == null)\n            return;\n\n        if (rating == Rating.UNKNOWN) {\n            if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, superiorPlayer)) {\n                island.removeRating(targetPlayer);\n                Message.RATE_REMOVE_ALL.send(sender, targetPlayer.getName());\n            }\n        } else if (PluginEventsFactory.callIslandRateEvent(island, sender, superiorPlayer, rating)) {\n            island.setRating(targetPlayer, rating);\n            Message.RATE_CHANGE_OTHER.send(sender, targetPlayer.getName(), Formatters.CAPITALIZED_FORMATTER.format(rating.name()));\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        switch (args.length) {\n            case 4: {\n                List<String> tabCompletes = new LinkedList<>();\n                tabCompletes.addAll(CommandTabCompletes.getRatedPlayers(plugin, island, args[3]));\n                tabCompletes.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[3], false));\n                return tabCompletes.isEmpty() ? Collections.emptyList() : tabCompletes;\n            }\n            case 5:\n                return CommandTabCompletes.getRatings(args[4]);\n            default:\n                return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetRoleLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setrolelimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setrolelimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setrolelimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        PlayerRole playerRole = CommandArguments.getPlayerRoleForLimit(sender, args[3]);\n        if (playerRole == null)\n            return;\n\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (limit <= 0) {\n                if (PluginEventsFactory.callIslandRemoveRoleLimitEvent(island, sender, playerRole)) {\n                    ++islandsChangedCount;\n                    island.removeRoleLimit(playerRole);\n                }\n            } else {\n                PluginEvent<PluginEventArgs.IslandChangeRoleLimit> event = PluginEventsFactory.callIslandChangeRoleLimitEvent(\n                        island, sender, playerRole, limit);\n                if (!event.isCancelled()) {\n                    island.setRoleLimit(playerRole, event.getArgs().roleLimit);\n                    ++islandsChangedCount;\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ROLE_LIMIT_ALL.send(sender, playerRole);\n        else if (targetPlayer == null)\n            Message.CHANGED_ROLE_LIMIT_NAME.send(sender, playerRole, islands.get(0).getName());\n        else\n            Message.CHANGED_ROLE_LIMIT.send(sender, playerRole, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getPlayerRoles(plugin, args[3], IslandUtils::isValidRoleForLimit)\n                : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetSettings implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setsettings\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setsettings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setsettings <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_SETTINGS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        IslandFlag islandFlag = CommandArguments.getIslandFlag(sender, args[3]);\n\n        if (islandFlag == null)\n            return;\n\n        boolean value = args[4].equalsIgnoreCase(\"true\");\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (island.hasSettingsEnabled(islandFlag) == value) {\n                ++islandsChangedCount;\n                continue;\n            }\n\n            if (value) {\n                if (PluginEventsFactory.callIslandEnableFlagEvent(island, sender, islandFlag)) {\n                    ++islandsChangedCount;\n                    island.enableSettings(islandFlag);\n                }\n            } else if (PluginEventsFactory.callIslandDisableFlagEvent(island, sender, islandFlag)) {\n                ++islandsChangedCount;\n                island.disableSettings(islandFlag);\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.SETTINGS_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()));\n        else if (targetPlayer == null)\n            Message.SETTINGS_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()), islands.get(0).getName());\n        else\n            Message.SETTINGS_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getIslandFlags(args[3]) :\n                args.length == 5 ? CommandTabCompletes.getCustomComplete(args[4], \"true\", \"false\") :\n                        Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdAdminSetSize implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setsize\", \"setislandsize\", \"setbordersize\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setsize\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setsize <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_SIZE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_SIZE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getSize(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int size = arguments.getNumber();\n\n        if (size > plugin.getSettings().getMaxIslandSize()) {\n            Message.SIZE_BIGGER_MAX.send(sender);\n            return;\n        }\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBorderSize> event = PluginEventsFactory.callIslandChangeBorderSizeEvent(island, sender, size);\n            if (!event.isCancelled()) {\n                island.setIslandSize(event.getArgs().borderSize);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ISLAND_SIZE_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_ISLAND_SIZE.send(sender, targetPlayer.getName());\n\n        if (plugin.getSettings().isBuildOutsideIsland())\n            Message.CHANGED_ISLAND_SIZE_BUILD_OUTSIDE.send(sender);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetSpawn implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setspawn\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setspawn\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setspawn\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_SPAWN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Player player = (Player) sender;\n\n        String newSpawnLocation;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = player.getLocation(wrapper.getHandle());\n            location.setX(location.getBlockX());\n            location.setY(location.getBlockY());\n            location.setZ(location.getBlockZ());\n            // Fix to corner of a block\n            location.add(0.5, 0, 0.5);\n            newSpawnLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location);\n        }\n\n        try {\n            plugin.getSettings().updateValue(\"spawn.location\", newSpawnLocation);\n            plugin.getGrid().updateSpawn();\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", newSpawnLocation);\n            Log.error(error, \"An unexpected error occurred while setting spawn:\");\n        }\n\n        Message.SPAWN_SET_SUCCESS.send(sender, newSpawnLocation);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetTeamLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setteamlimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setteamlimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setteamlimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeMembersLimit> event = PluginEventsFactory.callIslandChangeMembersLimitEvent(island, sender, limit);\n            if (!event.isCancelled()) {\n                island.setTeamLimit(event.getArgs().membersLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_TEAM_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_TEAM_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetWarpsLimit implements IAdminIslandCommand {\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setwarpslimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setwarpslimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setwarpslimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        if (limit < 0) {\n            Message.INVALID_AMOUNT.send(sender);\n            return;\n        }\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeWarpsLimit> event = PluginEventsFactory.callIslandChangeWarpsLimitEvent(island, sender, limit);\n            if (!event.isCancelled()) {\n                island.setWarpsLimit(event.getArgs().warpsLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_WARPS_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_WARPS_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSettings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSettings implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"settings\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.settings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin settings\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SETTINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Menus.MENU_CONFIG_EDITOR.createView(plugin.getPlayers().getSuperiorPlayer(sender), MenuConfigEditor.Args.ROOT);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeBlockLimits;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeMobDrops;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\npublic class CmdAdminShow implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"show\", \"info\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.show\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin show [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SHOW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = args.length == 2 ? CommandArguments.getIslandWhereStanding(plugin, sender).getIsland() :\n                CommandArguments.getIsland(plugin, sender, args[2]).getIsland();\n\n        if (island == null)\n            return;\n\n        java.util.Locale locale = PlayerLocales.getLocale(sender);\n        long lastTime = island.getLastTimeUpdate();\n\n        StringBuilder infoMessage = new StringBuilder();\n\n        if (!Message.ISLAND_INFO_HEADER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_HEADER.getMessage(locale)).append(\"\\n\");\n\n        // Island owner\n        if (!Message.ISLAND_INFO_OWNER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_OWNER.getMessage(locale, island.getOwner().getName())).append(\"\\n\");\n\n        // Island name\n        if (!Message.ISLAND_INFO_NAME.isEmpty(locale) && !island.getName().isEmpty())\n            infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append(\"\\n\");\n\n        // Island location\n        if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) {\n            WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension());\n            infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale,\n                    Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append(\"\\n\");\n        }\n\n        // Island last time updated\n        if (lastTime != -1) {\n            if (!Message.ISLAND_INFO_LAST_TIME_UPDATED.isEmpty(locale)) {\n\n                infoMessage.append(Message.ISLAND_INFO_LAST_TIME_UPDATED.getMessage(locale, Formatters.TIME_FORMATTER.format(\n                        Duration.ofMillis(System.currentTimeMillis() - (lastTime * 1000)), locale))).append(\"\\n\");\n            }\n        } else {\n            if (!Message.ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE.isEmpty(locale)) {\n                infoMessage.append(Message.ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE.getMessage(locale)).append(\"\\n\");\n            }\n        }\n\n        // Island rate\n        if (!Message.ISLAND_INFO_RATE.isEmpty(locale)) {\n            double rating = island.getTotalRating();\n            infoMessage.append(Message.ISLAND_INFO_RATE.getMessage(locale, Formatters.RATING_FORMATTER.format(rating, locale),\n                    Formatters.NUMBER_FORMATTER.format(rating), island.getRatingAmount())).append(\"\\n\");\n        }\n\n        if (BuiltinModules.BANK.isEnabled()) {\n            // Island balance\n            if (!Message.ISLAND_INFO_BANK.isEmpty(locale))\n                infoMessage.append(Message.ISLAND_INFO_BANK.getMessage(locale, island.getIslandBank().getBalance())).append(\"\\n\");\n        }\n\n        // Island bonus worth\n        if (!Message.ISLAND_INFO_BONUS.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_BONUS.getMessage(locale, island.getBonusWorth())).append(\"\\n\");\n\n        // Island bonus level\n        if (!Message.ISLAND_INFO_BONUS_LEVEL.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_BONUS_LEVEL.getMessage(locale, island.getBonusLevel())).append(\"\\n\");\n\n        // Island worth\n        if (!Message.ISLAND_INFO_WORTH.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_WORTH.getMessage(locale, island.getWorth())).append(\"\\n\");\n\n        // Island level\n        if (!Message.ISLAND_INFO_LEVEL.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append(\"\\n\");\n\n        // Island discord\n        if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !\"None\".equals(island.getDiscord())) {\n            infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append(\"\\n\");\n        }\n\n        // Island paypal\n        if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !\"None\".equals(island.getPaypal())) {\n            infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append(\"\\n\");\n        }\n\n        boolean upgradesModule = BuiltinModules.UPGRADES.isEnabled();\n\n        if (upgradesModule) {\n            // Island upgrades\n            if (!Message.ISLAND_INFO_ADMIN_UPGRADES.isEmpty(locale) && !Message.ISLAND_INFO_ADMIN_UPGRADE_LINE.isEmpty(locale)) {\n                StringBuilder upgradesString = new StringBuilder();\n                for (Upgrade upgrade : plugin.getUpgrades().getUpgrades()) {\n                    upgradesString.append(Message.ISLAND_INFO_ADMIN_UPGRADE_LINE.getMessage(locale, upgrade.getName(), island.getUpgradeLevel(upgrade).getLevel())).append(\"\\n\");\n                }\n                infoMessage.append(Message.ISLAND_INFO_ADMIN_UPGRADES.getMessage(locale, upgradesString));\n            }\n        }\n\n        // Island admin size\n        collectIslandData(locale, infoMessage, island::getIslandSize, island::getIslandSizeRaw, Message.ISLAND_INFO_ADMIN_SIZE);\n\n        // Island team limit\n        collectIslandData(locale, infoMessage, island::getTeamLimit, island::getTeamLimitRaw, Message.ISLAND_INFO_ADMIN_TEAM_LIMIT);\n\n        // Island warps limit\n        collectIslandData(locale, infoMessage, island::getWarpsLimit, island::getWarpsLimitRaw, Message.ISLAND_INFO_ADMIN_WARPS_LIMIT);\n\n        // Island coop limit\n        if (plugin.getSettings().isCoopMembers())\n            collectIslandData(locale, infoMessage, island::getCoopLimit, island::getCoopLimitRaw, Message.ISLAND_INFO_ADMIN_COOP_LIMIT);\n\n        // Island bank limit\n        if (BuiltinModules.BANK.isEnabled())\n            collectIslandData(locale, infoMessage, island::getBankLimit, island::getBankLimitRaw, Message.ISLAND_INFO_ADMIN_BANK_LIMIT,\n                Formatters.NUMBER_FORMATTER::format);\n\n        if (upgradesModule) {\n            // Island spawners multiplier\n            if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeSpawnerRates.class)) {\n                collectIslandData(locale, infoMessage, island::getSpawnerRatesMultiplier, island::getSpawnerRatesRaw,\n                        Message.ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER);\n            }\n\n\n            // Island drops multiplier\n            if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeMobDrops.class)) {\n                collectIslandData(locale, infoMessage, island::getMobDropsMultiplier, island::getMobDropsRaw,\n                        Message.ISLAND_INFO_ADMIN_DROPS_MULTIPLIER);\n            }\n\n            // Island crops multiplier\n            if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) {\n                collectIslandData(locale, infoMessage, island::getCropGrowthMultiplier, island::getCropGrowthRaw,\n                        Message.ISLAND_INFO_ADMIN_CROPS_MULTIPLIER);\n            }\n\n            // Island entity limits\n            if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class)) {\n                collectIslandData(locale, island::getEntitiesLimitsAsKeys, island::getCustomEntitiesLimits,\n                        Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS, Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE)\n                        .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS.getMessage(locale, message)));\n            }\n\n            // Island block limits\n            if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeBlockLimits.class)) {\n                collectIslandData(locale, island::getBlocksLimits, island::getCustomBlocksLimits,\n                        Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS, Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE)\n                        .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS.getMessage(locale, message)));\n            }\n        }\n\n        if (BuiltinModules.GENERATORS.isEnabled()) {\n            // Island generator rates\n            if (!Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.isEmpty(locale) && !Message.ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE.isEmpty(locale)) {\n                for (Dimension dimension : Dimension.values()) {\n                    Map<Key, Integer> customGeneratorValues = island.getCustomGeneratorAmounts(dimension);\n                    StringBuilder generatorString = new StringBuilder();\n                    for (Map.Entry<String, Integer> entry : island.getGeneratorPercentages(dimension).entrySet()) {\n                        Key key = Keys.ofMaterialAndData(entry.getKey());\n                        generatorString.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE.getMessage(locale,\n                                Formatters.CAPITALIZED_FORMATTER.format(entry.getKey()),\n                                Formatters.NUMBER_FORMATTER.format(IslandUtils.getGeneratorPercentageDecimal(island, key, dimension)),\n                                island.getGeneratorAmount(key, dimension))\n                        );\n                        if (!customGeneratorValues.containsKey(key))\n                            generatorString.append(\" \").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale));\n                        generatorString.append(\"\\n\");\n                    }\n                    if (generatorString.length() > 0)\n                        infoMessage.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.getMessage(locale, generatorString,\n                                Formatters.CAPITALIZED_FORMATTER.format(dimension.getName())));\n                }\n            }\n        }\n\n        // Island effects\n        if (upgradesModule && BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) {\n            collectIslandData(locale, island::getPotionEffects, island::getCustomPotionEffects,\n                    Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS, Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE, PotionEffectType::getName)\n                    .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.getMessage(locale, message)));\n        }\n\n        // Island role limits\n        collectIslandData(locale, island::getRoleLimits, island::getCustomRoleLimits,\n                Message.ISLAND_INFO_ADMIN_ROLE_LIMITS, Message.ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE)\n                .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ROLE_LIMITS.getMessage(locale, message)));\n\n        // Island members\n        if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) {\n            Map<PlayerRole, StringBuilder> rolesStrings = new LinkedHashMap<>();\n\n            List<SuperiorPlayer> members = island.getIslandMembers(false);\n\n            if (!Message.ISLAND_INFO_PLAYER_LINE.isEmpty(locale)) {\n                members.forEach(superiorPlayer -> rolesStrings.computeIfAbsent(superiorPlayer.getPlayerRole(), role -> new StringBuilder())\n                        .append(Message.ISLAND_INFO_PLAYER_LINE.getMessage(locale, superiorPlayer.getName())).append(\"\\n\"));\n            }\n\n            rolesStrings.keySet().stream()\n                    .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight)))\n                    .forEach(playerRole -> {\n                        StringBuilder players = rolesStrings.get(playerRole);\n                        if (players != null && players.length() > 0)\n                            infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players));\n                    });\n        }\n\n        if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_FOOTER.getMessage(locale));\n\n        Message.CUSTOM.send(sender, infoMessage.toString(), false);\n    }\n\n    private static <K, V> Optional<StringBuilder> collectIslandData(Locale locale,\n                                                                    Supplier<Map<K, V>> dataFunction,\n                                                                    Supplier<Map<K, V>> customDataFunction,\n                                                                    Message dataMessage, Message dataLineMessage) {\n        return collectIslandData(locale, dataFunction, customDataFunction, dataMessage, dataLineMessage, null);\n    }\n\n    private static <K, V> Optional<StringBuilder> collectIslandData(Locale locale,\n                                                                    Supplier<Map<K, V>> dataFunction,\n                                                                    Supplier<Map<K, V>> customDataFunction,\n                                                                    Message dataMessage, Message dataLineMessage,\n                                                                    @Nullable Function<K, String> formatter) {\n        if (dataMessage.isEmpty(locale) || dataLineMessage.isEmpty(locale))\n            return Optional.empty();\n\n        StringBuilder dataValue = new StringBuilder();\n\n        Map<K, V> islandData = dataFunction.get();\n        Map<K, V> islandCustomData = customDataFunction.get();\n\n        islandData.forEach((key, value) -> {\n            String keyStringValue = formatter == null ? key.toString() : formatter.apply(key);\n            dataValue.append(dataLineMessage.getMessage(locale, Formatters.CAPITALIZED_FORMATTER.format(keyStringValue), value));\n            if (!islandCustomData.containsKey(key))\n                dataValue.append(\" \").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale));\n            dataValue.append(\"\\n\");\n        });\n\n        return dataValue.length() > 0 ? Optional.of(dataValue) : Optional.empty();\n    }\n\n    private static <T> void collectIslandData(Locale locale, StringBuilder message,\n                                              Supplier<T> dataFunction,\n                                              Supplier<T> customDataFunction,\n                                              Message dataLineMessage) {\n        collectIslandData(locale, message, dataFunction, customDataFunction, dataLineMessage, null);\n    }\n\n    private static <T> void collectIslandData(Locale locale, StringBuilder message,\n                                              Supplier<T> dataFunction,\n                                              Supplier<T> customDataFunction,\n                                              Message dataLineMessage,\n                                              @Nullable Function<T, ?> formatter) {\n        if (dataLineMessage.isEmpty(locale))\n            return;\n\n        T islandData = dataFunction.get();\n        T islandCustomData = customDataFunction.get();\n\n        Object formattedIslandData = formatter == null ? islandData : formatter.apply(islandData);\n        message.append(dataLineMessage.getMessage(locale, formattedIslandData));\n        if (!Objects.equals(islandData, islandCustomData))\n            message.append(\" \").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale));\n        message.append(\"\\n\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpawn.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.ChatColor;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSpawn implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"spawn\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.spawn\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin spawn [\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SPAWN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer targetPlayer = null;\n\n        if (!(sender instanceof Player) && args.length == 2) {\n            sender.sendMessage(ChatColor.RED + \"You must specify a player to teleport.\");\n            return;\n        } else if (args.length == 3) {\n            targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]);\n            if (targetPlayer != null && !targetPlayer.isOnline())\n                targetPlayer = null;\n        } else if (sender instanceof Player) {\n            targetPlayer = plugin.getPlayers().getSuperiorPlayer((Player) sender);\n        }\n\n        if (targetPlayer == null) {\n            Message.INVALID_PLAYER.send(sender, args[2]);\n            return;\n        }\n\n        targetPlayer.teleport(plugin.getGrid().getSpawnIsland());\n\n        Message.SPAWN_TELEPORT_SUCCESS.send(sender, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 3 ? CommandTabCompletes.getOnlinePlayers(plugin, args[2], false) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSpy implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"spy\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.spy\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin spy\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SPY.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (!PluginEventsFactory.callPlayerToggleSpyEvent(superiorPlayer))\n            return;\n\n        if (superiorPlayer.hasAdminSpyEnabled()) {\n            Message.TOGGLED_SPY_OFF.send(superiorPlayer);\n        } else {\n            Message.TOGGLED_SPY_ON.send(superiorPlayer);\n        }\n\n        superiorPlayer.toggleAdminSpy();\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminStats.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.ChatColor;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminStats implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"stats\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.stats\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin stats\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_STATS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        sender.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY +\n                \" Stats:\\n\" + \" - Islands: \" + plugin.getGrid().getSize() + \"\\n\");\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class CmdAdminSyncBonus implements IAdminIslandCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"syncbonus\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.syncbonus\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin syncbonus <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <worth/level>\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        boolean isWorthBonus = !args[3].equalsIgnoreCase(\"level\");\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            BigDecimal currentBonus = isWorthBonus ? island.getBonusWorth() : island.getBonusLevel();\n            BigDecimal newBonus = calculateValue(island, isWorthBonus);\n            if (!newBonus.equals(currentBonus)) {\n                if (isWorthBonus) {\n                    PluginEvent<PluginEventArgs.IslandChangeWorthBonus> event = PluginEventsFactory.callIslandChangeWorthBonusEvent(\n                            island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, newBonus);\n                    if (!event.isCancelled()) {\n                        island.setBonusWorth(event.getArgs().worthBonus);\n                        ++islandsChangedCount;\n                    }\n                } else {\n                    PluginEvent<PluginEventArgs.IslandChangeLevelBonus> event = PluginEventsFactory.callIslandChangeLevelBonusEvent(\n                            island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, newBonus);\n                    if (!event.isCancelled()) {\n                        island.setBonusLevel(event.getArgs().levelBonus);\n                        ++islandsChangedCount;\n                    }\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.BONUS_SYNC_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.BONUS_SYNC_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.BONUS_SYNC.send(sender, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], \"worth\", \"level\") : Collections.emptyList();\n    }\n\n    private static BigDecimal calculateValue(Island island, boolean calculateWorth) {\n        BigDecimal value = BigDecimal.ZERO;\n\n        String generatedSchematic = island.getSchematicName();\n\n        for (Dimension dimension : Dimension.values()) {\n            if (island.wasSchematicGenerated(dimension)) {\n                String suffix = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension() ? \"\"\n                        : \"_\" + dimension.getName().toLowerCase(Locale.ENGLISH);\n                Schematic schematic = plugin.getSchematics().getSchematic(generatedSchematic + suffix);\n                if (schematic != null) {\n                    value = value.add(_calculateValues(schematic.getBlockCounts(), calculateWorth));\n                }\n            }\n        }\n\n        return value.negate();\n    }\n\n    private static BigDecimal _calculateValues(Map<Key, Integer> blockCounts, boolean calculateWorth) {\n        BigDecimal value = BigDecimal.ZERO;\n\n        for (Map.Entry<Key, Integer> blockEntry : blockCounts.entrySet()) {\n            BigDecimal blockValue = calculateWorth ? plugin.getBlockValues().getBlockWorth(blockEntry.getKey()) :\n                    plugin.getBlockValues().getBlockLevel(blockEntry.getKey());\n            if (blockValue.compareTo(BigDecimal.ZERO) > 0) {\n                value = value.add(blockValue.multiply(new BigDecimal(blockEntry.getValue())));\n            }\n        }\n\n        return value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminTeleport implements IAdminIslandCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PortalsManagerService> portalsManager = new LazyReference<PortalsManagerService>() {\n        @Override\n        protected PortalsManagerService create() {\n            return plugin.getServices().getService(PortalsManagerService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"tp\", \"teleport\", \"go\", \"visit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.teleport\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin teleport <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> [\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_TELEPORT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        Dimension dimension;\n\n        if (args.length != 4) {\n            dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n        } else {\n            dimension = CommandArguments.getDimension(sender, args[3]);\n            if (dimension == null)\n                return;\n        }\n\n        if (plugin.getGrid().getIslandsWorldInfo(island, dimension) == null) {\n            Message.WORLD_NOT_ENABLED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(dimension.getName()));\n            return;\n        }\n\n        if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            if (!island.wasSchematicGenerated(dimension)) {\n                IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n                    islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> {\n                        Location simulatedPortalLocation = island.getCenter(\n                                plugin.getSettings().getWorlds().getDefaultWorldDimension());\n                        Location destinationLocation = island.getCenter(dimension);\n                        portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island,\n                                simulatedPortalLocation, PortalType.CUSTOM, destinationLocation, false);\n                    });\n                });\n                return;\n            }\n        }\n\n        superiorPlayer.teleport(island, dimension, result -> {\n            if (!result) {\n                superiorPlayer.teleport(island.getIslandHome(dimension));\n            }\n        });\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CmdAdminTitle implements IAdminPlayerCommand {\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"title\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.title\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin title <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_FADE_IN.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_DURATION.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_FADE_OUT.getMessage(locale) + \"> \" +\n                \"-title [\" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \"] \" +\n                \"-subtitle [\" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_TITLE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 8;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        if (!targetPlayer.isOnline()) {\n            Message.PLAYER_NOT_ONLINE.send(sender);\n            return;\n        }\n\n        NumberArgument<Integer> fadeIn = CommandArguments.getInterval(sender, args[3]);\n\n        if (!fadeIn.isSucceed())\n            return;\n\n        NumberArgument<Integer> duration = CommandArguments.getInterval(sender, args[4]);\n\n        if (!duration.isSucceed())\n            return;\n\n        NumberArgument<Integer> fadeOut = CommandArguments.getInterval(sender, args[5]);\n\n        if (!fadeOut.isSucceed())\n            return;\n\n        Map<String, String> parsedArguments = CommandArguments.parseArguments(args);\n\n        String title = parsedArguments.get(\"title\");\n        String subtitle = parsedArguments.get(\"subtitle\");\n\n        if (title == null && subtitle == null) {\n            Message.INVALID_TITLE.send(sender);\n            return;\n        }\n\n        Player player = targetPlayer.asPlayer();\n\n        if (!Text.isBlank(title))\n            title = placeholdersService.get().parsePlaceholders(player, title);\n        if (!Text.isBlank(subtitle))\n            subtitle = placeholdersService.get().parsePlaceholders(player, subtitle);\n\n        plugin.getNMSPlayers().sendTitle(player,\n                title == null ? null : Formatters.COLOR_FORMATTER.format(title),\n                subtitle == null ? null : Formatters.COLOR_FORMATTER.format(subtitle),\n                fadeIn.getNumber(),\n                duration.getNumber(),\n                fadeOut.getNumber());\n\n        Message.TITLE_SENT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitleAll.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CmdAdminTitleAll implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"titleall\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.titleall\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin titleall <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_FADE_IN.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_DURATION.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_TITLE_FADE_OUT.getMessage(locale) + \"> \" +\n                \"-title [\" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \"] \" +\n                \"-subtitle [\" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_TITLE_ALL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 8;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Integer> fadeIn = CommandArguments.getInterval(sender, args[3]);\n\n        if (!fadeIn.isSucceed())\n            return;\n\n        NumberArgument<Integer> duration = CommandArguments.getInterval(sender, args[4]);\n\n        if (!duration.isSucceed())\n            return;\n\n        NumberArgument<Integer> fadeOut = CommandArguments.getInterval(sender, args[5]);\n\n        if (!fadeOut.isSucceed())\n            return;\n\n        Map<String, String> parsedArguments = CommandArguments.parseArguments(args);\n\n        String title = parsedArguments.get(\"title\");\n        String subtitle = parsedArguments.get(\"subtitle\");\n\n        if (title == null && subtitle == null) {\n            Message.INVALID_TITLE.send(sender);\n            return;\n        }\n\n        islands.forEach(island -> island.sendTitle(title == null ? null : Formatters.COLOR_FORMATTER.format(title),\n                subtitle == null ? null : Formatters.COLOR_FORMATTER.format(subtitle),\n                fadeIn.getNumber(), duration.getNumber(), fadeOut.getNumber()));\n\n        if (targetPlayer == null)\n            Message.GLOBAL_TITLE_SENT_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : \"all\");\n        else\n            Message.GLOBAL_TITLE_SENT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnignore.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminUnignore implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"unignore\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.unignore\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin unignore <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_UNIGNORE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        island.setIgnored(false);\n\n        if (targetPlayer == null)\n            Message.UNIGNORED_ISLAND_NAME.send(sender, island.getName());\n        else\n            Message.UNIGNORED_ISLAND.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.admin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminUnlockWorld implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"unlockworld\", \"world\", \"uworld\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.world\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin unlockworld <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \"> <true/false>\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Dimension dimension = CommandArguments.getDimension(sender, args[3]);\n\n        if (dimension == null)\n            return;\n\n        if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            Message.INVALID_ENVIRONMENT.send(sender, args[3]);\n            return;\n        }\n\n        boolean unlockWorld = Boolean.parseBoolean(args[4]);\n\n        if (unlockWorld) {\n            handleWorldUnlock(sender, islands, dimension, targetPlayer, args[3]);\n        } else {\n            handleWorldLock(sender, islands, dimension, targetPlayer, args[3]);\n        }\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : args.length == 5 ?\n                CommandTabCompletes.getCustomComplete(args[4], \"true\", \"false\") : Collections.emptyList();\n    }\n\n    private void handleWorldUnlock(CommandSender sender, List<Island> islands, Dimension dimension,\n                                   @Nullable SuperiorPlayer targetPlayer, String worldType) {\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (!PluginEventsFactory.callIslandUnlockWorldEvent(island, sender, dimension))\n                continue;\n\n            island.setDimensionEnabled(dimension, true);\n            ++islandsChangedCount;\n        }\n\n        if (islandsChangedCount > 1)\n            Message.UNLOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType));\n        else if (targetPlayer == null)\n            Message.UNLOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName());\n        else\n            Message.UNLOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName());\n\n    }\n\n    private void handleWorldLock(CommandSender sender, List<Island> islands, Dimension dimension,\n                                 @Nullable SuperiorPlayer targetPlayer, String worldType) {\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (!PluginEventsFactory.callIslandLockWorldEvent(island, sender, dimension))\n                continue;\n\n            island.setDimensionEnabled(dimension, false);\n            ++islandsChangedCount;\n        }\n\n        if (islandsChangedCount > 1)\n            Message.LOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType));\n        else if (targetPlayer == null)\n            Message.LOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName());\n        else\n            Message.LOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName());\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/Argument.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.arguments;\n\npublic abstract class Argument<K, V> {\n\n    protected final K k;\n    protected final V v;\n\n    protected Argument(K k, V v) {\n        this.k = k;\n        this.v = v;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.arguments;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class CommandArguments {\n\n    private CommandArguments() {\n\n    }\n\n    public static IslandArgument getIsland(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(argument);\n        Island island = targetPlayer == null ? plugin.getGrid().getIsland(argument) : targetPlayer.getIsland();\n\n        if (island == null) {\n            if (argument.equalsIgnoreCase(sender.getName()))\n                Message.INVALID_ISLAND.send(sender);\n            else if (targetPlayer == null)\n                Message.INVALID_ISLAND_OTHER_NAME.send(sender, Formatters.STRIP_COLOR_FORMATTER.format(argument));\n            else\n                Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n        }\n\n        return new IslandArgument(island, targetPlayer);\n    }\n\n    public static IslandsListArgument getMultipleIslands(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        List<Island> islands = new LinkedList<>();\n        SuperiorPlayer targetPlayer;\n\n        if (argument.equals(\"*\")) {\n            targetPlayer = null;\n            islands = plugin.getGrid().getIslands();\n        } else {\n            IslandArgument arguments = getIsland(plugin, sender, argument);\n            targetPlayer = arguments.getSuperiorPlayer();\n            if (arguments.getIsland() != null)\n                islands.add(arguments.getIsland());\n        }\n\n        return new IslandsListArgument(Collections.unmodifiableList(islands), targetPlayer);\n    }\n\n    public static IslandArgument getSenderIsland(SuperiorSkyblockPlugin plugin, CommandSender sender) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        Island island = superiorPlayer.getIsland();\n\n        if (island == null)\n            Message.INVALID_ISLAND.send(superiorPlayer);\n\n        return new IslandArgument(island, superiorPlayer);\n    }\n\n    public static SuperiorPlayer getPlayer(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) {\n        return getPlayer(plugin, superiorPlayer.asPlayer(), argument);\n    }\n\n    public static SuperiorPlayer getPlayer(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(argument);\n\n        if (targetPlayer == null)\n            Message.INVALID_PLAYER.send(sender, argument);\n\n        return targetPlayer;\n    }\n\n    public static List<SuperiorPlayer> getMultiplePlayers(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        List<SuperiorPlayer> players = new LinkedList<>();\n\n        if (argument.equals(\"*\")) {\n            players = plugin.getPlayers().getAllPlayers();\n        } else {\n            SuperiorPlayer targetPlayer = getPlayer(plugin, sender, argument);\n            if (targetPlayer != null)\n                players.add(targetPlayer);\n        }\n\n        return Collections.unmodifiableList(players);\n    }\n\n    public static IslandArgument getIslandWhereStanding(SuperiorSkyblockPlugin plugin, CommandSender sender) {\n        if (!(sender instanceof Player)) {\n            Message.CUSTOM.send(sender, \"&cYou must specify a player's name.\", true);\n            return IslandArgument.EMPTY;\n        }\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Island locationIsland = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle()));\n            island = locationIsland == null || locationIsland.isSpawn() ? superiorPlayer.getIsland() : locationIsland;\n        }\n\n        if (island == null)\n            Message.INVALID_ISLAND.send(sender);\n\n        return new IslandArgument(island, superiorPlayer);\n    }\n\n    public static Mission<?> getMission(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) {\n        return getMission(plugin, superiorPlayer.asPlayer(), argument);\n    }\n\n    public static Mission<?> getMission(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        Mission<?> mission = plugin.getMissions().getMission(argument);\n\n        if (mission == null)\n            Message.INVALID_MISSION.send(sender, argument);\n\n        return mission;\n    }\n\n    public static List<Mission<?>> getMultipleMissions(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        List<Mission<?>> missions = new LinkedList<>();\n\n        if (argument.equals(\"*\")) {\n            missions = plugin.getMissions().getAllMissions();\n        } else {\n            Mission<?> mission = getMission(plugin, sender, argument);\n            if (mission != null)\n                missions.add(mission);\n        }\n\n        return Collections.unmodifiableList(missions);\n    }\n\n    public static MissionCategory getMissionCategory(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        MissionCategory missionCategory = plugin.getMissions().getMissionCategory(argument);\n\n        if (missionCategory == null)\n            Message.INVALID_MISSION_CATEGORY.send(sender, argument);\n\n        return missionCategory;\n    }\n\n    public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) {\n        return getUpgrade(plugin, superiorPlayer.asPlayer(), argument);\n    }\n\n    public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        Upgrade upgrade = plugin.getUpgrades().getUpgrade(argument);\n\n        if (upgrade == null) {\n            Message.INVALID_UPGRADE.send(sender, argument, plugin.getUpgrades().getUpgradesNames());\n        }\n\n        return upgrade;\n    }\n\n    public static String buildLongString(String[] args, int start, boolean colorize) {\n        StringBuilder stringBuilder = new StringBuilder();\n\n        for (int i = start; i < args.length; i++)\n            stringBuilder.append(\" \").append(args[i]);\n\n        return colorize ? Formatters.COLOR_FORMATTER.format(stringBuilder.substring(1)) : stringBuilder.substring(1);\n    }\n\n    public static PlayerRole getPlayerRole(CommandSender sender, String argument) {\n        PlayerRole playerRole = null;\n\n        try {\n            playerRole = SPlayerRole.of(argument);\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        if (playerRole == null) {\n            Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getAllRoleNames());\n        }\n\n        return playerRole;\n    }\n\n    public static PlayerRole getPlayerRoleFromLadder(CommandSender sender, String argument) {\n        PlayerRole playerRole = null;\n\n        try {\n            playerRole = SPlayerRole.of(argument);\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        if (playerRole == null || !playerRole.isRoleLadder()) {\n            Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRolesLadderNames());\n            playerRole = null;\n        }\n\n        return playerRole;\n    }\n\n    public static PlayerRole getPlayerRoleForLimit(CommandSender sender, String argument) {\n        PlayerRole playerRole = null;\n\n        try {\n            playerRole = SPlayerRole.of(argument);\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        if (playerRole == null || !IslandUtils.isValidRoleForLimit(playerRole)) {\n            Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRoleLimitsNames());\n            playerRole = null;\n        }\n\n        return playerRole;\n    }\n\n    public static NumberArgument<Integer> getLimit(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_LIMIT);\n    }\n\n    public static BigDecimal getBigDecimalAmount(CommandSender sender, String argument) {\n        BigDecimal amount = null;\n\n        try {\n            amount = new BigDecimal(argument);\n        } catch (NumberFormatException ex) {\n            Message.INVALID_AMOUNT.send(sender);\n        }\n\n        return amount;\n    }\n\n    public static NumberArgument<Integer> getAmount(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_AMOUNT);\n    }\n\n    public static NumberArgument<Double> getMultiplier(CommandSender sender, String argument) {\n        double multiplier = 0;\n        boolean status = true;\n\n        try {\n            multiplier = Double.parseDouble(argument);\n            // Makes sure the multiplier is rounded.\n            multiplier = Math.round(multiplier * 100) / 100D;\n        } catch (IllegalArgumentException ex) {\n            Message.INVALID_MULTIPLIER.send(sender, argument);\n            status = false;\n        }\n\n        return new NumberArgument<>(multiplier, status);\n    }\n\n    public static PotionEffectType getPotionEffect(CommandSender sender, String argument) {\n        PotionEffectType potionEffectType = PotionEffectType.getByName(argument.toUpperCase(Locale.ENGLISH));\n\n        if (potionEffectType == null)\n            Message.INVALID_EFFECT.send(sender, argument);\n\n        return potionEffectType;\n    }\n\n    public static NumberArgument<Integer> getLevel(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_LEVEL);\n    }\n\n    public static Material getMaterial(CommandSender sender, String argument) {\n        Material material = null;\n\n        try {\n            material = Material.valueOf(argument.split(\":\")[0].toUpperCase(Locale.ENGLISH));\n        } catch (Exception ex) {\n            Message.INVALID_MATERIAL.send(sender, argument);\n        }\n\n        return material;\n    }\n\n    public static NumberArgument<Integer> getSize(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_SIZE);\n    }\n\n    public static IslandWarp getWarp(CommandSender sender, Island island, String[] args, int start) {\n        String warpName = buildLongString(args, start, false);\n        IslandWarp islandWarp = island.getWarp(warpName);\n\n        if (islandWarp == null)\n            Message.INVALID_WARP.send(sender, warpName);\n\n        return islandWarp;\n    }\n\n    public static Biome getBiome(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        Biome biome = plugin.getNMSAlgorithms().getBiome(argument);\n\n        if (biome == null) {\n            Message.INVALID_BIOME.send(sender, argument);\n        }\n\n        return biome;\n    }\n\n    public static World getWorld(CommandSender sender, String argument) {\n        World world = Bukkit.getWorld(argument);\n\n        if (world == null)\n            Message.INVALID_WORLD.send(sender, argument);\n\n        return world;\n    }\n\n    public static Location getLocation(CommandSender sender, World world, String x, String y, String z) {\n        Location location = null;\n\n        try {\n            location = new Location(world, Integer.parseInt(x), Integer.parseInt(y), Integer.parseInt(z));\n        } catch (Throwable ex) {\n            Message.INVALID_BLOCK.send(sender, world.getName() + \", \" + x + \", \" + y + \", \" + z);\n        }\n\n        return location;\n    }\n\n    public static NumberArgument<Integer> getPage(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_PAGE);\n    }\n\n    public static NumberArgument<Integer> getRows(CommandSender sender, String argument) {\n        return getInt(sender, argument, Message.INVALID_ROWS);\n    }\n\n    public static IslandPrivilege getIslandPrivilege(CommandSender sender, String argument) {\n        IslandPrivilege islandPrivilege = null;\n\n        try {\n            islandPrivilege = IslandPrivilege.getByName(argument);\n        } catch (NullPointerException ignored) {\n        }\n\n        if (islandPrivilege == null) {\n            Message.INVALID_ISLAND_PERMISSION.send(sender, argument, IslandPrivileges.getPrivilegesNames());\n        }\n\n        return islandPrivilege;\n    }\n\n    public static Rating getRating(CommandSender sender, String argument) {\n        Rating rating = null;\n\n        try {\n            rating = Rating.valueOf(argument.toUpperCase(Locale.ENGLISH));\n        } catch (Exception ex) {\n            Message.INVALID_RATE.send(sender, argument, Rating.getValuesString());\n        }\n\n        return rating;\n    }\n\n    public static IslandFlag getIslandFlag(CommandSender sender, String argument) {\n        IslandFlag islandFlag = null;\n\n        try {\n            islandFlag = IslandFlag.getByName(argument);\n        } catch (NullPointerException ignored) {\n        }\n\n        if (islandFlag == null) {\n            Message.INVALID_SETTINGS.send(sender, argument, IslandFlags.getFlagsNames());\n        }\n\n        return islandFlag;\n    }\n\n    public static Dimension getDimension(CommandSender sender, String argument) {\n        Dimension dimension = null;\n\n        try {\n            dimension = Dimension.getByName(argument.toUpperCase(Locale.ENGLISH));\n        } catch (Exception ignored) {\n        }\n\n        if (dimension == null)\n            Message.INVALID_ENVIRONMENT.send(sender, argument);\n\n        return dimension;\n    }\n\n    public static Schematic getSchematic(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) {\n        Schematic schematic = plugin.getSchematics().getSchematic(argument);\n\n        if (schematic == null || argument.endsWith(\"_nether\") || argument.endsWith(\"_normal\") || argument.endsWith(\"_the_end\")) {\n            Message.INVALID_SCHEMATIC.send(sender, argument);\n            return null;\n        }\n\n        return schematic;\n    }\n\n    public static NumberArgument<Integer> getInterval(CommandSender sender, String argument) {\n        NumberArgument<Integer> interval = getInt(sender, argument, Message.INVALID_INTERVAL);\n\n        if (interval.isSucceed() && interval.getNumber() < 0) {\n            Message.INVALID_INTERVAL.send(sender, argument);\n            return new NumberArgument<>(interval.getNumber(), false);\n        }\n\n        return interval;\n    }\n\n    public static Map<String, String> parseArguments(String[] args) {\n        Map<String, String> parsedArgs = new HashMap<>();\n        String currentKey = null;\n        StringBuilder stringBuilder = new StringBuilder();\n\n        for (String arg : args) {\n            if (arg.startsWith(\"-\")) {\n                if (currentKey != null && stringBuilder.length() > 0) {\n                    parsedArgs.put(currentKey, stringBuilder.substring(1));\n                }\n\n                currentKey = arg.substring(1).toLowerCase(Locale.ENGLISH);\n                stringBuilder = new StringBuilder();\n            } else if (currentKey != null) {\n                stringBuilder.append(\" \").append(arg);\n            }\n        }\n\n        if (currentKey != null && stringBuilder.length() > 0) {\n            parsedArgs.put(currentKey, stringBuilder.substring(1));\n        }\n\n        return parsedArgs;\n    }\n\n    public static BorderColor getBorderColor(CommandSender sender, String argument) {\n        BorderColor borderColor = null;\n\n        try {\n            borderColor = BorderColor.valueOf(argument.toUpperCase(Locale.ENGLISH));\n        } catch (Exception ignored) {\n        }\n\n        if (borderColor == null)\n            Message.INVALID_BORDER_COLOR.send(sender, argument);\n\n        return borderColor;\n    }\n\n    private static NumberArgument<Integer> getInt(CommandSender sender, String argument, Message locale) {\n        int i = 0;\n        boolean status = true;\n\n        try {\n            i = Integer.parseInt(argument);\n        } catch (IllegalArgumentException ex) {\n            locale.send(sender, argument);\n            status = false;\n        }\n\n        return new NumberArgument<>(i, status);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/IslandArgument.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.arguments;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class IslandArgument extends Argument<Island, SuperiorPlayer> {\n\n    public static final IslandArgument EMPTY = new IslandArgument(null, null);\n\n    public IslandArgument(@Nullable Island island, SuperiorPlayer superiorPlayer) {\n        super(island, superiorPlayer);\n    }\n\n    @Nullable\n    public Island getIsland() {\n        return super.k;\n    }\n\n    public SuperiorPlayer getSuperiorPlayer() {\n        return super.v;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/IslandsListArgument.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.arguments;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.List;\n\npublic class IslandsListArgument extends Argument<List<Island>, SuperiorPlayer> {\n\n    public IslandsListArgument(List<Island> islands, @Nullable SuperiorPlayer superiorPlayer) {\n        super(islands, superiorPlayer);\n    }\n\n    public List<Island> getIslands() {\n        return super.k;\n    }\n\n    @Nullable\n    public SuperiorPlayer getSuperiorPlayer() {\n        return super.v;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/NumberArgument.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.arguments;\n\npublic class NumberArgument<N> extends Argument<N, Boolean> {\n\n    public NumberArgument(N number, boolean succeed) {\n        super(number, succeed);\n    }\n\n    public N getNumber() {\n        return super.k;\n    }\n\n    public boolean isSucceed() {\n        return super.v;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAccept implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"accept\", \"join\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.accept\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"accept [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ACCEPT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        SuperiorPlayer targetPlayer;\n        Island island;\n\n        if (args.length == 1) {\n            List<Island> playerPendingInvites = superiorPlayer.getInvites();\n            island = playerPendingInvites.isEmpty() ? null : playerPendingInvites.get(0);\n            targetPlayer = null;\n        } else {\n            targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[1]);\n            island = targetPlayer == null ? plugin.getGrid().getIsland(args[1]) : targetPlayer.getIsland();\n        }\n\n        if (island == null || !island.isInvited(superiorPlayer)) {\n            Message.NO_ISLAND_INVITE.send(superiorPlayer);\n            return;\n        }\n\n        if (superiorPlayer.getIsland() != null) {\n            Message.JOIN_WHILE_IN_ISLAND.send(superiorPlayer);\n            return;\n        }\n\n        int teamLimit = island.getTeamLimit();\n        if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) {\n            Message.JOIN_FULL_ISLAND.send(superiorPlayer);\n            island.revokeInvite(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.INVITE))\n            return;\n\n        IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName());\n\n        island.addMember(superiorPlayer, SPlayerRole.defaultRole());\n\n        if (targetPlayer == null)\n            Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName());\n        else\n            Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) ->\n                        onlineIsland.isInvited(superiorPlayer)) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.CommandsHelper;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdAdmin implements ISuperiorCommand {\n\n    private static final Int2ObjectMapView<List<SuperiorCommand>> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap();\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh);\n        dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh);\n    }\n\n    private static void onCommandsRefresh() {\n        commandsPerPageCache.clear();\n    }\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"admin\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin [\" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        java.util.Locale locale = PlayerLocales.getLocale(sender);\n\n        if (args.length > 1 && !isNumber(args[1])) {\n            String executedSubCommand = args[1];\n\n            Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), executedSubCommand);\n\n            SuperiorCommand command = plugin.getCommands().getAdminCommand(executedSubCommand);\n            if (command != null) {\n                if (!(sender instanceof Player) && !command.canBeExecutedByConsole()) {\n                    Message.CUSTOM.send(sender, \"&cCan be executed only by players!\", true);\n                    return;\n                }\n\n                if (!CommandsHelper.hasCommandAccess(command, sender)) {\n                    Log.debugResult(Debug.EXECUTE_COMMAND, \"Return Missing Permission\", command.getPermission());\n\n                    if (!plugin.getSettings().isHelpOnNoPermission())\n                        Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission());\n                    else\n                        plugin.getCommands().dispatchSubCommand(sender, \"admin\");\n\n                    return;\n                }\n\n                if (args.length < command.getMinArgs() || args.length > command.getMaxArgs()) {\n                    Log.debugResult(Debug.EXECUTE_COMMAND, \"Return Incorrect Usage\", command.getUsage(locale));\n                    Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + \" \" + command.getUsage(locale));\n                    return;\n                }\n\n                command.execute(plugin, sender, args);\n                return;\n            }\n\n            if (!plugin.getSettings().isHelpOnInvalidCommand())\n                Message.INVALID_COMMAND.send(sender, locale, executedSubCommand);\n            else\n                plugin.getCommands().dispatchSubCommand(sender, \"admin\");\n\n            return;\n        }\n\n        int page = 1;\n\n        if (args.length == 2) {\n            try {\n                page = Integer.parseInt(args[1]);\n            } catch (IllegalArgumentException ex) {\n                Message.INVALID_AMOUNT.send(sender, args[1]);\n                return;\n            }\n        }\n\n        if (page <= 0) {\n            Message.INVALID_AMOUNT.send(sender, page);\n            return;\n        }\n\n        List<SuperiorCommand> subCommands = new SequentialListBuilder<SuperiorCommand>()\n                .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender))\n                .build(plugin.getCommands().getAdminSubCommands());\n\n        if (subCommands.isEmpty()) {\n            Message.NO_COMMAND_PERMISSION.send(sender, locale, getPermission());\n            return;\n        }\n\n        int commandsPerPageCount = plugin.getSettings().getCommandsPerPage();\n\n        int lastPage;\n        if (commandsPerPageCount > 0) {\n            lastPage = subCommands.size() / commandsPerPageCount;\n            if (subCommands.size() % commandsPerPageCount != 0) lastPage++;\n        } else {\n            lastPage = 1;\n        }\n\n        if (page > lastPage) {\n            Message.INVALID_AMOUNT.send(sender, page);\n            return;\n        }\n\n        Message.ADMIN_HELP_HEADER.send(sender, locale, page, lastPage);\n\n        List<SuperiorCommand> commandsOfPage;\n        if (commandsPerPageCount > 0) {\n            commandsOfPage = commandsPerPageCache.get(page);\n            if (commandsOfPage == null) {\n                commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount));\n                commandsPerPageCache.put(page, commandsOfPage);\n            }\n        } else {\n            commandsOfPage = subCommands;\n        }\n\n        for (SuperiorCommand subCommand : commandsOfPage) {\n            String description = subCommand.getDescription(locale);\n            if (description == null)\n                new NullPointerException(\"The description of the command \" + subCommand.getAliases().get(0) + \" is null.\").printStackTrace();\n            Message.ADMIN_HELP_LINE.send(sender, locale, plugin.getCommands().getLabel() + \" \" + subCommand.getUsage(locale), description);\n        }\n\n        if (page != lastPage)\n            Message.ADMIN_HELP_NEXT_PAGE.send(sender, locale, page + 1);\n        else\n            Message.ADMIN_HELP_FOOTER.send(sender, locale);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args.length > 1) {\n            SuperiorCommand command = plugin.getCommands().getAdminCommand(args[1]);\n            if (command != null) {\n                return CommandsHelper.hasCommandAccess(command, sender) ?\n                        command.tabComplete(plugin, sender, args) : Collections.emptyList();\n            }\n        } else if (args.length == 1) {\n            return Collections.emptyList();\n        }\n\n        List<String> list = new LinkedList<>();\n\n        for (SuperiorCommand subCommand : plugin.getCommands().getAdminSubCommands()) {\n            if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) {\n                List<String> aliases = new LinkedList<>(subCommand.getAliases());\n                aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList()));\n                for (String alias : aliases) {\n                    if (alias.contains(args[1].toLowerCase(Locale.ENGLISH))) {\n                        list.add(alias);\n                    }\n                }\n            }\n        }\n\n        return list.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(list);\n    }\n\n    private boolean isNumber(String str) {\n        try {\n            Integer.valueOf(str);\n            return true;\n        } catch (NumberFormatException ex) {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdBan implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"ban\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.ban\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"ban <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BAN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.BAN_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_BAN_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!IslandUtils.checkBanRestrictions(superiorPlayer, island, targetPlayer))\n            return;\n\n        if (plugin.getSettings().isBanConfirm()) {\n            plugin.getMenus().openConfirmBan(superiorPlayer, null, island, targetPlayer);\n        } else {\n            IslandUtils.handleBanPlayer(superiorPlayer, island, targetPlayer);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(),\n                onlinePlayer -> !island.isBanned(onlinePlayer) && (!island.isMember(onlinePlayer) ||\n                        onlinePlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()))) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdBans implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"bans\", \"banlist\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.bans\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"bans\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BANS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        plugin.getMenus().openIslandBannedPlayers(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBiome.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdBiome implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"biome\", \"setbiome\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.biome\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"biome\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BIOME.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_BIOME;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_BIOME_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        plugin.getMenus().openBiomes(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), superiorPlayer.getIsland());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBorder.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdBorder implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"border\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.border\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"border [\" + Message.COMMAND_ARGUMENT_BORDER_COLOR.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BORDER.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (args.length != 2) {\n            plugin.getMenus().openBorderColor(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()));\n            return;\n        }\n\n        BorderColor borderColor = CommandArguments.getBorderColor(sender, args[1]);\n\n        if (borderColor == null)\n            return;\n\n        IslandUtils.handleBorderColorUpdate(superiorPlayer, borderColor);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getBorderColors(args[1]);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.IntStream;\n\npublic class CmdChest implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"chest\", \"vault\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.chest\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"chest [\" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_CHEST.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.ISLAND_CHEST;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_ISLAND_CHEST_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (args.length == 2) {\n            NumberArgument<Integer> pageArguments = CommandArguments.getPage(superiorPlayer.asPlayer(), args[1]);\n\n            if (!pageArguments.isSucceed())\n                return;\n\n            int page = pageArguments.getNumber() - 1;\n            IslandChest[] islandChests = island.getChest();\n\n            if (page < 0 || page >= islandChests.length) {\n                Message.INVALID_PAGE.send(superiorPlayer, args[1]);\n                return;\n            }\n\n            islandChests[page].openChest(superiorPlayer);\n        } else {\n            plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        IslandChest[] islandChests = island.getChest();\n        return args.length == 1 || islandChests.length == 0 ? Collections.emptyList() :\n                CommandTabCompletes.getCustomComplete(args[1], IntStream.range(1, islandChests.length + 1).boxed()\n                        .map(Object::toString).toArray(String[]::new));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdClose implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"close\", \"lock\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.close\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"close\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_CLOSE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.CLOSE_ISLAND;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_CLOSE_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (island.isLocked()) {\n            Message.ISLAND_ALREADY_CLOSED.send(superiorPlayer);\n        } else if (PluginEventsFactory.callIslandCloseEvent(island, superiorPlayer)) {\n            island.setLocked(true);\n            Message.ISLAND_CLOSED.send(superiorPlayer);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdCoop implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"coop\", \"trust\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.coop\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"coop <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_COOP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.COOP_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_COOP_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!targetPlayer.isOnline()) {\n            Message.INVALID_PLAYER.send(superiorPlayer, args[1]);\n            return;\n        }\n\n        if (island.isMember(targetPlayer)) {\n            Message.ALREADY_IN_ISLAND_OTHER.send(superiorPlayer);\n            return;\n        }\n\n        if (island.isCoop(targetPlayer)) {\n            Message.PLAYER_ALREADY_COOP.send(superiorPlayer);\n            return;\n        }\n\n        if (island.isBanned(targetPlayer)) {\n            Message.COOP_BANNED_PLAYER.send(superiorPlayer);\n            return;\n        }\n\n        int coopLimit = island.getCoopLimit();\n        if (coopLimit >= 0 && island.getCoopPlayers().size() >= coopLimit) {\n            Message.COOP_LIMIT_EXCEED.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandCoopPlayerEvent(island, superiorPlayer, targetPlayer))\n            return;\n\n        island.addCoop(targetPlayer);\n\n        IslandUtils.sendMessage(island, Message.COOP_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName());\n\n        if (island.getName().isEmpty())\n            Message.JOINED_ISLAND_AS_COOP.send(targetPlayer, superiorPlayer.getName());\n        else\n            Message.JOINED_ISLAND_AS_COOP_NAME.send(targetPlayer, island.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer ->\n                        !island.isMember(onlinePlayer) && !island.isBanned(onlinePlayer) && !island.isCoop(onlinePlayer))\n                : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoops.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdCoops implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"coops\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.coops\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"coops\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_COOPS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        plugin.getMenus().openCoops(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCounts.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdCounts implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"counts\", \"blocks\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.counts\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"counts [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_COUNTS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = (args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) :\n                CommandArguments.getIsland(plugin, sender, args[1])).getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        plugin.getMenus().openCounts(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1],\n                plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandNames;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdCreate implements ISuperiorCommand {\n\n    private final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"create\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.create\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        StringBuilder usage = new StringBuilder(\"create\");\n\n        if (plugin.getSettings().getIslandNames().isRequiredForCreation())\n            usage.append(\" <\").append(Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale)).append(\">\");\n\n        if (plugin.getSettings().isSchematicNameArgument())\n            usage.append(\" [\").append(Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale)).append(\"]\");\n\n        return usage.toString();\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_CREATE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        int args = 3;\n\n        if (!plugin.getSettings().getIslandNames().isRequiredForCreation())\n            args--;\n\n        if (!plugin.getSettings().isSchematicNameArgument())\n            args--;\n\n        return args;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (superiorPlayer.getIsland() != null) {\n            Message.ALREADY_IN_ISLAND.send(superiorPlayer);\n            return;\n        }\n\n        if (plugin.getGrid().hasActiveCreateRequest(superiorPlayer)) {\n            Message.ISLAND_CREATE_PROCESS_FAIL.send(superiorPlayer);\n            return;\n        }\n\n        String islandName = \"\";\n        Schematic schematic = null;\n\n        if (plugin.getSettings().getIslandNames().isRequiredForCreation()) {\n            if (args.length >= 2) {\n                islandName = args[1];\n                if (!IslandNames.isValidName(sender, null, islandName))\n                    return;\n            }\n        }\n\n        if (plugin.getSettings().isSchematicNameArgument() &&\n                args.length == (plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2)) {\n            schematic = CommandArguments.getSchematic(plugin, sender,\n                    args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]);\n\n            if (schematic == null)\n                return;\n        }\n\n        if (schematic == null) {\n            plugin.getMenus().openIslandCreation(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), islandName);\n        } else {\n            MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(schematic);\n            MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView());\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        int argumentLength = plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2;\n        return plugin.getSettings().isSchematicNameArgument() && args.length == argumentLength ?\n                CommandTabCompletes.getSchematics(plugin, args[argumentLength - 1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.warp.SignWarp;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdDelWarp implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"delwarp\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.delwarp\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"delwarp <\" + Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + \"...>\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_DEL_WARP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.DELETE_WARP;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_DELETE_WARP_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        Player player = superiorPlayer.asPlayer();\n        IslandWarp islandWarp = CommandArguments.getWarp(player, island, args, 1);\n\n        if (islandWarp == null)\n            return;\n\n        if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp))\n            return;\n\n        island.deleteWarp(islandWarp.getName());\n        Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName());\n\n        SignWarp.trySignWarpBreak(islandWarp, player);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getIslandWarps(island, args[1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdDemote implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"demote\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.demote\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"demote <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_DEMOTE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.DEMOTE_MEMBERS;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_DEMOTE_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!island.isMember(targetPlayer)) {\n            Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer);\n            return;\n        }\n\n        if (!targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) {\n            Message.DEMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer);\n            return;\n        }\n\n        PlayerRole previousRole = targetPlayer.getPlayerRole();\n        int roleLimit;\n\n        do {\n            previousRole = previousRole.getPreviousRole();\n            roleLimit = previousRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(previousRole);\n        } while (previousRole != null && !previousRole.isFirstRole() && roleLimit >= 0 && roleLimit >= island.getIslandMembers(previousRole).size());\n\n        if (previousRole == null) {\n            Message.LAST_ROLE_DEMOTE.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole))\n            return;\n\n        targetPlayer.setPlayerRole(previousRole);\n\n        Message.DEMOTED_MEMBER.send(superiorPlayer, targetPlayer.getName(), targetPlayer.getPlayerRole());\n        Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getIslandMembers(island, args[1], islandMember ->\n                islandMember.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()) &&\n                        islandMember.getPlayerRole().getPreviousRole() != null) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\n\nimport java.math.BigDecimal;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdDisband implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"disband\", \"reset\", \"delete\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.disband\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"disband\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_DISBAND.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.DISBAND_ISLAND;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_DISBAND_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (!superiorPlayer.hasDisbands() && plugin.getSettings().getDisbandCount() >= 0) {\n            Message.NO_MORE_DISBANDS.send(superiorPlayer);\n            return;\n        }\n\n        if (plugin.getSettings().isDisbandConfirm()) {\n            plugin.getMenus().openConfirmDisband(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n        } else if (PluginEventsFactory.callIslandDisbandEvent(island, superiorPlayer)) {\n            IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName());\n\n            Message.DISBANDED_ISLAND.send(superiorPlayer);\n\n            if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) {\n                BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund();\n                Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), Formatters.NUMBER_FORMATTER.format(\n                        island.getIslandBank().getBalance().multiply(disbandRefund)));\n            }\n\n            if (plugin.getSettings().getDisbandCount() >= 0) {\n                superiorPlayer.setDisbands(superiorPlayer.getDisbands() - 1);\n            }\n\n            island.disbandIsland();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdExpel implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"expel\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.expel\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"expel <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_EXPEL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.EXPEL_PLAYERS;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_EXPEL_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island playerIsland, String[] args) {\n        CommandSender sender = superiorPlayer == null ? Bukkit.getConsoleSender() : superiorPlayer.asPlayer();\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[1]);\n\n        if (targetPlayer == null || sender == null)\n            return;\n\n        Player target = targetPlayer.asPlayer();\n\n        if (target == null) {\n            Message.INVALID_PLAYER.send(sender, args[1]);\n            return;\n        }\n\n        Island targetIsland;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            targetIsland = plugin.getGrid().getIslandAt(target.getLocation(wrapper.getHandle()));\n        }\n\n        if (targetIsland == null) {\n            Message.PLAYER_NOT_INSIDE_ISLAND.send(sender);\n            return;\n        }\n\n        // Checking requirements for players\n        if (superiorPlayer != null) {\n            if (!targetIsland.equals(playerIsland)) {\n                Message.PLAYER_NOT_INSIDE_ISLAND.send(sender);\n                return;\n            }\n\n            if (targetIsland.hasPermission(targetPlayer, IslandPrivileges.EXPEL_BYPASS)) {\n                Message.PLAYER_EXPEL_BYPASS.send(sender);\n                return;\n            }\n        }\n\n        targetPlayer.teleport(plugin.getGrid().getSpawnIsland());\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            target.getLocation(wrapper.getHandle()).setDirection(plugin.getGrid().getSpawnIsland()\n                    .getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getDirection());\n        }\n        Message.EXPELLED_PLAYER.send(sender, targetPlayer.getName());\n        Message.GOT_EXPELLED.send(targetPlayer, sender.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (args.length != 2)\n            return Collections.emptyList();\n\n        if (island != null)\n            return CommandTabCompletes.getIslandVisitors(island, args[1], plugin.getSettings().isTabCompleteHideVanished());\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(),\n                    onlinePlayer -> plugin.getGrid().getIslandAt(onlinePlayer.getLocation(wrapper.getHandle())) != null);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdFly implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"fly\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.fly\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"fly\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_FLY.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (!PluginEventsFactory.callPlayerToggleFlyEvent(superiorPlayer))\n            return;\n\n        Player player = (Player) sender;\n\n        if (superiorPlayer.hasIslandFlyEnabled()) {\n            player.setAllowFlight(false);\n            player.setFlying(false);\n\n            Message.TOGGLED_FLY_OFF.send(superiorPlayer);\n        } else {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) {\n                player.setAllowFlight(true);\n                player.setFlying(true);\n            }\n\n            Message.TOGGLED_FLY_ON.send(superiorPlayer);\n        }\n\n        superiorPlayer.toggleIslandFly();\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.CommandsHelper;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class CmdHelp implements ISuperiorCommand {\n\n    private static final Int2ObjectMapView<List<SuperiorCommand>> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap();\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdHelp::onCommandsRefresh);\n        dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdHelp::onCommandsRefresh);\n    }\n\n    private static void onCommandsRefresh() {\n        commandsPerPageCache.clear();\n    }\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"help\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.help\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"help [\" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_HELP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        int page = 1;\n\n        if (args.length == 2) {\n            try {\n                page = Integer.parseInt(args[1]);\n            } catch (IllegalArgumentException ex) {\n                Message.INVALID_AMOUNT.send(sender, args[1]);\n                return;\n            }\n        }\n\n        if (page <= 0) {\n            Message.INVALID_AMOUNT.send(sender, page);\n            return;\n        }\n\n        List<SuperiorCommand> subCommands = new SequentialListBuilder<SuperiorCommand>()\n                .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender))\n                .build(plugin.getCommands().getSubCommands());\n\n        if (subCommands.isEmpty()) {\n            Message.NO_COMMAND_PERMISSION.send(sender, getPermission());\n            return;\n        }\n\n        int commandsPerPageCount = plugin.getSettings().getCommandsPerPage();\n\n        int lastPage;\n        if (commandsPerPageCount > 0) {\n            lastPage = subCommands.size() / commandsPerPageCount;\n            if (subCommands.size() % commandsPerPageCount != 0) lastPage++;\n        } else {\n            lastPage = 1;\n        }\n\n        if (page > lastPage) {\n            Message.INVALID_AMOUNT.send(sender, page);\n            return;\n        }\n\n        Message.ISLAND_HELP_HEADER.send(sender, page, lastPage);\n\n        java.util.Locale locale = PlayerLocales.getLocale(sender);\n\n        List<SuperiorCommand> commandsOfPage;\n        if (commandsPerPageCount > 0) {\n            commandsOfPage = commandsPerPageCache.get(page);\n            if (commandsOfPage == null) {\n                commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount));\n                commandsPerPageCache.put(page, commandsOfPage);\n            }\n        } else {\n            commandsOfPage = subCommands;\n        }\n\n        for (SuperiorCommand subCommand : commandsOfPage) {\n            String description = subCommand.getDescription(locale);\n            if (description == null)\n                new NullPointerException(\"The description of the command \" + subCommand.getAliases().get(0) + \" is null.\").printStackTrace();\n            Message.ISLAND_HELP_LINE.send(sender, plugin.getCommands().getLabel() + \" \" + subCommand.getUsage(locale), description == null ? \"\" : description);\n        }\n\n        if (page != lastPage)\n            Message.ISLAND_HELP_NEXT_PAGE.send(sender, page + 1);\n        else\n            Message.ISLAND_HELP_FOOTER.send(sender);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args.length != 2)\n            return Collections.emptyList();\n\n        List<String> list = new LinkedList<>();\n\n        List<SuperiorCommand> subCommands = new SequentialListBuilder<SuperiorCommand>()\n                .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender))\n                .build(plugin.getCommands().getSubCommands());\n\n        int commandsPerPageCount = plugin.getSettings().getCommandsPerPage();\n\n        int lastPage;\n        if (commandsPerPageCount > 0) {\n            lastPage = subCommands.size() / commandsPerPageCount;\n            if (subCommands.size() % commandsPerPageCount != 0) lastPage++;\n        } else {\n            lastPage = 1;\n        }\n\n        for (int i = 1; i <= lastPage; i++)\n            list.add(i + \"\");\n\n        return Collections.unmodifiableList(list);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdInvite implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"invite\", \"add\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.invite\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"invite <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_INVITE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.INVITE_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_INVITE_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (island.isMember(targetPlayer)) {\n            Message.ALREADY_IN_ISLAND_OTHER.send(superiorPlayer);\n            return;\n        }\n\n        if (island.isBanned(targetPlayer)) {\n            Message.INVITE_BANNED_PLAYER.send(superiorPlayer);\n            return;\n        }\n\n        Message announcementMessage;\n\n        if (island.isInvited(targetPlayer)) {\n            island.revokeInvite(targetPlayer);\n            announcementMessage = Message.REVOKE_INVITE_ANNOUNCEMENT;\n            Message.GOT_REVOKED.send(targetPlayer, superiorPlayer.getName());\n        } else {\n            int teamLimit = island.getTeamLimit();\n            if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) {\n                Message.INVITE_TO_FULL_ISLAND.send(superiorPlayer);\n                return;\n            }\n\n            if (!PluginEventsFactory.callIslandInviteEvent(island, superiorPlayer, targetPlayer))\n                return;\n\n            island.inviteMember(targetPlayer);\n            announcementMessage = Message.INVITE_ANNOUNCEMENT;\n\n            Message.GOT_INVITE.send(targetPlayer, superiorPlayer.getName());\n        }\n\n        IslandUtils.sendMessage(island, announcementMessage, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> !island.isMember(onlinePlayer)) :\n                Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdKick.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdKick implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"kick\", \"remove\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.kick\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"kick <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_KICK.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.KICK_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_KICK_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!IslandUtils.checkKickRestrictions(superiorPlayer, island, targetPlayer))\n            return;\n\n        if (plugin.getSettings().isKickConfirm()) {\n            plugin.getMenus().openConfirmKick(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island, targetPlayer);\n        } else {\n            IslandUtils.handleKickPlayer(superiorPlayer, island, targetPlayer);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getIslandMembersWithLowerRole(island, args[1], superiorPlayer.getPlayerRole()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLang.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdLang implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"lang\", \"language\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.lang\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"lang\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_LANG.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        plugin.getMenus().openPlayerLanguage(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()));\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.player.inventory.ClearActions;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdLeave implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"leave\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.leave\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"leave\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_LEAVE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        if (superiorPlayer.getPlayerRole().getNextRole() == null) {\n            Message.LEAVE_ISLAND_AS_LEADER.send(superiorPlayer);\n            return;\n        }\n\n        if (plugin.getSettings().isLeaveConfirm()) {\n            plugin.getMenus().openConfirmLeave(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()));\n        } else {\n            IslandUtils.handleLeaveIsland(superiorPlayer, island);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdMembers implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"members\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.members\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"members\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_MEMBERS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        plugin.getMenus().openMembers(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandNames;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdName implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"name\", \"setname\", \"rename\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.name\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"name <\" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_NAME.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.CHANGE_NAME;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_NAME_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        PluginEvent<PluginEventArgs.IslandRename> event = PluginEventsFactory.callIslandRenameEvent(island, superiorPlayer, args[1]);\n\n        if (event.isCancelled())\n            return;\n\n        String islandName = event.getArgs().islandName;\n\n        if (!IslandNames.isValidName(superiorPlayer, island, islandName))\n            return;\n\n        island.setName(islandName);\n\n        String coloredName = island.getName();\n\n        IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT, superiorPlayer.getName(), coloredName);\n        Message.CHANGED_NAME.send(superiorPlayer, coloredName);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdOpen implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"open\", \"unlock\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.open\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"open\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_OPEN.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.OPEN_ISLAND;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_OPEN_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (!island.isLocked()) {\n            Message.ISLAND_ALREADY_OPENED.send(superiorPlayer);\n        } else if (PluginEventsFactory.callIslandOpenEvent(island, superiorPlayer)) {\n            island.setLocked(false);\n            Message.ISLAND_OPENED.send(superiorPlayer);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class CmdPanel implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"panel\", \"manager\", \"cp\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.panel\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"panel [members/visitors] [toggle]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_PANEL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        if (args.length > 1) {\n            if (args[1].equalsIgnoreCase(\"members\")) {\n                plugin.getCommands().dispatchSubCommand(sender, \"members\");\n                return;\n            } else if (args[1].equalsIgnoreCase(\"visitors\")) {\n                plugin.getCommands().dispatchSubCommand(sender, \"visitors\");\n                return;\n            } else if (args[1].equalsIgnoreCase(\"toggle\")) {\n                if (!PluginEventsFactory.callPlayerTogglePanelEvent(superiorPlayer))\n                    return;\n\n                if (superiorPlayer.hasToggledPanel()) {\n                    superiorPlayer.setToggledPanel(false);\n                    Message.PANEL_TOGGLE_OFF.send(superiorPlayer);\n                } else {\n                    superiorPlayer.setToggledPanel(true);\n                    Message.PANEL_TOGGLE_ON.send(superiorPlayer);\n                }\n                return;\n            }\n        }\n\n        plugin.getMenus().openControlPanel(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args.length != 2)\n            return Collections.emptyList();\n\n        List<String> extraArgument = new LinkedList<>();\n        extraArgument.add(\"toggle\");\n        if (!(sender instanceof Player)) {\n            extraArgument.add(\"visitors\");\n            extraArgument.add(\"members\");\n        } else {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n            if (superiorPlayer.hasPermission(\"superior.island.visitors\"))\n                extraArgument.add(\"visitors\");\n            if (superiorPlayer.hasPermission(\"superior.island.members\"))\n                extraArgument.add(\"members\");\n        }\n\n        return CommandTabCompletes.getCustomComplete(args[1], extraArgument);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdPardon implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"pardon\", \"unban\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.pardon\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"pardon <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_PARDON.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.BAN_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_BAN_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!island.isBanned(targetPlayer)) {\n            Message.PLAYER_NOT_BANNED.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandUnbanEvent(island, superiorPlayer, targetPlayer))\n            return;\n\n        island.unbanMember(targetPlayer);\n\n        IslandUtils.sendMessage(island, Message.UNBAN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName(), superiorPlayer.getName());\n\n        Message.GOT_UNBANNED.send(targetPlayer, island.getOwner().getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getIslandBannedPlayers(island, args[1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdPermissions implements IPermissibleCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"permissions\", \"perms\", \"setpermission\", \"setperm\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.permissions\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        if (plugin.getSettings().isEditPlayerPermissions()) {\n            return \"permissions [\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"] [reset]\";\n        } else {\n            return \"permissions [reset]\";\n        }\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_PERMISSIONS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return plugin.getSettings().isEditPlayerPermissions() ? 3 : 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_PERMISSION;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_PERMISSION_CHECK_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        Object permissionHolder = SPlayerRole.guestRole();\n\n        boolean setToDefault = (args.length == 2 ? args[1] : args.length == 3 ? args[2] : \"\").equalsIgnoreCase(\"reset\");\n\n        if (plugin.getSettings().isEditPlayerPermissions() && ((!setToDefault && args.length == 2) || args.length == 3)) {\n            SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[1]);\n\n            if (targetPlayer == null) {\n                Message.INVALID_PLAYER.send(superiorPlayer, args[1]);\n                return;\n            }\n\n            if (island.isMember(targetPlayer) && !superiorPlayer.getPlayerRole().isHigherThan(targetPlayer.getPlayerRole())) {\n                Message.CHANGE_PERMISSION_FOR_HIGHER_ROLE.send(superiorPlayer);\n                return;\n            }\n\n            permissionHolder = targetPlayer;\n        }\n\n        if (!setToDefault) {\n            if (permissionHolder instanceof PlayerRole) {\n                plugin.getMenus().openPermissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()),\n                        island, (PlayerRole) permissionHolder);\n            } else {\n                plugin.getMenus().openPermissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()),\n                        island, (SuperiorPlayer) permissionHolder);\n            }\n        } else {\n            if (permissionHolder instanceof PlayerRole) {\n                if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, superiorPlayer)) {\n                    island.resetPermissions();\n                    Message.PERMISSIONS_RESET_ROLES.send(superiorPlayer);\n                }\n            } else {\n                if (PluginEventsFactory.callIslandClearPlayerPrivilegesEvent(island, superiorPlayer, (SuperiorPlayer) permissionHolder)) {\n                    island.resetPermissions((SuperiorPlayer) permissionHolder);\n                    Message.PERMISSIONS_RESET_PLAYER.send(superiorPlayer, ((SuperiorPlayer) permissionHolder).getName());\n                }\n            }\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        List<String> tabVariables = new LinkedList<>();\n\n        if (args.length == 2) {\n            if (\"reset\".contains(args[1].toLowerCase(Locale.ENGLISH)))\n                tabVariables.add(\"reset\");\n            if (plugin.getSettings().isEditPlayerPermissions()) {\n                tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[1],\n                        plugin.getSettings().isTabCompleteHideVanished()));\n            }\n        } else if (plugin.getSettings().isEditPlayerPermissions() && args.length == 3) {\n            if (\"reset\".contains(args[2].toLowerCase(Locale.ENGLISH)))\n                tabVariables.add(\"reset\");\n        }\n\n        return Collections.unmodifiableList(tabVariables);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdPromote implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"promote\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.promote\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"promote <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_PROMOTE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.PROMOTE_MEMBERS;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_PROMOTE_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!island.isMember(targetPlayer)) {\n            Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer);\n            return;\n        }\n\n        PlayerRole playerRole = targetPlayer.getPlayerRole();\n\n        if (playerRole.isLastRole()) {\n            Message.LAST_ROLE_PROMOTE.send(superiorPlayer);\n            return;\n        }\n\n        if (!playerRole.isLessThan(superiorPlayer.getPlayerRole())) {\n            Message.PROMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer);\n            return;\n        }\n\n        PlayerRole nextRole = playerRole;\n        int roleLimit;\n\n        do {\n            nextRole = nextRole.getNextRole();\n            roleLimit = nextRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(nextRole);\n        } while (nextRole != null && !nextRole.isLastRole() && !nextRole.isHigherThan(superiorPlayer.getPlayerRole()) &&\n                roleLimit >= 0 && island.getIslandMembers(nextRole).size() >= roleLimit);\n\n        if (nextRole == null || nextRole.isLastRole()) {\n            Message.LAST_ROLE_PROMOTE.send(superiorPlayer);\n            return;\n        }\n\n        if (nextRole.isHigherThan(superiorPlayer.getPlayerRole())) {\n            Message.PROMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole))\n            return;\n\n        targetPlayer.setPlayerRole(nextRole);\n\n        Message.PROMOTED_MEMBER.send(superiorPlayer, targetPlayer.getName(), targetPlayer.getPlayerRole());\n        Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getIslandMembers(island, args[1], islandMember -> {\n            PlayerRole playerRole = islandMember.getPlayerRole();\n            PlayerRole nextRole = playerRole.getNextRole();\n            return nextRole != null && !nextRole.isLastRole() && playerRole.isLessThan(superiorPlayer.getPlayerRole()) &&\n                    !nextRole.isHigherThan(superiorPlayer.getPlayerRole());\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdRate implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"rate\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.rate\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"rate [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_RATE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender) :\n                CommandArguments.getIsland(plugin, sender, args[1]);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        if (island.isSpawn()) {\n            Message.INVALID_ISLAND_LOCATION.send(sender);\n            return;\n        }\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        RateResult rateResult = canRateIsland(plugin, superiorPlayer, island);\n\n        switch (rateResult) {\n            case RATE_OWN_ISLAND:\n                Message.RATE_OWN_ISLAND.send(superiorPlayer);\n                return;\n            case ALREADY_RATED:\n                Message.RATE_ALREADY_GIVEN.send(superiorPlayer);\n                return;\n        }\n\n        plugin.getMenus().openIslandRate(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        Island island = superiorPlayer.getIsland();\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) ->\n                        canRateIsland(plugin, superiorPlayer, island, onlineIsland) == RateResult.SUCCESS) :\n                Collections.emptyList();\n    }\n\n    private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island) {\n        return canRateIsland(plugin, superiorPlayer, superiorPlayer.getIsland(), island);\n    }\n\n    private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer,\n                                            Island playerIsland, Island island) {\n        if (!plugin.getSettings().isRateOwnIsland() && island.equals(playerIsland)) {\n            return RateResult.RATE_OWN_ISLAND;\n        }\n\n        if (!plugin.getSettings().isChangeIslandRating() && island.getRating(superiorPlayer) != Rating.UNKNOWN) {\n            return RateResult.ALREADY_RATED;\n        }\n\n        return RateResult.SUCCESS;\n    }\n\n    private enum RateResult {\n\n        SUCCESS,\n        RATE_OWN_ISLAND,\n        ALREADY_RATED\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRatings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdRatings implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"ratings\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.ratings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"ratings\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_RATINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.RATINGS_SHOW;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_RATINGS_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        plugin.getMenus().openIslandRatings(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRecalc.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdRecalc implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"recalc\", \"recalculate\", \"level\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.recalc\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"recalc\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_RECALC.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        if (island.isBeingRecalculated()) {\n            Message.RECALC_ALREADY_RUNNING.send(superiorPlayer);\n            return;\n        }\n\n        Message.RECALC_PROCCESS_REQUEST.send(superiorPlayer);\n        island.calcIslandWorth(superiorPlayer);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdSetDiscord implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setdiscord\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.setdiscord\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"setdiscord <\" + Message.COMMAND_ARGUMENT_DISCORD.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SET_DISCORD.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_DISCORD;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_DISCORD_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        String discord = CommandArguments.buildLongString(args, 1, false);\n\n        PluginEvent<PluginEventArgs.IslandChangeDiscord> event = PluginEventsFactory.callIslandChangeDiscordEvent(island, superiorPlayer, discord);\n\n        if (event.isCancelled())\n            return;\n\n        island.setDiscord(event.getArgs().discord);\n        Message.CHANGED_DISCORD.send(superiorPlayer, event.getArgs().discord);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdSetPaypal implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setpaypal\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.setpaypal\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"setpaypal <\" + Message.COMMAND_ARGUMENT_EMAIL.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SET_PAYPAL.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_PAYPAL;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_PAYPAL_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        PluginEvent<PluginEventArgs.IslandChangePaypal> event = PluginEventsFactory.callIslandChangePaypalEvent(island, superiorPlayer, args[1]);\n\n        if (event.isCancelled())\n            return;\n\n        island.setPaypal(event.getArgs().paypal);\n        Message.CHANGED_PAYPAL.send(superiorPlayer, event.getArgs().paypal);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdSetRole implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setrole\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.setrole\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"setrole <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SET_ROLE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_ROLE;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_ROLE_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island playerIsland, String[] args) {\n        CommandSender sender = superiorPlayer == null ? Bukkit.getConsoleSender() : superiorPlayer.asPlayer();\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[1]);\n\n        if (targetPlayer == null || sender == null)\n            return;\n\n        if (targetPlayer.getName().equals(sender.getName())) {\n            Message.SELF_ROLE_CHANGE.send(sender);\n            return;\n        }\n\n        PlayerRole playerRole = CommandArguments.getPlayerRoleFromLadder(sender, args[2]);\n        if (playerRole == null)\n            return;\n\n        Island targetIsland = targetPlayer.getIsland();\n\n        // Checking requirements for players\n        if (superiorPlayer != null) {\n            if (!playerIsland.isMember(targetPlayer)) {\n                Message.PLAYER_NOT_INSIDE_ISLAND.send(sender);\n                return;\n            }\n\n            targetIsland = playerIsland;\n\n            if (targetPlayer.getPlayerRole().isHigherThan(superiorPlayer.getPlayerRole()) ||\n                    !playerRole.isLessThan(superiorPlayer.getPlayerRole())) {\n                Message.CANNOT_SET_ROLE.send(sender, playerRole);\n                return;\n            }\n        } else {\n            if (targetIsland == null) {\n                Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName());\n                return;\n            }\n\n            if (playerRole.isLastRole()) {\n                Message.CANNOT_SET_ROLE.send(sender, playerRole);\n                return;\n            }\n        }\n\n        if (targetPlayer.getPlayerRole().equals(playerRole)) {\n            Message.PLAYER_ALREADY_IN_ROLE.send(sender, targetPlayer.getName(), playerRole);\n            return;\n        }\n\n        int roleLimit = targetIsland.getRoleLimit(playerRole);\n\n        if (roleLimit >= 0 && targetIsland.getIslandMembers(playerRole).size() >= roleLimit) {\n            Message.CANNOT_SET_ROLE.send(sender, playerRole);\n            return;\n        }\n\n        PlayerRole currentRole = targetPlayer.getPlayerRole();\n\n        if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, playerRole))\n            return;\n\n        targetPlayer.setPlayerRole(playerRole);\n\n        if (currentRole.isLessThan(playerRole)) {\n            Message.PROMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole());\n            Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n        } else {\n            Message.DEMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole());\n            Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole());\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? island == null ?\n                CommandTabCompletes.getOnlinePlayers(plugin, args[1], false, onlinePlayer -> onlinePlayer.getIsland() != null) :\n                CommandTabCompletes.getIslandMembers(island, args[1]) :\n                args.length == 3 ? CommandTabCompletes.getPlayerRoles(plugin, args[2], PlayerRole::isRoleLadder) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.Location;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class CmdSetTeleport implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"setteleport\", \"settp\", \"setgo\", \"sethome\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.setteleport\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"setteleport\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SET_TELEPORT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_HOME;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_HOME_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location newLocation = superiorPlayer.getLocation(wrapper.getHandle());\n\n            if (!island.isInsideRange(newLocation)) {\n                Message.TELEPORT_LOCATION_OUTSIDE_ISLAND.send(superiorPlayer);\n                return;\n            }\n\n            PluginEvent<PluginEventArgs.IslandSetHome> event = PluginEventsFactory.callIslandSetHomeEvent(\n                    island, superiorPlayer, newLocation, IslandSetHomeEvent.Reason.SET_HOME_COMMAND);\n\n            if (event.isCancelled())\n                return;\n\n            island.setIslandHome(event.getArgs().islandHome);\n        }\n\n        Message.CHANGED_TELEPORT_LOCATION.send(superiorPlayer);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdSetWarp implements IPermissibleCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setwarp\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.setwarp\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        StringBuilder usage = new StringBuilder(\"setwarp <\")\n                .append(Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale)).append(\">\");\n\n        if (plugin.getSettings().isWarpCategories())\n            usage.append(\" [\").append(Message.COMMAND_ARGUMENT_WARP_CATEGORY.getMessage(locale)).append(\"]\");\n\n        return usage.toString();\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SET_WARP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return plugin.getSettings().isWarpCategories() ? 3 : 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_WARP;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_WARP_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        int warpsLimit = island.getWarpsLimit();\n        if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) {\n            Message.NO_MORE_WARPS.send(superiorPlayer);\n            return;\n        }\n\n        String warpName = args[1];\n\n        if (warpName.isEmpty()) {\n            Message.WARP_ILLEGAL_NAME.send(superiorPlayer);\n            return;\n        }\n\n        if (!IslandUtils.isWarpNameLengthValid(warpName)) {\n            Message.WARP_NAME_TOO_LONG.send(superiorPlayer);\n            return;\n        }\n\n        if (island.getWarp(warpName) != null) {\n            Message.WARP_ALREADY_EXIST.send(superiorPlayer);\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (!island.isInsideRange(superiorPlayer.getLocation(wrapper.getHandle()))) {\n                Message.SET_WARP_OUTSIDE.send(superiorPlayer);\n                return;\n            }\n        }\n\n        String categoryName = null;\n\n        if (args.length == 3) {\n            categoryName = args[2];\n\n            if (categoryName.isEmpty()) {\n                Message.WARP_CATEGORY_ILLEGAL_NAME.send(superiorPlayer);\n                return;\n            }\n\n            if (!IslandUtils.isWarpNameLengthValid(categoryName)) {\n                Message.WARP_CATEGORY_NAME_TOO_LONG.send(superiorPlayer);\n                return;\n            }\n\n            if (island.getWarpCategory(categoryName) == null &&\n                    !PluginEventsFactory.callIslandCreateWarpCategoryEvent(island, superiorPlayer, categoryName))\n                return;\n        }\n\n        WarpCategory warpCategory = categoryName == null ? null : island.createWarpCategory(categoryName);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location warpLocation = superiorPlayer.getLocation(wrapper.getHandle());\n\n            Preconditions.checkState(warpLocation != null, \"Null location for a warp.\");\n\n            if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, warpCategory))\n                return;\n\n            island.createWarp(warpName, warpLocation, warpCategory);\n\n            Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdSettings implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"settings\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.settings\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"settings [reset]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SETTINGS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.SET_SETTINGS;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_SET_SETTINGS_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        if (args.length == 2 && args[1].equalsIgnoreCase(\"reset\")) {\n            if (PluginEventsFactory.callIslandClearFlagsEvent(island, superiorPlayer)) {\n                island.resetSettings();\n                Message.SETTINGS_RESET_SELF.send(superiorPlayer);\n            }\n            return;\n        }\n\n        plugin.getMenus().openSettings(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], \"reset\") : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CmdShow implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"show\", \"info\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.show\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"show [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_SHOW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender).getIsland() :\n                CommandArguments.getIsland(plugin, sender, args[1]).getIsland();\n\n        if (island == null)\n            return;\n\n        java.util.Locale locale = PlayerLocales.getLocale(sender);\n\n        StringBuilder infoMessage = new StringBuilder();\n\n        if (!Message.ISLAND_INFO_HEADER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_HEADER.getMessage(locale)).append(\"\\n\");\n        if (!Message.ISLAND_INFO_OWNER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_OWNER.getMessage(locale, island.getOwner().getName())).append(\"\\n\");\n        if (!Message.ISLAND_INFO_NAME.isEmpty(locale) && !island.getName().isEmpty())\n            infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append(\"\\n\");\n        if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) {\n            WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension());\n            infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale,\n                    Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append(\"\\n\");\n        }\n        if (!Message.ISLAND_INFO_CREATION_TIME.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_CREATION_TIME.getMessage(locale, island.getCreationTimeDate())).append(\"\\n\");\n        if (!Message.ISLAND_INFO_RATE.isEmpty(locale)) {\n            double rating = island.getTotalRating();\n            infoMessage.append(Message.ISLAND_INFO_RATE.getMessage(locale, Formatters.RATING_FORMATTER.format(rating, locale),\n                    Formatters.NUMBER_FORMATTER.format(rating), island.getRatingAmount())).append(\"\\n\");\n        }\n        if (BuiltinModules.BANK.isEnabled()) {\n            if (!Message.ISLAND_INFO_BANK.isEmpty(locale))\n                infoMessage.append(Message.ISLAND_INFO_BANK.getMessage(locale, island.getIslandBank().getBalance())).append(\"\\n\");\n        }\n        if (!Message.ISLAND_INFO_WORTH.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_WORTH.getMessage(locale, island.getWorth())).append(\"\\n\");\n        if (!Message.ISLAND_INFO_LEVEL.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append(\"\\n\");\n        if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !\"None\".equals(island.getDiscord()) && island.hasPermission(sender, IslandPrivileges.DISCORD_SHOW)) {\n            infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append(\"\\n\");\n        }\n        if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !\"None\".equals(island.getPaypal()) && island.hasPermission(sender, IslandPrivileges.PAYPAL_SHOW)) {\n            infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append(\"\\n\");\n        }\n        if (!Message.ISLAND_INFO_VISITORS_COUNT.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_VISITORS_COUNT.getMessage(locale, island.getIslandVisitors(false).size(), island.getUniqueVisitorsWithTimes().size())).append(\"\\n\");\n\n        if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) {\n            Map<PlayerRole, StringBuilder> rolesStrings = new ArrayMap<>();\n            plugin.getRoles().getRoles().stream().filter(playerRole -> playerRole.isRoleLadder() && !playerRole.isLastRole())\n                    .forEach(playerRole -> rolesStrings.put(playerRole, new StringBuilder()));\n\n            List<SuperiorPlayer> members = island.getIslandMembers(false);\n\n            if (!Message.ISLAND_INFO_PLAYER_LINE.isEmpty(locale)) {\n                members.forEach(superiorPlayer -> {\n                    try {\n                        rolesStrings.get(superiorPlayer.getPlayerRole())\n                                .append(Message.ISLAND_INFO_PLAYER_LINE.getMessage(locale, superiorPlayer.getName())).append(\"\\n\");\n                    } catch (NullPointerException ex) {\n                        Log.warn(\"It seems like \", superiorPlayer.getName(), \" isn't part of the island of \"\n                                , island.getOwner().getName(), \".\");\n                    }\n                });\n            }\n\n            rolesStrings.keySet().stream()\n                    .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight)))\n                    .forEach(playerRole -> {\n                        StringBuilder players = rolesStrings.get(playerRole);\n                        if (players != null && players.length() > 0)\n                            infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players));\n                    });\n        }\n\n        if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale))\n            infoMessage.append(Message.ISLAND_INFO_FOOTER.getMessage(locale));\n\n        Message.CUSTOM.send(sender, infoMessage.toString(), false);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1],\n                plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeam.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CmdTeam implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"team\", \"showteam\", \"online\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.team\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"team [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TEAM.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island island = (args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) :\n                CommandArguments.getIsland(plugin, sender, args[1])).getIsland();\n\n        if (island == null)\n            return;\n\n        BukkitExecutor.async(() -> {\n            java.util.Locale locale = PlayerLocales.getLocale(sender);\n            StringBuilder infoMessage = new StringBuilder();\n\n            if (!Message.ISLAND_TEAM_STATUS_HEADER.isEmpty(locale)) {\n                infoMessage.append(Message.ISLAND_TEAM_STATUS_HEADER.getMessage(locale, island.getOwner().getName(),\n                        island.getIslandMembers(true).size(), island.getTeamLimit())).append(\"\\n\");\n            }\n\n            List<SuperiorPlayer> members = island.getIslandMembers(true);\n\n            if (!Message.ISLAND_TEAM_STATUS_ROLES.isEmpty(locale)) {\n                Map<PlayerRole, StringBuilder> rolesStrings = new ArrayMap<>();\n                plugin.getRoles().getRoles().stream().filter(PlayerRole::isRoleLadder)\n                        .forEach(playerRole -> rolesStrings.put(playerRole, new StringBuilder()));\n                rolesStrings.put(SPlayerRole.lastRole(), new StringBuilder());\n\n                String onlineStatus = Message.ISLAND_TEAM_STATUS_ONLINE.getMessage(locale),\n                        offlineStatus = Message.ISLAND_TEAM_STATUS_OFFLINE.getMessage(locale);\n\n                members.forEach(islandMember -> {\n                    PlayerRole playerRole = islandMember.getPlayerRole();\n                    long time = islandMember.getLastTimeStatus() == -1 ? -1 : ((System.currentTimeMillis() / 1000) - islandMember.getLastTimeStatus());\n                    boolean onlinePlayer = islandMember.isOnline() && islandMember.isShownAsOnline();\n                    rolesStrings.get(playerRole).append(Message.ISLAND_TEAM_STATUS_ROLES.getMessage(locale, playerRole,\n                            islandMember.getName(), onlinePlayer ? onlineStatus : offlineStatus,\n                            Formatters.TIME_FORMATTER.format(Duration.ofSeconds(time), locale))).append(\"\\n\");\n                });\n\n                rolesStrings.keySet().stream()\n                        .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight)))\n                        .forEach(playerRole -> infoMessage.append(rolesStrings.get(playerRole)));\n            }\n\n            if (!Message.ISLAND_TEAM_STATUS_FOOTER.isEmpty(locale))\n                infoMessage.append(Message.ISLAND_TEAM_STATUS_FOOTER.getMessage(locale));\n\n            Message.CUSTOM.send(sender, infoMessage.toString(), false);\n        });\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1],\n                plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdTeamChat implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"teamchat\", \"chat\", \"tc\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.teamchat\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"teamchat [\" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TEAM_CHAT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return Integer.MAX_VALUE;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        if (args.length == 1) {\n            if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer))\n                return;\n\n            if (superiorPlayer.hasTeamChatEnabled()) {\n                Message.TOGGLED_TEAM_CHAT_OFF.send(superiorPlayer);\n            } else {\n                Message.TOGGLED_TEAM_CHAT_ON.send(superiorPlayer);\n            }\n\n            superiorPlayer.toggleTeamChat();\n        } else {\n            String message = CommandArguments.buildLongString(args, 1, false);\n            IslandUtils.handleIslandChat(island, superiorPlayer, message);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdTeleport implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"teleport\", \"tp\", \"go\", \"home\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.teleport\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"teleport\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TELEPORT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n        Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n\n        if (!PluginEventsFactory.callIslandHomeTeleportEvent(island, superiorPlayer, dimension))\n            return;\n\n        EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getHomeWarmup(),\n                unused -> teleportToIsland(superiorPlayer, island));\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n    private void teleportToIsland(SuperiorPlayer superiorPlayer, Island island) {\n        superiorPlayer.setTeleportTask(null);\n        superiorPlayer.teleport(island, result -> {\n            if (result)\n                Message.TELEPORTED_SUCCESS.send(superiorPlayer);\n            else\n                Message.TELEPORTED_FAILED.send(superiorPlayer);\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdToggle implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"toggle\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.toggle\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"toggle <border/blocks>\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TOGGLE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (args[1].equalsIgnoreCase(\"border\")) {\n            if (!superiorPlayer.hasPermission(\"superior.island.toggle.border\")) {\n                Message.NO_COMMAND_PERMISSION.send(sender, \"superior.island.toggle.border\");\n                return;\n            }\n\n            if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer))\n                return;\n\n            if (superiorPlayer.hasWorldBorderEnabled()) {\n                Message.TOGGLED_WORLD_BORDER_OFF.send(superiorPlayer);\n            } else {\n                Message.TOGGLED_WORLD_BORDER_ON.send(superiorPlayer);\n            }\n\n            superiorPlayer.toggleWorldBorder();\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                superiorPlayer.updateWorldBorder(plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())));\n            }\n        } else if (args[1].equalsIgnoreCase(\"blocks\")) {\n            if (!superiorPlayer.hasPermission(\"superior.island.toggle.blocks\")) {\n                Message.NO_COMMAND_PERMISSION.send(sender, \"superior.island.toggle.blocks\");\n                return;\n            }\n\n            if (!PluginEventsFactory.callPlayerToggleBlocksStackerEvent(superiorPlayer))\n                return;\n\n            if (superiorPlayer.hasBlocksStackerEnabled()) {\n                Message.TOGGLED_STACKED_BLOCKS_OFF.send(superiorPlayer);\n            } else {\n                Message.TOGGLED_STACKED_BLOCKS_ON.send(superiorPlayer);\n            }\n\n            superiorPlayer.toggleBlocksStacker();\n        } else {\n            Message.INVALID_TOGGLE_MODE.send(superiorPlayer, args[1]);\n        }\n\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], var ->\n                sender.hasPermission(\"superior.island.toggle.\" + var), \"border\", \"blocks\") : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdTop implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"top\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.top\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"top\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TOP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        plugin.getMenus().openTopIslands(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), SortingTypes.getIslandTopSorting());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdTransfer implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"transfer\", \"leader\", \"leadership\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.transfer\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"transfer <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_TRANSFER.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!IslandUtils.checkTransferRestrictions(superiorPlayer, island, targetPlayer))\n            return;\n\n        if (plugin.getSettings().isTransferConfirm()) {\n            plugin.getMenus().openConfirmTransfer(superiorPlayer, null, island, targetPlayer);\n        } else {\n            IslandUtils.handleTransferIsland(superiorPlayer, island, targetPlayer);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        Island island = superiorPlayer.getIsland();\n        return args.length == 2 && island != null && superiorPlayer.getPlayerRole().isLastRole() ?\n                CommandTabCompletes.getIslandMembers(island, args[1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdUncoop implements IPermissibleCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"uncoop\", \"untrust\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.uncoop\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"uncoop <\" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_UNCOOP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.UNCOOP_MEMBER;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_UNCOOP_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]);\n\n        if (targetPlayer == null)\n            return;\n\n        if (!island.isCoop(targetPlayer)) {\n            Message.PLAYER_NOT_COOP.send(superiorPlayer);\n            return;\n        }\n\n        if (!PluginEventsFactory.callIslandUncoopPlayerEvent(island, superiorPlayer, targetPlayer, IslandUncoopPlayerEvent.UncoopReason.PLAYER))\n            return;\n\n        island.removeCoop(targetPlayer);\n\n        IslandUtils.sendMessage(island, Message.UNCOOP_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName());\n\n        if (island.getName().isEmpty())\n            Message.LEFT_ISLAND_COOP.send(targetPlayer, superiorPlayer.getName());\n        else\n            Message.LEFT_ISLAND_COOP_NAME.send(targetPlayer, island.getName());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(), island::isCoop) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.CustomKey;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport org.bukkit.Material;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdValue implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"value\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.value\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"value [\" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_VALUE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        Key toCheck;\n        String keyName = \"\";\n\n        if (args.length == 1) {\n            ItemStack inHand = ((Player) sender).getItemInHand();\n\n            if (inHand == null) {\n                inHand = new ItemStack(Material.AIR);\n            }\n\n            toCheck = Keys.of(inHand);\n\n            if (inHand.getType() == Materials.SPAWNER.toBukkitType()) {\n                String subKey = toCheck.getSubKey();\n                if (!Text.isBlank(subKey))\n                    keyName = Formatters.CAPITALIZED_FORMATTER.format(subKey + \"_Spawner\");\n            }\n\n            if (keyName.isEmpty() && toCheck instanceof CustomKey) {\n                String subKey = toCheck.getSubKey();\n                if (Text.isBlank(subKey)) {\n                    keyName = Formatters.CAPITALIZED_FORMATTER.format(toCheck.toString());\n                } else {\n                    keyName = Formatters.CAPITALIZED_FORMATTER.format(subKey);\n                }\n            }\n\n        } else {\n            toCheck = Keys.ofMaterialAndData(args[1]);\n        }\n\n        if (keyName.isEmpty())\n            keyName = Formatters.CAPITALIZED_FORMATTER.format(toCheck.getGlobalKey());\n\n        java.util.Locale locale = superiorPlayer.getUserLocale();\n\n        StringBuilder stringBuilder = new StringBuilder();\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(toCheck);\n\n        {\n            BigDecimal blockWorth = blockValue.getWorth();\n            if (blockWorth.doubleValue() == 0) {\n                if (!Message.BLOCK_VALUE_WORTHLESS.isEmpty(locale))\n                    stringBuilder.append(Message.BLOCK_VALUE_WORTHLESS.getMessage(locale, keyName)).append(\"\\n\");\n            } else {\n                if (!Message.BLOCK_VALUE.isEmpty(locale))\n                    stringBuilder.append(Message.BLOCK_VALUE.getMessage(locale, keyName,\n                            Formatters.NUMBER_FORMATTER.format(blockWorth))).append(\"\\n\");\n            }\n        }\n\n        {\n            BigDecimal blockLevel = blockValue.getLevel();\n            if (blockLevel.doubleValue() == 0) {\n                if (!Message.BLOCK_LEVEL_WORTHLESS.isEmpty(locale)) {\n                    stringBuilder.append(Message.BLOCK_LEVEL_WORTHLESS.getMessage(locale, keyName)).append(\"\\n\");\n                }\n            } else {\n                if (!Message.BLOCK_LEVEL.isEmpty(locale))\n                    stringBuilder.append(Message.BLOCK_LEVEL.getMessage(locale, keyName,\n                            Formatters.NUMBER_FORMATTER.format(blockLevel))).append(\"\\n\");\n            }\n        }\n\n        Message.CUSTOM.send(superiorPlayer, stringBuilder.toString(), false);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getMaterials(args[1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValues.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdValues implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"values\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.values\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"values [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_VALUES.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) :\n                CommandArguments.getIsland(plugin, sender, args[1]);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        plugin.getMenus().openValues(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1],\n                plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport com.bgsoftware.superiorskyblock.world.WorldBlocks;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdVisit implements ISuperiorCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"visit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.visit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"visit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_VISIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        Island targetIsland = CommandArguments.getIsland(plugin, sender, args[1]).getIsland();\n\n        if (targetIsland == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n\n        if (!PluginEventsFactory.callIslandVisitorHomeTeleportEvent(targetIsland, superiorPlayer, dimension))\n            return;\n\n        IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, true, islandWorldResult ->\n                islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer)));\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1],\n                plugin.getSettings().isTabCompleteHideVanished(),\n                (onlinePlayer, onlineIsland) -> onlineIsland != null && (\n                        (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() ||\n                                onlineIsland.getVisitorsPosition(null /* unused */) != null) ||\n                                superiorPlayer.hasBypassModeEnabled()) && (!onlineIsland.isLocked() ||\n                        onlineIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS))) : Collections.emptyList();\n    }\n\n    private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer superiorPlayer) {\n        Location visitLocation;\n        boolean isVisitorSign;\n\n        if (plugin.getSettings().getVisitorsSign().isRequiredForVisit()) {\n            isVisitorSign = true;\n            visitLocation = targetIsland.getVisitorsLocation(null /* unused */);\n        } else {\n            isVisitorSign = false;\n            visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension());\n        }\n\n        if (visitLocation == null) {\n            Message.INVALID_VISIT_LOCATION.send(superiorPlayer);\n\n            if (!superiorPlayer.hasBypassModeEnabled())\n                return;\n\n            visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension());\n            Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer);\n        }\n\n        if (targetIsland.isLocked() && !targetIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) {\n            Message.NO_CLOSE_BYPASS.send(superiorPlayer);\n            return;\n        }\n\n        Location finalVisitLocation = visitLocation;\n\n        EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup ->\n                teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, isVisitorSign, afterWarmup /*checkIslandLock*/));\n    }\n\n    private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation,\n                                               boolean isVisitorSign, boolean checkIslandLock) {\n        if (visitLocation.getWorld() == null) {\n            IslandWorlds.accessIslandWorldAsync(island, visitLocation, true, islandWorldResult -> {\n                islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> {\n                    visitLocation.setWorld(world);\n                    teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock);\n                });\n            });\n        } else {\n            teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock);\n        }\n    }\n\n    private static void teleportPlayerNoWarmupWorldLoaded(SuperiorPlayer superiorPlayer, Island island, Location visitLocation,\n                                                          boolean isVisitorSign, boolean checkIslandLock) {\n        superiorPlayer.setTeleportTask(null);\n\n        if (checkIslandLock && island.isLocked() && !island.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) {\n            Message.NO_CLOSE_BYPASS.send(superiorPlayer);\n            return;\n        }\n\n        if (isVisitorSign && !WorldBlocks.isSafeBlock(visitLocation.getBlock())) {\n            Message.INVALID_VISIT_LOCATION.send(superiorPlayer);\n\n            if (!superiorPlayer.hasBypassModeEnabled()) {\n                if (PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer))\n                    island.setVisitorsLocation(null);\n                return;\n            }\n\n            Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer);\n        }\n\n        superiorPlayer.teleport(visitLocation);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdVisitors implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"visitors\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.visitors\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"visitors\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_VISITORS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        plugin.getMenus().openVisitors(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CmdWarp implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"warp\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.warp\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"warp [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"] [\" +\n                Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_WARP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        Island targetIsland = null;\n        String targetWarpName = null;\n\n        switch (args.length) {\n            case 1: {\n                IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n                targetIsland = arguments.getIsland();\n                break;\n            }\n            case 2: {\n                if (superiorPlayer.hasIsland()) {\n                    IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n                    targetIsland = arguments.getIsland();\n                    targetWarpName = args[1];\n                } else {\n                    IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]);\n                    targetIsland = arguments.getIsland();\n                }\n                break;\n            }\n            case 3: {\n                IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]);\n                targetIsland = arguments.getIsland();\n                targetWarpName = args[2];\n                break;\n            }\n        }\n\n        if (targetIsland == null)\n            return;\n\n        IslandWarp islandWarp = targetWarpName == null ? null : targetIsland.getWarp(targetWarpName);\n\n        if (islandWarp == null) {\n            switch (args.length) {\n                case 1:\n                    plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland);\n                    break;\n                case 2:\n                    IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]);\n                    targetIsland = arguments.getIsland();\n                    if (targetIsland != null) {\n                        plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland);\n                    }\n                    break;\n                case 3:\n                    Message.INVALID_WARP.send(superiorPlayer, targetWarpName);\n                    break;\n            }\n\n            return;\n        }\n\n        if (!targetIsland.isMember(superiorPlayer) && islandWarp.hasPrivateFlag()) {\n            Message.INVALID_WARP.send(superiorPlayer, targetWarpName);\n            return;\n        }\n\n        if (PluginEventsFactory.callIslandWarpTeleportEvent(targetIsland, superiorPlayer, islandWarp))\n            targetIsland.warpPlayer(superiorPlayer, targetWarpName);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        Island playerIsland = superiorPlayer.getIsland();\n\n        switch (args.length) {\n            case 2: {\n                List<String> tabCompletes = new LinkedList<>(CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], true,\n                        (player, island) -> island.getIslandWarps().values().stream().anyMatch(islandWarp ->\n                                island.isMember(superiorPlayer) || !islandWarp.hasPrivateFlag())));\n\n                if (playerIsland != null) {\n                    for (String warpName : playerIsland.getIslandWarps().keySet()) {\n                        if (warpName.startsWith(args[1]))\n                            tabCompletes.add(warpName);\n                    }\n                }\n\n                return tabCompletes.isEmpty() ? Collections.emptyList() : tabCompletes;\n            }\n            case 3: {\n                Island targetIsland = plugin.getGrid().getIsland(args[1]);\n                if (targetIsland != null) {\n                    return new SequentialListBuilder<Map.Entry<String, IslandWarp>>()\n                            .filter(islandWarpEntry -> targetIsland.isMember(superiorPlayer) || !islandWarpEntry.getValue().hasPrivateFlag())\n                            .map(targetIsland.getIslandWarps().entrySet(), Map.Entry::getKey);\n                }\n                break;\n            }\n        }\n\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarps.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdWarps implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"warps\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.warps\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"warps\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_WARPS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        plugin.getMenus().openGlobalWarps(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()));\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java",
    "content": "package com.bgsoftware.superiorskyblock.commands.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.CommandsMap;\n\npublic class PlayerCommandsMap extends CommandsMap {\n\n    public PlayerCommandsMap(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadDefaultCommands() {\n        clearCommands();\n\n        registerCommand(new CmdAccept());\n        registerCommand(new CmdAdmin());\n        registerCommand(new CmdBan());\n        registerCommand(new CmdBans());\n        registerCommand(new CmdBiome());\n        registerCommand(new CmdBorder());\n        registerCommand(new CmdChest());\n        registerCommand(new CmdClose());\n        if (plugin.getSettings().isCoopMembers()) {\n            registerCommand(new CmdCoop());\n            registerCommand(new CmdCoops());\n        }\n        registerCommand(new CmdCounts());\n        registerCommand(new CmdCreate());\n        registerCommand(new CmdDelWarp());\n        registerCommand(new CmdDemote());\n        registerCommand(new CmdDisband());\n        registerCommand(new CmdExpel());\n        registerCommand(new CmdFly());\n        registerCommand(new CmdHelp());\n        registerCommand(new CmdInvite());\n        registerCommand(new CmdKick());\n        registerCommand(new CmdLang());\n        registerCommand(new CmdLeave());\n        registerCommand(new CmdMembers());\n        registerCommand(new CmdName());\n        registerCommand(new CmdOpen());\n        registerCommand(new CmdPanel());\n        registerCommand(new CmdPardon());\n        registerCommand(new CmdPermissions());\n        registerCommand(new CmdPromote());\n        registerCommand(new CmdRate());\n        registerCommand(new CmdRatings());\n        registerCommand(new CmdRecalc());\n        registerCommand(new CmdSetDiscord());\n        registerCommand(new CmdSetPaypal());\n        registerCommand(new CmdSetRole());\n        registerCommand(new CmdSetTeleport());\n        registerCommand(new CmdSettings());\n        registerCommand(new CmdSetWarp());\n        registerCommand(new CmdShow());\n        registerCommand(new CmdTeam());\n        registerCommand(new CmdTeamChat());\n        registerCommand(new CmdTeleport());\n        registerCommand(new CmdToggle());\n        registerCommand(new CmdTop());\n        registerCommand(new CmdTransfer());\n        if (plugin.getSettings().isCoopMembers())\n            registerCommand(new CmdUncoop());\n        registerCommand(new CmdValue());\n        registerCommand(new CmdValues());\n        registerCommand(new CmdVisit());\n        registerCommand(new CmdVisitors());\n        registerCommand(new CmdWarp());\n        registerCommand(new CmdWarps());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.config;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.config.section.EntityCategoriesSection;\nimport com.bgsoftware.superiorskyblock.config.section.InteractablesSection;\nimport com.bgsoftware.superiorskyblock.config.section.WorldsSection;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.DateFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.NumberFormatter;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.io.Resources;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValuesManagerImpl;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.math.RoundingMode;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Collectors;\n\npublic class SettingsContainer {\n\n    public final String databaseType;\n    public final boolean databaseBackup;\n    public final String databaseMySQLAddress;\n    public final int databaseMySQLPort;\n    public final String databaseMySQLDBName;\n    public final String databaseMySQLUsername;\n    public final String databaseMySQLPassword;\n    public final String databaseMySQLPrefix;\n    public final boolean databaseMySQLSSL;\n    public final boolean databaseMySQLPublicKeyRetrieval;\n    public final long databaseMySQLWaitTimeout;\n    public final long databaseMySQLMaxLifetime;\n    public final int maxIslandSize;\n    public final String islandCommand;\n    public final int defaultIslandSize;\n    public final KeyMap<Integer> defaultBlockLimits;\n    public final KeyMap<Integer> defaultEntityLimits;\n    public final EnumerateMap<Dimension, Map<Key, Integer>> defaultGenerator;\n    public final int defaultWarpsLimit;\n    public final int defaultTeamLimit;\n    public final int defaultCoopLimit;\n    public final int defaultCropGrowth;\n    public final double defaultSpawnerRates;\n    public final double defaultMobDrops;\n    public final BigDecimal defaultBankLimit;\n    public final Int2IntMapView defaultRoleLimits;\n    public final Map<PotionEffectType, Integer> defaultIslandEffects;\n    public final int islandsHeight;\n    public final int seaLevelHeight;\n    public final boolean worldBordersEnabled;\n    public final boolean stackedBlocksEnabled;\n    public final KeySet whitelistedStackedBlocks;\n    public final List<String> stackedBlocksDisabledWorlds;\n    public final String stackedBlocksName;\n    public final KeyMap<Integer> stackedBlocksLimits;\n    public final boolean stackedBlocksAutoPickup;\n    public final boolean stackedBlocksMenuEnabled;\n    public final String stackedBlocksMenuTitle;\n    public final String blockLevelFormula;\n    public final boolean roundedIslandLevel;\n    public final RoundingMode islandLevelRoundingMode;\n    public final boolean autoBlocksTracking;\n    public final SortingType islandTopOrder;\n    public final SortingType globalWarpsOrder;\n    public boolean coopMembers;\n    public boolean editPlayerPermissions;\n    public final ConfigurationSection islandRolesSection;\n    public final long calcInterval;\n    public final String signWarpLine;\n    public final List<String> signWarp;\n    public final boolean visitorsSignRequiredForVisit;\n    public final String visitorsSignLine;\n    public final String visitorsSignActive;\n    public final String visitorsSignInactive;\n    public final String visitorsSignDescriptionLineFormat;\n    public final Dimension defaultWorldDimension;\n    public final String defaultWorldName;\n    public final String islandWorldName;\n    public final EnumerateMap<Dimension, SettingsManager.Worlds.DimensionConfig> dimensionConfigs = new EnumerateMap<>(Dimension.values());\n    public final String worldsDifficulty;\n    public final String spawnLocation;\n    public final boolean spawnProtection;\n    public final List<String> spawnSettings;\n    public final List<String> spawnPermissions;\n    public final boolean spawnWorldBorder;\n    public final int spawnSize;\n    public final boolean spawnDamage;\n    public final Set<String> worldPermissions;\n    public final boolean voidTeleportMembers;\n    public final boolean voidTeleportVisitors;\n    public final SettingsManager.Interactables interactables;\n    public final KeySet safeBlocks;\n    public final boolean visitorsDamage;\n    public final boolean coopDamage;\n    public final boolean islandTopIncludeLeader;\n    public final Map<String, String> defaultPlaceholders;\n    public final boolean banConfirm;\n    public final boolean disbandConfirm;\n    public final boolean kickConfirm;\n    public final boolean leaveConfirm;\n    public final boolean transferConfirm;\n    public final String spawnersProvider;\n    public final String stackedBlocksProvider;\n    public final boolean islandNamesRequiredForCreation;\n    public final int islandNamesMaxLength;\n    public final int islandNamesMinLength;\n    public final List<String> filteredIslandNames;\n    public final boolean islandNamesColorSupport;\n    public final boolean islandNamesIslandTop;\n    public final boolean islandNamesPreventPlayerNames;\n    public final boolean islandNamesAnnounceChangeToAll;\n    public final boolean teleportOnCreate;\n    public final boolean teleportOnJoin;\n    public final boolean teleportOnKick;\n    public final boolean teleportOnLeave;\n    public final List<ClearAction> clearActionsOnDisband;\n    public final List<ClearAction> clearActionsOnJoin;\n    public final List<ClearAction> clearActionsOnKick;\n    public final List<ClearAction> clearActionsOnLeave;\n    public final boolean rateOwnIsland;\n    public final boolean changeIslandRating;\n    public final List<String> defaultSettings;\n    public final boolean disableRedstoneOffline;\n    public final boolean disableRedstoneAFK;\n    public final boolean disableSpawningAFK;\n    public final Map<String, Pair<Integer, String>> commandsCooldown;\n    public final long upgradeCooldown;\n    public final String numberFormat;\n    public final String dateFormat;\n    public final boolean skipOneItemMenus;\n    public final boolean teleportOnPVPEnable;\n    public final boolean immuneToPVPWhenTeleport;\n    public final List<String> blockedVisitorsCommands;\n    public final boolean defaultContainersEnabled;\n    public final Map<InventoryType, ListTag> defaultContainersContents;\n    public final List<String> defaultSignLines;\n    public final Map<String, List<String>> eventCommands;\n    public final long warpsWarmup;\n    public final long homeWarmup;\n    public final long visitWarmup;\n    public final boolean liquidUpdate;\n    public final boolean lightsUpdate;\n    public final List<String> pvpWorlds;\n    public final boolean stopLeaving;\n    public final boolean valuesMenu;\n    public final List<String> cropsToGrow;\n    public final int cropsInterval;\n    public final boolean onlyBackButton;\n    public final boolean buildOutsideIsland;\n    public final int defaultDisbandCount;\n    public final String defaultLanguage;\n    public final boolean defaultWorldBorder;\n    public final boolean defaultBlocksStacker;\n    public final boolean defaultToggledPanel;\n    public final boolean defaultIslandFly;\n    public final String defaultBorderColor;\n    public final boolean obsidianToLava;\n    public final BlockValuesManagerImpl.SyncWorthStatus syncWorth;\n    public final boolean negativeWorth;\n    public final boolean negativeLevel;\n    public final List<String> disabledEvents;\n    public final List<String> disabledCommands;\n    public final List<String> disabledHooks;\n    public final boolean schematicNameArgument;\n    public final String islandChestTitle;\n    public final int islandChestsDefaultPage;\n    public final int islandChestsDefaultSize;\n    public final Map<String, List<String>> commandAliases;\n    public final KeySet valuableBlocks;\n    public final GameMode islandPreviewsGameMode;\n    public final int islandPreviewsMaxDistance;\n    public final List<String> islandPreviewsBlockedCommands;\n    public final Map<String, Location> islandPreviewsLocations;\n    public final boolean tabCompleteHideVanished;\n    public final boolean dropsUpgradePlayersMultiply;\n    public final Map<String, Long> messageDelays;\n    public final boolean warpCategories;\n    public final boolean physicsListener;\n    public final double chargeOnWarp;\n    public final boolean publicWarps;\n    public final boolean lockedIslands;\n    public final long recalcTaskTimeout;\n    public final boolean autoLanguageDetection;\n    public final boolean autoUncoopWhenAlone;\n    public final TopIslandMembersSorting islandTopMembersSorting;\n    public final int bossBarLimit;\n    public final boolean deleteUnsafeWarps;\n    public final List<RespawnAction> playerRespawnActions;\n    public final BigInteger blockCountsSaveThreshold;\n    public final boolean chatSigningSupport;\n    public final int commandsPerPage;\n    public final boolean helpOnNoPermission;\n    public final boolean helpOnInvalidCommand;\n    public final boolean cacheSchematics;\n    public final SettingsManager.EntityCategories entityCategories;\n\n    public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException {\n        databaseType = config.getString(\"database.type\").toUpperCase(Locale.ENGLISH);\n        databaseBackup = config.getBoolean(\"database.backup\");\n        databaseMySQLAddress = config.getString(\"database.address\");\n        databaseMySQLPort = config.getInt(\"database.port\");\n        databaseMySQLDBName = config.getString(\"database.db-name\");\n        databaseMySQLUsername = config.getString(\"database.user-name\");\n        databaseMySQLPassword = config.getString(\"database.password\");\n        databaseMySQLPrefix = config.getString(\"database.prefix\");\n        databaseMySQLSSL = config.getBoolean(\"database.useSSL\");\n        databaseMySQLPublicKeyRetrieval = config.getBoolean(\"database.allowPublicKeyRetrieval\");\n        databaseMySQLWaitTimeout = config.getLong(\"database.waitTimeout\");\n        databaseMySQLMaxLifetime = config.getLong(\"database.maxLifetime\");\n\n        calcInterval = config.getLong(\"calc-interval\", 6000);\n        islandCommand = config.getString(\"island-command\", \"island,is,islands\");\n        maxIslandSize = config.getInt(\"max-island-size\", 200);\n        defaultIslandSize = Math.max(config.getInt(\"default-values.island-size\", 20), 1);\n        KeyMap<Integer> defaultBlockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        loadListOrSection(config, \"default-values.block-limits\", \"block limit\", (key, limit) -> {\n            if (limit >= 0) {\n                Key blockKey = Keys.ofMaterialAndData(key);\n                defaultBlockLimits.put(blockKey, limit);\n                plugin.getBlockValues().addCustomBlockKey(blockKey);\n            }\n        });\n        this.defaultBlockLimits = KeyMaps.unmodifiableKeyMap(defaultBlockLimits);\n        KeyMap<Integer> defaultEntityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n        loadListOrSection(config, \"default-values.entity-limits\", \"entity limit\", (entityType, limit) -> {\n            if (limit >= 0) {\n                defaultEntityLimits.put(Keys.ofEntityType(entityType), limit);\n            }\n        });\n        this.defaultEntityLimits = KeyMaps.unmodifiableKeyMap(defaultEntityLimits);\n        Map<PotionEffectType, Integer> defaultIslandEffects = new ArrayMap<>();\n        loadListOrSection(config, \"default-values.island-effects\", \"island effect\", (effectName, effectLevel) -> {\n            if (effectLevel >= 1) {\n                PotionEffectType potionEffectType = PotionEffectType.getByName(effectName);\n                if (potionEffectType == null) {\n                    Log.errorFromFile(\"config.yml\", \"Invalid potion effect \" + effectName + \", skipping...\");\n                } else {\n                    defaultIslandEffects.put(potionEffectType, effectLevel - 1);\n                }\n            }\n        });\n        this.defaultIslandEffects = Collections.unmodifiableMap(defaultIslandEffects);\n        defaultTeamLimit = Math.max(config.getInt(\"default-values.team-limit\", 4), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultWarpsLimit = Math.max(config.getInt(\"default-values.warps-limit\", 3), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultCoopLimit = Math.max(config.getInt(\"default-values.coop-limit\", 8), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultCropGrowth = Math.max(config.getInt(\"default-values.crop-growth\", 1), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultSpawnerRates = Math.max(config.getDouble(\"default-values.spawner-rates\", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultMobDrops = Math.max(config.getDouble(\"default-values.mob-drops\", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE);\n        defaultBankLimit = new BigDecimal(config.getString(\"default-values.bank-limit\", \"-1\")).max(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE);\n        defaultRoleLimits = CollectionsFactory.createInt2IntHashMap();\n        loadListOrSection(config, \"default-values.role-limits\", \"role limit\", (role, limit) -> {\n            if (limit >= 0) {\n                try {\n                    defaultRoleLimits.put(Integer.parseInt(role), limit);\n                } catch (NumberFormatException error) {\n                    Log.warnFromFile(\"config.yml\", \"Invalid role id for limit: \" + role);\n                }\n            }\n        });\n        islandsHeight = config.getInt(\"islands-height\", 100);\n        worldBordersEnabled = config.getBoolean(\"world-borders\", true);\n        stackedBlocksEnabled = config.getBoolean(\"stacked-blocks.enabled\", true);\n        stackedBlocksDisabledWorlds = Collections.unmodifiableList(config.getStringList(\"stacked-blocks.disabled-worlds\"));\n        whitelistedStackedBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList(\"stacked-blocks.whitelisted\"));\n        stackedBlocksName = Formatters.COLOR_FORMATTER.format(config.getString(\"stacked-blocks.custom-name\"));\n        KeyMap<Integer> stackedBlocksLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        loadListOrSection(config, \"stacked-blocks.limits\", \"stacked-block limit\", (key, limit) -> {\n            Key blockKey = Keys.ofMaterialAndData(key);\n            stackedBlocksLimits.put(blockKey, limit);\n        });\n        this.stackedBlocksLimits = KeyMaps.unmodifiableKeyMap(stackedBlocksLimits);\n        stackedBlocksAutoPickup = config.getBoolean(\"stacked-blocks.auto-collect\", false);\n        stackedBlocksMenuEnabled = config.getBoolean(\"stacked-blocks.deposit-menu.enabled\", true);\n        stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString(\"stacked-blocks.deposit-menu.title\", \"&lDeposit Blocks\"));\n        blockLevelFormula = config.getString(\"block-level-formula\", \"{} / 2\");\n        roundedIslandLevel = config.getBoolean(\"rounded-island-level\", false);\n        islandLevelRoundingMode = Optional.ofNullable(EnumHelper.getEnum(RoundingMode.class,\n                        config.getString(\"island-level-rounding-mode\").toUpperCase(Locale.ENGLISH)))\n                .orElse(RoundingMode.HALF_UP);\n        autoBlocksTracking = config.getBoolean(\"auto-blocks-tracking\", true);\n\n        String rawTop = config.getString(\"island-top-order\", \"WORTH\");\n        SortingType parsedTop = SortingType.getByName(rawTop.toUpperCase(Locale.ENGLISH));\n        if (parsedTop == null) {\n            parsedTop = SortingType.getByName(\"WORTH\");\n            Log.warnFromFile(\"config.yml\", \"Invalid island-top-order '\" + rawTop + \"', using 'WORTH'.\");\n        }\n        this.islandTopOrder = parsedTop;\n\n        String rawGlobalWarps = config.getString(\"global-warps-order\", \"WORTH\").toUpperCase(Locale.ENGLISH);\n        SortingType foundGlobalWarpsOrder = SortingType.getByName(rawGlobalWarps);\n        if (foundGlobalWarpsOrder == null) {\n            foundGlobalWarpsOrder = SortingType.getByName(\"WORTH\");\n            Log.warnFromFile(\"config.yml\", \"Invalid global-warps-order '\" + rawGlobalWarps + \"', using 'WORTH'.\");\n        }\n        this.globalWarpsOrder = foundGlobalWarpsOrder;\n        coopMembers = config.getBoolean(\"coop-members\", true);\n        editPlayerPermissions = config.getBoolean(\"edit-player-permissions\", true);\n        islandRolesSection = config.getConfigurationSection(\"island-roles\");\n        signWarpLine = config.getString(\"sign-warp-line\", \"[IslandWarp]\");\n        List<String> signWarp = Formatters.formatList(config.getStringList(\"sign-warp\"), Formatters.COLOR_FORMATTER);\n        while (signWarp.size() < 4)\n            signWarp.add(\"\");\n        this.signWarp = Collections.unmodifiableList(signWarp);\n        visitorsSignRequiredForVisit = config.getBoolean(\"visitors-sign.required-for-visit\", true);\n        visitorsSignLine = config.getString(\"visitors-sign.line\", \"[Welcome]\");\n        visitorsSignActive = Formatters.COLOR_FORMATTER.format(config.getString(\"visitors-sign.active\", \"&a[Welcome]\"));\n        visitorsSignInactive = Formatters.COLOR_FORMATTER.format(config.getString(\"visitors-sign.inactive\", \"&c[Welcome]\"));\n        visitorsSignDescriptionLineFormat = Formatters.COLOR_FORMATTER.format(config.getString(\"visitors-sign.description-line-format\", \"{0}\"));\n        loadDimensions(config.getConfigurationSection(\"worlds.dimensions\"));\n        islandWorldName = config.getString(\"worlds.world-name\", \"SuperiorWorld\");\n        worldsDifficulty = config.getString(\"worlds.difficulty\", \"EASY\").toUpperCase(Locale.ENGLISH);\n        seaLevelHeight = config.getInt(\"worlds.sea-level-height\", 100);\n        this.defaultWorldDimension = Dimension.getByName(config.getString(\"worlds.default-world\"));\n        loadDimensionConfigs(config.getConfigurationSection(\"worlds.dimensions\"));\n        this.defaultWorldName = this.dimensionConfigs.get(this.defaultWorldDimension).getName();\n        spawnLocation = config.getString(\"spawn.location\", \"SuperiorWorld, 0, 100, 0, 0, 0\");\n        spawnProtection = config.getBoolean(\"spawn.protection\", true);\n        spawnSettings = Collections.unmodifiableList(new LinkedList<>(config.getStringList(\"spawn.settings\")\n                .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())));\n        spawnPermissions = Collections.unmodifiableList(new LinkedList<>(config.getStringList(\"spawn.permissions\")\n                .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())));\n        spawnWorldBorder = config.getBoolean(\"spawn.world-border\", false);\n        spawnSize = config.getInt(\"spawn.size\", 200);\n        spawnDamage = config.getBoolean(\"spawn.players-damage\", false);\n        worldPermissions = Collections.unmodifiableSet(new LinkedHashSet<>(config.getStringList(\"world-permissions\")\n                .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toSet())));\n        voidTeleportMembers = config.getBoolean(\"void-teleport.members\", true);\n        voidTeleportVisitors = config.getBoolean(\"void-teleport.visitors\", true);\n        interactables = loadInteractables(plugin);\n        safeBlocks = loadSafeBlocks(plugin);\n        visitorsDamage = config.getBoolean(\"visitors-damage\", false);\n        coopDamage = config.getBoolean(\"coop-damage\", true);\n        islandTopIncludeLeader = config.getBoolean(\"island-top-include-leader\", true);\n        defaultPlaceholders = Collections.unmodifiableMap(config.getStringList(\"default-placeholders\").stream().collect(Collectors.toMap(\n                line -> line.split(\":\")[0].replace(\"superior_\", \"\").toLowerCase(Locale.ENGLISH),\n                line -> line.split(\":\")[1]\n        )));\n        banConfirm = config.getBoolean(\"ban-confirm\");\n        disbandConfirm = config.getBoolean(\"disband-confirm\");\n        kickConfirm = config.getBoolean(\"kick-confirm\");\n        leaveConfirm = config.getBoolean(\"leave-confirm\");\n        transferConfirm = config.getBoolean(\"transfer-confirm\");\n        spawnersProvider = config.getString(\"spawners-provider\", \"AUTO\");\n        stackedBlocksProvider = config.getString(\"stacked-blocks-provider\", \"AUTO\");\n        islandNamesRequiredForCreation = config.getBoolean(\"island-names.required-for-creation\", true);\n        islandNamesMaxLength = config.getInt(\"island-names.max-length\", 16);\n        islandNamesMinLength = config.getInt(\"island-names.min-length\", 3);\n        filteredIslandNames = Collections.unmodifiableList(config.getStringList(\"island-names.filtered-names\").stream()\n                .map(str -> str.toLowerCase(Locale.ENGLISH))\n                .collect(Collectors.toList()));\n        islandNamesColorSupport = config.getBoolean(\"island-names.color-support\", true);\n        islandNamesIslandTop = config.getBoolean(\"island-names.island-top\", true);\n        islandNamesPreventPlayerNames = config.getBoolean(\"island-names.prevent-player-names\", true);\n        islandNamesAnnounceChangeToAll = config.getBoolean(\"island-names.announce-change-to-all\", true);\n        teleportOnCreate = config.getBoolean(\"teleport-on-create\", true);\n        teleportOnJoin = config.getBoolean(\"teleport-on-join\", false);\n        teleportOnKick = config.getBoolean(\"teleport-on-kick\", true);\n        teleportOnLeave = config.getBoolean(\"teleport-on-leave\", false);\n        clearActionsOnDisband = loadClearActions(config.getStringList(\"clear-on-disband\"));\n        clearActionsOnJoin = loadClearActions(config.getStringList(\"clear-on-join\"));\n        clearActionsOnKick = loadClearActions(config.getStringList(\"clear-on-kick\"));\n        clearActionsOnLeave = loadClearActions(config.getStringList(\"clear-on-leave\"));\n        rateOwnIsland = config.getBoolean(\"rate-own-island\", false);\n        changeIslandRating = config.getBoolean(\"change-island-rating\", true);\n        defaultSettings = Collections.unmodifiableList(config.getStringList(\"default-settings\")\n                .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()));\n        defaultGenerator = new EnumerateMap<>(Dimension.values());\n        if (config.isConfigurationSection(\"default-values.generator\")) {\n            for (String env : config.getConfigurationSection(\"default-values.generator\").getKeys(false)) {\n                try {\n                    Dimension dimension = Dimension.getByName(env.toUpperCase(Locale.ENGLISH));\n                    loadGenerator(config, \"default-values.generator.\" + env, dimension);\n                } catch (Exception error) {\n                    Log.errorFromFile(error, \"config.yml\", \"An unexpected error occurred while loading default generator values for \", env + \":\");\n                }\n            }\n        } else {\n            loadGenerator(config, \"default-values.generator\", this.defaultWorldDimension);\n        }\n        disableRedstoneOffline = config.getBoolean(\"disable-redstone-offline\", true);\n        disableRedstoneAFK = config.getBoolean(\"afk-integrations.disable-redstone\", false);\n        disableSpawningAFK = config.getBoolean(\"afk-integrations.disable-spawning\", true);\n        Map<String, Pair<Integer, String>> commandsCooldown = new HashMap<>();\n        for (String subCommand : config.getConfigurationSection(\"commands-cooldown\").getKeys(false)) {\n            int cooldown = config.getInt(\"commands-cooldown.\" + subCommand + \".cooldown\");\n            String permission = config.getString(\"commands-cooldown.\" + subCommand + \".bypass-permission\");\n            commandsCooldown.put(subCommand, new Pair<>(cooldown, permission));\n        }\n        this.commandsCooldown = Collections.unmodifiableMap(commandsCooldown);\n        upgradeCooldown = config.getLong(\"upgrade-cooldown\", -1L);\n        numberFormat = config.getString(\"number-format\", \"en-US\");\n        NumberFormatter.setNumberFormatter(numberFormat);\n        dateFormat = config.getString(\"date-format\", \"dd/MM/yyyy HH:mm:ss\");\n        DateFormatter.setDateFormatter(plugin, dateFormat);\n        skipOneItemMenus = config.getBoolean(\"skip-one-item-menus\", false);\n        teleportOnPVPEnable = config.getBoolean(\"teleport-on-pvp-enable\", true);\n        immuneToPVPWhenTeleport = config.getBoolean(\"immune-to-pvp-when-teleport\", true);\n        blockedVisitorsCommands = Collections.unmodifiableList(config.getStringList(\"blocked-visitors-commands\"));\n        defaultContainersEnabled = config.getBoolean(\"default-containers.enabled\", false);\n        Map<InventoryType, ListTag> defaultContainersContents = new EnumMap<>(InventoryType.class);\n        if (config.isConfigurationSection(\"default-containers.containers\")) {\n            for (String container : config.getConfigurationSection(\"default-containers.containers\").getKeys(false)) {\n                try {\n                    InventoryType containerType = InventoryType.valueOf(container.toUpperCase(Locale.ENGLISH));\n                    ListTag items = ListTag.of(CompoundTag.class);\n                    defaultContainersContents.put(containerType, items);\n\n                    ConfigurationSection containerSection = config.getConfigurationSection(\"default-containers.containers.\" + container);\n                    for (String slot : containerSection.getKeys(false)) {\n                        try {\n                            // Reading the item from the config\n                            TemplateItem templateItem = MenuParserImpl.getInstance().getItemStack(\"config.yml\", containerSection.getConfigurationSection(slot));\n\n                            if (templateItem == null)\n                                continue;\n\n                            ItemStack itemStack = templateItem.build();\n                            itemStack.setAmount(containerSection.getInt(slot + \".amount\", 1));\n\n                            // Parsing it into compound tag\n                            CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack);\n                            itemCompound.setByte(\"Slot\", Byte.parseByte(slot));\n\n                            items.addTag(itemCompound);\n                        } catch (Exception error) {\n                            Log.errorFromFile(error, \"config.yml\", \"An unexpected error occurred while loading container item for \", slot + \":\");\n                        }\n                    }\n                } catch (IllegalArgumentException ex) {\n                    Log.warnFromFile(\"config.yml\", \"Invalid container type \", container + \", skipping...\");\n                }\n            }\n        }\n        this.defaultContainersContents = Collections.unmodifiableMap(defaultContainersContents);\n        defaultSignLines = Collections.unmodifiableList(\n                Formatters.formatList(config.getStringList(\"default-signs\"), Formatters.COLOR_FORMATTER));\n        Map<String, List<String>> eventCommands = new HashMap<>();\n        if (config.isConfigurationSection(\"event-commands\")) {\n            for (String eventName : config.getConfigurationSection(\"event-commands\").getKeys(false)) {\n                eventCommands.put(eventName.toLowerCase(Locale.ENGLISH), config.getStringList(\"event-commands.\" + eventName));\n            }\n        }\n        this.eventCommands = Collections.unmodifiableMap(eventCommands);\n        warpsWarmup = config.getLong(\"warps-warmup\", 0);\n        homeWarmup = config.getLong(\"home-warmup\", 0);\n        visitWarmup = config.getLong(\"visit-warmup\", 0);\n        liquidUpdate = config.getBoolean(\"liquid-update\", false);\n        lightsUpdate = config.getBoolean(\"lights-update\", true);\n        pvpWorlds = Collections.unmodifiableList(config.getStringList(\"pvp-worlds\"));\n        stopLeaving = config.getBoolean(\"stop-leaving\", false);\n        valuesMenu = config.getBoolean(\"values-menu\", true);\n        cropsToGrow = Collections.unmodifiableList(config.getStringList(\"crops-to-grow\"));\n        cropsInterval = config.getInt(\"crops-interval\", 5);\n        onlyBackButton = config.getBoolean(\"only-back-button\", false);\n        buildOutsideIsland = config.getBoolean(\"build-outside-island\", false);\n        defaultDisbandCount = config.getInt(\"default-disband-count\", 5);\n        defaultLanguage = config.getString(\"default-language\", \"en-US\");\n        defaultWorldBorder = config.getBoolean(\"default-world-border\", true);\n        defaultBlocksStacker = config.getBoolean(\"default-blocks-stacker\", true);\n        defaultToggledPanel = config.getBoolean(\"default-toggled-panel\", false);\n        defaultIslandFly = config.getBoolean(\"default-island-fly\", false);\n        defaultBorderColor = config.getString(\"default-border-color\", \"BLUE\");\n        obsidianToLava = config.getBoolean(\"obsidian-to-lava\", false);\n        syncWorth = BlockValuesManagerImpl.SyncWorthStatus.of(config.getString(\"sync-worth\", \"NONE\"));\n        negativeWorth = config.getBoolean(\"negative-worth\", true);\n        negativeLevel = config.getBoolean(\"negative-level\", true);\n        disabledEvents = Collections.unmodifiableList(config.getStringList(\"disabled-events\")\n                .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()));\n        disabledCommands = Collections.unmodifiableList(config.getStringList(\"disabled-commands\")\n                .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()));\n        disabledHooks = Collections.unmodifiableList(config.getStringList(\"disabled-hooks\")\n                .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()));\n        schematicNameArgument = config.getBoolean(\"schematic-name-argument\", true);\n        islandChestTitle = Formatters.COLOR_FORMATTER.format(config.getString(\"island-chests.chest-title\", \"&4Island Chest\"));\n        islandChestsDefaultPage = config.getInt(\"island-chests.default-pages\", 0);\n        islandChestsDefaultSize = Math.min(6, Math.max(1, config.getInt(\"island-chests.default-size\", 3)));\n        Map<String, List<String>> commandAliases = new HashMap<>();\n        if (config.isConfigurationSection(\"command-aliases\")) {\n            for (String label : config.getConfigurationSection(\"command-aliases\").getKeys(false)) {\n                commandAliases.put(label.toLowerCase(Locale.ENGLISH), config.getStringList(\"command-aliases.\" + label));\n            }\n        }\n        this.commandAliases = Collections.unmodifiableMap(commandAliases);\n        valuableBlocks = KeySets.unmodifiableKeySet(\n                KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList(\"valuable-blocks\")));\n        GameMode islandPreviewsGameMode;\n        String islandPreviewsGameModeName = config.getString(\"island-previews.game-mode\", \"SPECTATOR\").toUpperCase(Locale.ENGLISH);\n        try {\n            islandPreviewsGameMode = GameMode.valueOf(islandPreviewsGameModeName);\n        } catch (IllegalArgumentException error) {\n            islandPreviewsGameMode = GameMode.SPECTATOR;\n            Log.warnFromFile(\"config.yml\", \"Invalid game mode \", islandPreviewsGameModeName + \", using SPECTATOR instead.\");\n        }\n        this.islandPreviewsGameMode = islandPreviewsGameMode;\n        islandPreviewsMaxDistance = config.getInt(\"island-previews.max-distance\", 100);\n        islandPreviewsBlockedCommands = Collections.unmodifiableList(config.getStringList(\"island-previews.blocked-commands\"));\n        Map<String, Location> islandPreviewsLocations = new HashMap<>();\n        if (config.isConfigurationSection(\"island-previews.locations\")) {\n            for (String schematic : config.getConfigurationSection(\"island-previews.locations\").getKeys(false)) {\n                try {\n                    islandPreviewsLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SPACED_CENTERED_SERIALIZER\n                            .deserialize(config.getString(\"island-previews.locations.\" + schematic)));\n                } catch (Exception error) {\n                    Log.warnFromFile(\"config.yml\", \"Cannot deserialize island preview for \", schematic, \", skipping...\");\n                }\n            }\n        }\n        this.islandPreviewsLocations = Collections.unmodifiableMap(islandPreviewsLocations);\n        tabCompleteHideVanished = config.getBoolean(\"tab-complete-hide-vanished\", true);\n        dropsUpgradePlayersMultiply = config.getBoolean(\"drops-upgrade-players-multiply\", false);\n        Map<String, Long> messageDelays = new HashMap<>();\n        if (config.isConfigurationSection(\"message-delays\")) {\n            for (String message : config.getConfigurationSection(\"message-delays\").getKeys(false)) {\n                messageDelays.put(message.toUpperCase(Locale.ENGLISH), config.getLong(\"message-delays.\" + message));\n            }\n        }\n        this.messageDelays = Collections.unmodifiableMap(messageDelays);\n        warpCategories = config.getBoolean(\"warp-categories\", true);\n        physicsListener = config.getBoolean(\"physics-listener\", true);\n        chargeOnWarp = config.getDouble(\"charge-on-warp\", 0D);\n        publicWarps = config.getBoolean(\"public-warps\");\n        lockedIslands = config.getBoolean(\"locked-islands\", false);\n        recalcTaskTimeout = config.getLong(\"recalc-task-timeout\");\n        autoLanguageDetection = config.getBoolean(\"auto-language-detection\", true);\n        autoUncoopWhenAlone = config.getBoolean(\"auto-uncoop-when-alone\", false);\n        islandTopMembersSorting = Optional.ofNullable(EnumHelper.getEnum(TopIslandMembersSorting.class,\n                        config.getString(\"island-top-members-sorting\").toUpperCase(Locale.ENGLISH)))\n                .orElse(TopIslandMembersSorting.NAMES);\n        bossBarLimit = config.getInt(\"bossbar-limit\", 1);\n        deleteUnsafeWarps = config.getBoolean(\"delete-unsafe-warps\", true);\n        List<RespawnAction> playerRespawnActions = new LinkedList<>();\n        config.getStringList(\"player-respawn\").forEach(respawnAction -> {\n            try {\n                playerRespawnActions.add(RespawnAction.getByName(respawnAction));\n            } catch (NullPointerException error) {\n                Log.warnFromFile(\"config.yml\", \"Invalid respawn action \", respawnAction + \", skipping...\");\n            }\n        });\n        this.playerRespawnActions = Collections.unmodifiableList(playerRespawnActions);\n        blockCountsSaveThreshold = BigInteger.valueOf(config.getInt(\"block-counts-save-threshold\", 100));\n        chatSigningSupport = config.getBoolean(\"chat-signing-support\", true);\n        commandsPerPage = config.getInt(\"commands-per-page\", 7);\n        helpOnInvalidCommand = config.getBoolean(\"help-on-invalid-command\", true);\n        helpOnNoPermission = config.getBoolean(\"help-on-no-permission\", false);\n        cacheSchematics = config.getBoolean(\"cache-schematics\", true);\n        entityCategories = loadEntityCategories(plugin);\n    }\n\n    private void loadDimensions(ConfigurationSection dimensionsSection) {\n        // First register all dimensions\n        for (String dimensionName : dimensionsSection.getKeys(false)) {\n            String environmentName = dimensionsSection.getString(dimensionName + \".environment\");\n            World.Environment environment;\n            try {\n                environment = World.Environment.valueOf(environmentName.toUpperCase(Locale.ENGLISH));\n            } catch (IllegalArgumentException error) {\n                Log.warnFromFile(\"config.yml\", \"Cannot load dimension due to invalid environment: \", environmentName, \" - skipping...\");\n                continue;\n            }\n\n            try {\n                Dimension.register(dimensionName, environment);\n            } catch (IllegalStateException ignored) {\n            }\n        }\n    }\n\n    private void loadDimensionConfigs(ConfigurationSection dimensionsSection) throws ManagerLoadException {\n        for (String dimensionName : dimensionsSection.getKeys(false)) {\n            ConfigurationSection dimensionSection = dimensionsSection.getConfigurationSection(dimensionName);\n\n            if (dimensionSection == null) {\n                Log.warnFromFile(\"config.yml\", \"Invalid dimension config section for \", dimensionName, \" - skipping...\");\n                continue;\n            }\n\n            Dimension dimension = Dimension.getByName(dimensionName);\n\n            String worldName = defaultWorldDimension == dimension ? islandWorldName :\n                    islandWorldName + \"_\" + dimensionName.toLowerCase(Locale.ENGLISH);\n\n            switch (dimension.getEnvironment()) {\n                case NORMAL:\n                    dimensionConfigs.put(dimension, new WorldsSection.NormalDimensionConfig(dimensionSection, dimension, worldName));\n                    break;\n                case NETHER:\n                    dimensionConfigs.put(dimension, new WorldsSection.NetherDimensionConfig(dimensionSection, dimension, worldName));\n                    break;\n                case THE_END:\n                    dimensionConfigs.put(dimension, new WorldsSection.EndDimensionConfig(dimensionSection, dimension, worldName));\n                    break;\n            }\n\n        }\n\n        // Check the default dimension is valid\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = this.dimensionConfigs.get(this.defaultWorldDimension);\n        if (dimensionConfig == null || !dimensionConfig.isEnabled()) {\n            throw new ManagerLoadException(\"Cannot find a default islands world.\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n    }\n\n    private List<ClearAction> loadClearActions(List<String> clearActionsNames) {\n        List<ClearAction> clearActions = new LinkedList<>();\n        clearActionsNames.forEach(clearAction -> {\n            try {\n                clearActions.add(ClearAction.getByName(clearAction));\n            } catch (NullPointerException error) {\n                Log.warnFromFile(\"config.yml\", \"Invalid clear action \", clearAction + \", skipping...\");\n            }\n        });\n        return Collections.unmodifiableList(clearActions);\n    }\n\n    private SettingsManager.Interactables loadInteractables(SuperiorSkyblockPlugin plugin) {\n        File file = new File(plugin.getDataFolder(), \"interactables.yml\");\n\n        if (!file.exists())\n            plugin.saveResource(\"interactables.yml\", false);\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);\n\n        InteractablesSection interactables = new InteractablesSection(plugin, cfg);\n\n        // Warn about interactables that the default file contains but the current\n        // file does not.\n        Set<String> localInteractables = new HashSet<>();\n        for (Key key : interactables.getInteractables()) {\n            localInteractables.add(key.toString());\n        }\n\n        YamlConfiguration defaultInteractablesConfig = CommentedConfiguration.loadConfiguration(plugin.getResource(\"interactables.yml\"));\n        for (String block : defaultInteractablesConfig.getStringList(\"interactables\")) {\n            if (!localInteractables.contains(block)) {\n                Log.warn(\"Potentially missing interactable block \", block);\n            }\n        }\n\n        if (interactables.isLegacy()) {\n            try {\n                interactables.saveToFile(file);\n            } catch (IOException error) {\n                Log.errorFromFile(error, \"interactables.yml\", \"Failed to save interactables:\");\n            }\n        }\n\n        return interactables;\n    }\n\n    private SettingsManager.EntityCategories loadEntityCategories(SuperiorSkyblockPlugin plugin) {\n        File file = new File(plugin.getDataFolder(), \"entity-categories.yml\");\n\n        boolean removeInvalidEntityKeys = false;\n\n        if (!file.exists()) {\n            plugin.saveResource(\"entity-categories.yml\", false);\n            removeInvalidEntityKeys = true;\n        }\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);\n\n        if (removeInvalidEntityKeys) {\n            EntityCategoriesSection.removeInvalidEntityKeys(cfg, file);\n        }\n\n        return new EntityCategoriesSection(cfg);\n    }\n\n    private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) {\n        File file = new File(plugin.getDataFolder(), \"safe_blocks.yml\");\n\n        if (!file.exists())\n            Resources.saveResource(\"safe_blocks.yml\");\n\n        CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file);\n\n        List<String> safeBlocks = cfg.getStringList(\"safe-blocks\");\n\n        if (safeBlocks.isEmpty()) {\n            Log.warnFromFile(file.getName(), \"There are no valid safe blocks! Generating default ones...\");\n            safeBlocks.addAll(Arrays.stream(Material.values())\n                    .filter(Material::isSolid)\n                    .map(Material::name)\n                    .sorted()\n                    .collect(Collectors.toList()));\n\n            try {\n                cfg.set(\"safe-blocks\", safeBlocks);\n                cfg.save(file);\n            } catch (IOException error) {\n                Log.errorFromFile(error, \"config.yml\", \"An unexpected error occurred while saving safe blocks into file:\");\n            }\n        }\n\n        return KeySets.unmodifiableKeySet(KeySets.createHashSet(KeyIndicator.MATERIAL, safeBlocks));\n    }\n\n    private void loadGenerator(YamlConfiguration config, String path, Dimension dimension) {\n        KeyMap<Integer> defaultGenerator = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        loadListOrSection(config, path, \"generator-rates\", (key, percentage) -> {\n            if (percentage >= 0) {\n                Key blockKey = Keys.ofMaterialAndData(key);\n                defaultGenerator.put(blockKey, percentage);\n            }\n        });\n        this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator));\n    }\n\n    private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer<String, Integer> consumer) {\n        Object value = config.get(path);\n        if (value == null)\n            return;\n\n        if (value instanceof List) {\n            ((List<String>) value).forEach(line -> {\n                String[] sections = line.split(\":\");\n                if (sections.length == 2) {\n                    consumer.accept(sections[0], Integer.parseInt(sections[1]));\n                } else if (sections.length == 3) {\n                    consumer.accept(sections[0] + \":\" + sections[1], Integer.parseInt(sections[2]));\n                } else {\n                    Log.warnFromFile(\"config.yml\", \"Cannot parse \" + parseName + \" '\", line, \"', skipping...\");\n                }\n            });\n\n        } else if (value instanceof ConfigurationSection) {\n            for (String key : ((ConfigurationSection) value).getKeys(false)) {\n                consumer.accept(key, ((ConfigurationSection) value).getInt(key));\n            }\n        } else {\n            throw new IllegalArgumentException(\"Value of path '\" + path + \"' is not a list or a section, but \" + value.getClass());\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainerHolder.java",
    "content": "package com.bgsoftware.superiorskyblock.config;\n\npublic abstract class SettingsContainerHolder {\n\n    private SettingsContainer container;\n\n    protected SettingsContainerHolder() {\n\n    }\n\n    public void setContainer(SettingsContainer container) {\n        this.container = container;\n    }\n\n    protected SettingsContainer getContainer() {\n        if (this.container == null)\n            throw new IllegalStateException(\"Cannot access SettingsManager before initialization\");\n        return this.container;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.config;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.config.section.AFKIntegrationsSection;\nimport com.bgsoftware.superiorskyblock.config.section.DatabaseSection;\nimport com.bgsoftware.superiorskyblock.config.section.DefaultContainersSection;\nimport com.bgsoftware.superiorskyblock.config.section.DefaultValuesSection;\nimport com.bgsoftware.superiorskyblock.config.section.GlobalSection;\nimport com.bgsoftware.superiorskyblock.config.section.IslandChestsSection;\nimport com.bgsoftware.superiorskyblock.config.section.IslandNamesSection;\nimport com.bgsoftware.superiorskyblock.config.section.IslandPreviewsSection;\nimport com.bgsoftware.superiorskyblock.config.section.IslandRolesSection;\nimport com.bgsoftware.superiorskyblock.config.section.SpawnSection;\nimport com.bgsoftware.superiorskyblock.config.section.StackedBlocksSection;\nimport com.bgsoftware.superiorskyblock.config.section.VisitorsSignSection;\nimport com.bgsoftware.superiorskyblock.config.section.VoidTeleportSection;\nimport com.bgsoftware.superiorskyblock.config.section.WorldsSection;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.player.inventory.ClearActions;\nimport org.bukkit.Location;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.math.RoundingMode;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\n@SuppressWarnings(\"WeakerAccess\")\npublic class SettingsManagerImpl extends Manager implements SettingsManager {\n\n    private static final String[] IGNORED_SECTIONS = new String[]{\n            \"config.yml\", \"ladder\", \"commands-cooldown\", \"containers\", \"event-commands\", \"command-aliases\", \"worlds.dimensions\",\n            \"island-previews.locations\", \"default-values.block-limits\", \"default-values.entity-limits\",\n            \"default-values.role-limits\", \"stacked-blocks.limits\", \"default-values.generator\", \"message-delays\"\n    };\n\n    private final GlobalSection global = new GlobalSection();\n    private final DatabaseSection database = new DatabaseSection();\n    private final DefaultValuesSection defaultValues = new DefaultValuesSection();\n    private final StackedBlocksSection stackedBlocks = new StackedBlocksSection();\n    private final IslandRolesSection islandRoles = new IslandRolesSection();\n    private final VisitorsSignSection visitorsSign = new VisitorsSignSection();\n    private final WorldsSection worlds = new WorldsSection();\n    private final SpawnSection spawn = new SpawnSection();\n    private final VoidTeleportSection voidTeleport = new VoidTeleportSection();\n    private final IslandNamesSection islandNames = new IslandNamesSection();\n    private final AFKIntegrationsSection afkIntegrations = new AFKIntegrationsSection();\n    private final DefaultContainersSection defaultContainers = new DefaultContainersSection();\n    private final IslandChestsSection islandChests = new IslandChestsSection();\n    private final IslandPreviewsSection islandPreviews = new IslandPreviewsSection();\n\n    public SettingsManagerImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadData() throws ManagerLoadException {\n        File file = new File(plugin.getDataFolder(), \"config.yml\");\n\n        if (!file.exists())\n            plugin.saveResource(\"config.yml\", false);\n\n        CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file);\n        convertData(cfg);\n        convertInteractables(plugin, cfg);\n        convertEntityCategories(plugin, cfg);\n\n        try {\n            cfg.syncWithConfig(file, plugin.getResource(\"config.yml\"), IGNORED_SECTIONS);\n        } catch (Exception error) {\n            Log.error(error, file, \"An unexpected error occurred while loading config file:\");\n        }\n\n        loadContainerFromConfig(cfg);\n\n        PluginEventsFactory.callSettingsUpdateEvent();\n    }\n\n    @Override\n    public long getCalcInterval() {\n        return this.global.getCalcInterval();\n    }\n\n    @Override\n    public Database getDatabase() {\n        return this.database;\n    }\n\n    @Override\n    public String getIslandCommand() {\n        return this.global.getIslandCommand();\n    }\n\n    @Override\n    public int getMaxIslandSize() {\n        return this.global.getMaxIslandSize();\n    }\n\n    @Override\n    public DefaultValuesSection getDefaultValues() {\n        return this.defaultValues;\n    }\n\n    @Override\n    public int getIslandHeight() {\n        return this.global.getIslandHeight();\n    }\n\n    @Override\n    public boolean isWorldBorders() {\n        return this.global.isWorldBorders();\n    }\n\n    @Override\n    public StackedBlocks getStackedBlocks() {\n        return this.stackedBlocks;\n    }\n\n    @Override\n    public String getIslandLevelFormula() {\n        return this.global.getBlockLevelFormula();\n    }\n\n    @Override\n    public boolean isRoundedIslandLevels() {\n        return this.global.isRoundedIslandLevels();\n    }\n\n    @Override\n    public RoundingMode getIslandLevelRoundingMode() {\n        return this.global.getIslandLevelRoundingMode();\n    }\n\n    @Override\n    public boolean isAutoBlocksTracking() {\n        return this.global.isAutoBlocksTracking();\n    }\n\n    @Override\n    public String getIslandTopOrder() {\n        return this.global.getIslandTopOrder().getName();\n    }\n\n    @Override\n    public String getGlobalWarpsOrder() {\n        return this.global.getGlobalWarpsOrder().getName();\n    }\n\n    @Override\n    public boolean isCoopMembers() {\n        return this.global.isCoopMembers();\n    }\n\n    @Override\n    public boolean isEditPlayerPermissions() {\n        return this.global.isEditPlayerPermissions();\n    }\n\n    @Override\n    public IslandRoles getIslandRoles() {\n        return this.islandRoles;\n    }\n\n    @Override\n    public String getSignWarpLine() {\n        return this.global.getSignWarpLine();\n    }\n\n    @Override\n    public List<String> getSignWarp() {\n        return this.global.getSignWarp();\n    }\n\n    @Override\n    public VisitorsSign getVisitorsSign() {\n        return this.visitorsSign;\n    }\n\n    @Override\n    public Worlds getWorlds() {\n        return this.worlds;\n    }\n\n    @Override\n    public Spawn getSpawn() {\n        return this.spawn;\n    }\n\n    @Override\n    public Collection<String> getWorldPermissions() {\n        return this.global.getWorldPermissions();\n    }\n\n    @Override\n    public VoidTeleport getVoidTeleport() {\n        return this.voidTeleport;\n    }\n\n    @Override\n    public List<String> getInteractables() {\n        List<String> interactables = new LinkedList<>();\n        for (Key key : getInteractablesMap().getInteractables()) {\n            interactables.add(key.toString());\n        }\n        return interactables.isEmpty() ? Collections.emptyList() : interactables;\n    }\n\n    @Override\n    public Interactables getInteractablesMap() {\n        return this.global.getInteractablesMap();\n    }\n\n    @Override\n    public Collection<Key> getSafeBlocks() {\n        return this.global.getSafeBlocks();\n    }\n\n    @Override\n    public boolean isVisitorsDamage() {\n        return this.global.isVisitorsDamage();\n    }\n\n    @Override\n    public boolean isCoopDamage() {\n        return this.global.isCoopDamage();\n    }\n\n    @Override\n    public int getDisbandCount() {\n        return this.global.getDisbandCount();\n    }\n\n    @Override\n    public boolean isIslandTopIncludeLeader() {\n        return this.global.isIslandTopIncludeLeader();\n    }\n\n    @Override\n    public Map<String, String> getDefaultPlaceholders() {\n        return this.global.getDefaultPlaceholders();\n    }\n\n    @Override\n    public boolean isBanConfirm() {\n        return this.global.isBanConfirm();\n    }\n\n    @Override\n    public boolean isDisbandConfirm() {\n        return this.global.isDisbandConfirm();\n    }\n\n    @Override\n    public boolean isKickConfirm() {\n        return this.global.isKickConfirm();\n    }\n\n    @Override\n    public boolean isLeaveConfirm() {\n        return this.global.isLeaveConfirm();\n    }\n\n    @Override\n    public boolean isTransferConfirm() {\n        return this.global.isTransferConfirm();\n    }\n\n    @Override\n    public String getSpawnersProvider() {\n        return this.global.getSpawnersProvider();\n    }\n\n    @Override\n    public String getStackedBlocksProvider() {\n        return this.global.getStackedBlocksProvider();\n    }\n\n    @Override\n    public boolean isDisbandInventoryClear() {\n        List<ClearAction> clearActions = this.global.getClearActionsOnDisband();\n        return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY);\n    }\n\n    @Override\n    public IslandNames getIslandNames() {\n        return this.islandNames;\n    }\n\n    @Override\n    public boolean isTeleportOnCreate() {\n        return this.global.isTeleportOnCreate();\n    }\n\n    @Override\n    public boolean isTeleportOnJoin() {\n        return this.global.isTeleportOnJoin();\n    }\n\n    @Override\n    public boolean isTeleportOnKick() {\n        return this.global.isTeleportOnKick();\n    }\n\n    @Override\n    public boolean isTeleportOnLeave() {\n        return this.global.isTeleportOnLeave();\n    }\n\n    @Override\n    public boolean isClearOnJoin() {\n        List<ClearAction> clearActions = this.global.getClearActionsOnJoin();\n        return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY);\n    }\n\n    @Override\n    public List<ClearAction> getClearActionsOnDisband() {\n        return this.global.getClearActionsOnDisband();\n    }\n\n    @Override\n    public List<ClearAction> getClearActionsOnJoin() {\n        return this.global.getClearActionsOnJoin();\n    }\n\n    @Override\n    public List<ClearAction> getClearActionsOnKick() {\n        return this.global.getClearActionsOnKick();\n    }\n\n    @Override\n    public List<ClearAction> getClearActionsOnLeave() {\n        return this.global.getClearActionsOnLeave();\n    }\n\n    @Override\n    public boolean isRateOwnIsland() {\n        return this.global.isRateOwnIsland();\n    }\n\n    @Override\n    public boolean isChangeIslandRating() {\n        return this.global.isChangeIslandRating();\n    }\n\n    @Override\n    public List<String> getDefaultSettings() {\n        return this.global.getDefaultSettings();\n    }\n\n    @Override\n    public boolean isDisableRedstoneOffline() {\n        return this.global.isDisableRedstoneOffline();\n    }\n\n    @Override\n    public AFKIntegrations getAFKIntegrations() {\n        return this.afkIntegrations;\n    }\n\n    @Override\n    public Map<String, Pair<Integer, String>> getCommandsCooldown() {\n        return this.global.getCommandsCooldown();\n    }\n\n    @Override\n    public long getUpgradeCooldown() {\n        return this.global.getUpgradeCooldown();\n    }\n\n    @Override\n    public String getNumbersFormat() {\n        return this.global.getNumbersFormat();\n    }\n\n    @Override\n    public String getDateFormat() {\n        return this.global.getDateFormat();\n    }\n\n    @Override\n    public boolean isSkipOneItemMenus() {\n        return this.global.isSkipOneItemMenus();\n    }\n\n    @Override\n    public boolean isTeleportOnPvPEnable() {\n        return this.global.isTeleportOnPvPEnable();\n    }\n\n    @Override\n    public boolean isImmuneToPvPWhenTeleport() {\n        return this.global.isImmuneToPvPWhenTeleport();\n    }\n\n    @Override\n    public List<String> getBlockedVisitorsCommands() {\n        return this.global.getBlockedVisitorsCommands();\n    }\n\n    @Override\n    public DefaultContainersSection getDefaultContainers() {\n        return this.defaultContainers;\n    }\n\n    @Override\n    public List<String> getDefaultSign() {\n        return this.global.getDefaultSign();\n    }\n\n    @Override\n    public Map<String, List<String>> getEventCommands() {\n        return this.global.getEventCommands();\n    }\n\n    @Override\n    public long getWarpsWarmup() {\n        return this.global.getWarpsWarmup();\n    }\n\n    @Override\n    public long getHomeWarmup() {\n        return this.global.getHomeWarmup();\n    }\n\n    @Override\n    public long getVisitWarmup() {\n        return this.global.getVisitWarmup();\n    }\n\n    @Override\n    public boolean isLiquidUpdate() {\n        return this.global.isLiquidUpdate();\n    }\n\n    @Override\n    public boolean isLightsUpdate() {\n        return this.global.isLightsUpdate();\n    }\n\n    @Override\n    public List<String> getPvPWorlds() {\n        return this.global.getPvPWorlds();\n    }\n\n    @Override\n    public boolean isStopLeaving() {\n        return this.global.isStopLeaving();\n    }\n\n    @Override\n    public boolean isValuesMenu() {\n        return this.global.isValuesMenu();\n    }\n\n    @Override\n    public List<String> getCropsToGrow() {\n        return this.global.getCropsToGrow();\n    }\n\n    @Override\n    public int getCropsInterval() {\n        return this.global.getCropsInterval();\n    }\n\n    @Override\n    public boolean isOnlyBackButton() {\n        return this.global.isOnlyBackButton();\n    }\n\n    @Override\n    public boolean isBuildOutsideIsland() {\n        return this.global.isBuildOutsideIsland();\n    }\n\n    @Override\n    public String getDefaultLanguage() {\n        return this.global.getDefaultLanguage();\n    }\n\n    @Override\n    public boolean isDefaultWorldBorder() {\n        return this.global.isDefaultWorldBorder();\n    }\n\n    @Override\n    public boolean isDefaultStackedBlocks() {\n        return this.global.isDefaultStackedBlocks();\n    }\n\n    @Override\n    public boolean isDefaultToggledPanel() {\n        return this.global.isDefaultToggledPanel();\n    }\n\n    @Override\n    public boolean isDefaultIslandFly() {\n        return this.global.isDefaultIslandFly();\n    }\n\n    @Override\n    public String getDefaultBorderColor() {\n        return this.global.getDefaultBorderColor();\n    }\n\n    @Override\n    public boolean isObsidianToLava() {\n        return this.global.isObsidianToLava();\n    }\n\n    @Override\n    public BlockValuesManager.SyncWorthStatus getSyncWorth() {\n        return this.global.getSyncWorth();\n    }\n\n    @Override\n    public boolean isNegativeWorth() {\n        return this.global.isNegativeWorth();\n    }\n\n    @Override\n    public boolean isNegativeLevel() {\n        return this.global.isNegativeLevel();\n    }\n\n    @Override\n    public List<String> getDisabledEvents() {\n        return this.global.getDisabledEvents();\n    }\n\n    @Override\n    public List<String> getDisabledCommands() {\n        return this.global.getDisabledCommands();\n    }\n\n    @Override\n    public List<String> getDisabledHooks() {\n        return this.global.getDisabledHooks();\n    }\n\n    @Override\n    public boolean isSchematicNameArgument() {\n        return this.global.isSchematicNameArgument();\n    }\n\n    @Override\n    public IslandChests getIslandChests() {\n        return this.islandChests;\n    }\n\n    @Override\n    public Map<String, List<String>> getCommandAliases() {\n        return this.global.getCommandAliases();\n    }\n\n    @Override\n    public Set<Key> getValuableBlocks() {\n        return this.global.getValuableBlocks();\n    }\n\n    @Override\n    @Deprecated\n    public Map<String, Location> getPreviewIslands() {\n        return this.islandPreviews.getLocations();\n    }\n\n    @Override\n    public IslandPreviewsSection getIslandPreviews() {\n        return this.islandPreviews;\n    }\n\n    @Override\n    public boolean isTabCompleteHideVanished() {\n        return this.global.isTabCompleteHideVanished();\n    }\n\n    @Override\n    public boolean isDropsUpgradePlayersMultiply() {\n        return this.global.isDropsUpgradePlayersMultiply();\n    }\n\n    @Override\n    @Deprecated\n    public long getProtectedMessageDelay() {\n        return this.global.getMessageDelays().getOrDefault(\"ISLAND_PROTECTED\", 0L);\n    }\n\n    @Override\n    public Map<String, Long> getMessageDelays() {\n        return this.global.getMessageDelays();\n    }\n\n    @Override\n    public boolean isWarpCategories() {\n        return this.global.isWarpCategories();\n    }\n\n    @Override\n    public boolean isPhysicsListener() {\n        return this.global.isPhysicsListener();\n    }\n\n    @Override\n    public double getChargeOnWarp() {\n        return this.global.getChargeOnWarp();\n    }\n\n    @Override\n    public boolean isPublicWarps() {\n        return this.global.isPublicWarps();\n    }\n\n    @Override\n    public boolean isLockedIslands() {\n        return this.global.isLockedIslands();\n    }\n\n    @Override\n    public long getRecalcTaskTimeout() {\n        return this.global.getRecalcTaskTimeout();\n    }\n\n    @Override\n    public boolean isAutoLanguageDetection() {\n        return this.global.isAutoLanguageDetection();\n    }\n\n    @Override\n    public boolean isAutoUncoopWhenAlone() {\n        return this.global.isAutoUncoopWhenAlone();\n    }\n\n    @Override\n    public TopIslandMembersSorting getTopIslandMembersSorting() {\n        return this.global.getTopIslandMembersSorting();\n    }\n\n    @Override\n    public int getBossbarLimit() {\n        return this.global.getBossbarLimit();\n    }\n\n    @Override\n    public boolean getDeleteUnsafeWarps() {\n        return this.global.getDeleteUnsafeWarps();\n    }\n\n    @Override\n    public List<RespawnAction> getPlayerRespawn() {\n        return this.global.getPlayerRespawn();\n    }\n\n    @Override\n    public BigInteger getBlockCountsSaveThreshold() {\n        return this.global.getBlockCountsSaveThreshold();\n    }\n\n    @Override\n    public boolean getChatSigningSupport() {\n        return this.global.getChatSigningSupport();\n    }\n\n    @Override\n    public int getCommandsPerPage() {\n        return this.global.getCommandsPerPage();\n    }\n\n    @Override\n    public boolean isHelpOnInvalidCommand() {\n        return this.global.isHelpOnInvalidCommand();\n    }\n\n    @Override\n    public boolean isHelpOnNoPermission() {\n        return this.global.isHelpOnNoPermission();\n    }\n\n    @Override\n    public boolean isCacheSchematics() {\n        return this.global.isCacheSchematics();\n    }\n\n    @Override\n    public Map<String, KeySet> getEntityCategories() {\n        Map<String, KeySet> categories = new HashMap<>();\n        for (EntityCategory entityCategory : getEntityCategoriesMap().getCategories()) {\n            categories.put(entityCategory.getName(), entityCategory.getEntities());\n        }\n        return categories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(categories);\n    }\n\n    @Override\n    public EntityCategories getEntityCategoriesMap() {\n        return this.global.getEntityCategoriesMap();\n    }\n\n    public void updateValue(String path, Object value) throws IOException {\n        File file = new File(plugin.getDataFolder(), \"config.yml\");\n\n        if (!file.exists())\n            plugin.saveResource(\"config.yml\", false);\n\n        CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file);\n        cfg.syncWithConfig(file, plugin.getResource(\"config.yml\"), \"config.yml\",\n                \"ladder\", \"commands-cooldown\", \"containers\", \"event-commands\", \"command-aliases\", \"island-previews.locations\", \"worlds.dimensions\");\n\n        cfg.set(path, value);\n\n        cfg.save(file);\n\n        try {\n            loadContainerFromConfig(cfg);\n        } catch (ManagerLoadException ex) {\n            ManagerLoadException.handle(ex);\n        }\n    }\n\n    private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadException {\n        SettingsContainer container = new SettingsContainer(plugin, cfg);\n        this.global.setContainer(container);\n        this.database.setContainer(container);\n        this.defaultValues.setContainer(container);\n        this.stackedBlocks.setContainer(container);\n        this.islandRoles.setContainer(container);\n        this.visitorsSign.setContainer(container);\n        this.worlds.setContainer(container);\n        this.spawn.setContainer(container);\n        this.voidTeleport.setContainer(container);\n        this.islandNames.setContainer(container);\n        this.afkIntegrations.setContainer(container);\n        this.defaultContainers.setContainer(container);\n        this.islandChests.setContainer(container);\n        this.islandPreviews.setContainer(container);\n    }\n\n    private void convertData(YamlConfiguration cfg) {\n        if (cfg.getConfigurationSection(\"worlds.dimensions\") == null) {\n            cfg.set(\"worlds.dimensions.normal\", cfg.getConfigurationSection(\"worlds.normal\"));\n            cfg.set(\"worlds.dimensions.normal.environment\", \"NORMAL\");\n            cfg.set(\"worlds.dimensions.normal.portals.NETHER\", \"nether\");\n            cfg.set(\"worlds.dimensions.normal.portals.ENDER\", \"the_end\");\n            cfg.set(\"worlds.normal\", null);\n            cfg.set(\"worlds.dimensions.nether\", cfg.getConfigurationSection(\"worlds.nether\"));\n            cfg.set(\"worlds.dimensions.nether.environment\", \"NETHER\");\n            cfg.set(\"worlds.dimensions.nether.portals.NETHER\", \"normal\");\n            cfg.set(\"worlds.dimensions.nether.portals.ENDER\", \"the_end\");\n            cfg.set(\"worlds.nether\", null);\n            cfg.set(\"worlds.dimensions.the_end\", cfg.getConfigurationSection(\"worlds.end\"));\n            cfg.set(\"worlds.dimensions.the_end.environment\", \"THE_END\");\n            cfg.set(\"worlds.dimensions.the_end.portals.NETHER\", \"nether\");\n            cfg.set(\"worlds.dimensions.the_end.portals.ENDER\", \"normal\");\n            cfg.set(\"worlds.end\", null);\n        }\n        if (cfg.get(\"island-level-formula\") != null) {\n            cfg.set(\"block-level-formula\", cfg.getString(\"island-level-formula\"));\n            cfg.set(\"island-level-formula\", null);\n        }\n        if (cfg.get(\"protected-message-delay\") instanceof Number) {\n            long delay = cfg.getLong(\"protected-message-delay\") * 50;\n            cfg.set(\"message-delays.ISLAND_PROTECTED\", delay);\n            cfg.set(\"message-delays.ISLAND_PROTECTED_OPPED\", delay);\n            cfg.set(\"message-delays.SPAWN_PROTECTED\", delay);\n            cfg.set(\"message-delays.SPAWN_PROTECTED_OPPED\", delay);\n            cfg.set(\"protected-message-delay\", null);\n        }\n        if (cfg.isConfigurationSection(\"preview-islands\")) {\n            cfg.set(\"island-previews.locations\", cfg.getConfigurationSection(\"preview-islands\"));\n            cfg.set(\"preview-islands\", null);\n        }\n        if (cfg.isBoolean(\"disband-inventory-clear\")) {\n            if (cfg.getBoolean(\"disband-inventory-clear\")) {\n                cfg.set(\"clear-on-disband\", Arrays.asList(\"ENDER_CHEST\", \"INVENTORY\"));\n            } else {\n                cfg.set(\"clear-on-disband\", Collections.emptyList());\n            }\n            cfg.set(\"disband-inventory-clear\", null);\n        }\n        if (cfg.isBoolean(\"clear-on-join\")) {\n            if (cfg.getBoolean(\"disband-inventory-clear\")) {\n                cfg.set(\"clear-on-join\", Arrays.asList(\"ENDER_CHEST\", \"INVENTORY\"));\n            } else {\n                cfg.set(\"clear-on-join\", Collections.emptyList());\n            }\n        }\n        if (cfg.isInt(\"disband-count\")) {\n            cfg.set(\"default-disband-count\", cfg.getInt(\"disband-count\") == 0 ? -1 : cfg.getInt(\"disband-count\"));\n            cfg.set(\"disband-count\", null);\n        }\n        if (cfg.isInt(\"default-hoppers-limit\")) {\n            cfg.set(\"default-limits\", Collections.singletonList(\"HOPPER:\" + cfg.getInt(\"default-hoppers-limit\")));\n            cfg.set(\"default-hoppers-limit\", null);\n        }\n        if (cfg.isConfigurationSection(\"default-permissions\")) {\n            cfg.set(\"island-roles.guest.name\", \"Guest\");\n            cfg.set(\"island-roles.guest.permissions\", cfg.getStringList(\"default-permissions.guest\"));\n            cfg.set(\"island-roles.ladder.member.name\", \"Member\");\n            cfg.set(\"island-roles.ladder.member.weight\", 0);\n            cfg.set(\"island-roles.ladder.member.permissions\", cfg.getStringList(\"default-permissions.member\"));\n            cfg.set(\"island-roles.ladder.mod.name\", \"Moderator\");\n            cfg.set(\"island-roles.ladder.mod.weight\", 1);\n            cfg.set(\"island-roles.ladder.mod.permissions\", cfg.getStringList(\"default-permissions.mod\"));\n            cfg.set(\"island-roles.ladder.admin.name\", \"Admin\");\n            cfg.set(\"island-roles.ladder.admin.weight\", 2);\n            cfg.set(\"island-roles.ladder.admin.permissions\", cfg.getStringList(\"default-permissions.admin\"));\n            cfg.set(\"island-roles.ladder.leader.name\", \"Leader\");\n            cfg.set(\"island-roles.ladder.leader.weight\", 3);\n            cfg.set(\"island-roles.ladder.leader.permissions\", cfg.getStringList(\"default-permissions.leader\"));\n        }\n        if (cfg.isString(\"spawn-location\"))\n            cfg.set(\"spawn.location\", cfg.getString(\"spawn-location\"));\n        if (cfg.isBoolean(\"spawn-protection\"))\n            cfg.set(\"spawn.protection\", cfg.getBoolean(\"spawn-protection\"));\n        if (cfg.getBoolean(\"spawn-pvp\", false))\n            cfg.set(\"spawn.settings\", Collections.singletonList(\"PVP\"));\n        if (cfg.isString(\"island-world\"))\n            cfg.set(\"worlds.normal-world\", cfg.getString(\"island-world\"));\n        if (cfg.isString(\"welcome-sign-line\"))\n            cfg.set(\"visitors-sign.line\", cfg.getString(\"welcome-sign-line\"));\n        if (cfg.isConfigurationSection(\"island-roles.ladder\")) {\n            for (String name : cfg.getConfigurationSection(\"island-roles.ladder\").getKeys(false)) {\n                if (!cfg.isInt(\"island-roles.ladder.\" + name + \".id\"))\n                    cfg.set(\"island-roles.ladder.\" + name + \".id\", cfg.getInt(\"island-roles.ladder.\" + name + \".weight\"));\n            }\n        }\n        if (cfg.isInt(\"default-island-size\"))\n            cfg.set(\"default-values.island-size\", cfg.getInt(\"default-island-size\"));\n        if (cfg.isList(\"default-limits\"))\n            cfg.set(\"default-values.block-limits\", cfg.getStringList(\"default-limits\"));\n        if (cfg.isList(\"default-entity-limits\"))\n            cfg.set(\"default-values.entity-limits\", cfg.getStringList(\"default-entity-limits\"));\n        if (cfg.isInt(\"default-warps-limit\"))\n            cfg.set(\"default-values.warps-limit\", cfg.getInt(\"default-warps-limit\"));\n        if (cfg.isInt(\"default-team-limit\"))\n            cfg.set(\"default-values.team-limit\", cfg.getInt(\"default-team-limit\"));\n        if (cfg.isInt(\"default-crop-growth\"))\n            cfg.set(\"default-values.crop-growth\", cfg.getInt(\"default-crop-growth\"));\n        if (cfg.isInt(\"default-spawner-rates\"))\n            cfg.set(\"default-values.spawner-rates\", cfg.getInt(\"default-spawner-rates\"));\n        if (cfg.isInt(\"default-mob-drops\"))\n            cfg.set(\"default-values.mob-drops\", cfg.getInt(\"default-mob-drops\"));\n        if (cfg.isInt(\"default-island-height\"))\n            cfg.set(\"islands-height\", cfg.getInt(\"default-island-height\"));\n        if (cfg.isConfigurationSection(\"starter-chest\")) {\n            cfg.set(\"default-containers.enabled\", cfg.getBoolean(\"starter-chest.enabled\"));\n            cfg.set(\"default-containers.containers.chest\", cfg.getConfigurationSection(\"starter-chest.contents\"));\n        }\n        if (cfg.isList(\"default-generator\"))\n            cfg.set(\"default-values.generator\", cfg.getStringList(\"default-generator\"));\n        if (cfg.isBoolean(\"void-teleport\")) {\n            boolean voidTeleport = cfg.getBoolean(\"void-teleport\");\n            cfg.set(\"void-teleport.members\", voidTeleport);\n            cfg.set(\"void-teleport.visitors\", voidTeleport);\n        }\n        if (cfg.isBoolean(\"sync-worth\"))\n            cfg.set(\"sync-worth\", cfg.getBoolean(\"sync-worth\") ? \"BUY\" : \"NONE\");\n        if (!cfg.isConfigurationSection(\"worlds.nether\")) {\n            cfg.set(\"worlds.nether.enabled\", cfg.getBoolean(\"worlds.nether-world\"));\n            cfg.set(\"worlds.nether.unlock\", cfg.getBoolean(\"worlds.nether-unlock\"));\n        }\n        if (!cfg.isConfigurationSection(\"worlds.end\")) {\n            cfg.set(\"worlds.end.enabled\", cfg.getBoolean(\"worlds.end-world\"));\n            cfg.set(\"worlds.end.unlock\", cfg.getBoolean(\"worlds.end-unlock\"));\n        }\n        if (cfg.isString(\"worlds.normal-world\")) {\n            cfg.set(\"worlds.world-name\", cfg.getString(\"worlds.normal-world\"));\n            cfg.set(\"worlds.normal-world\", null);\n        }\n        if (cfg.isBoolean(\"worlds.end.dragon-fight\")) {\n            cfg.set(\"worlds.end.dragon-fight.enabled\", cfg.getBoolean(\"worlds.end.dragon-fight\"));\n        }\n        if (!cfg.isConfigurationSection(\"default-values.island-effects\"))\n            cfg.createSection(\"default-values.island-effects\");\n    }\n\n    private void convertInteractables(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) {\n        if (!cfg.isList(\"interactables\"))\n            return;\n\n        File file = new File(plugin.getDataFolder(), \"interactables.yml\");\n\n        if (!file.exists())\n            plugin.saveResource(\"interactables.yml\", false);\n\n        CommentedConfiguration commentedConfig = CommentedConfiguration.loadConfiguration(file);\n\n        commentedConfig.set(\"interactables\", cfg.getStringList(\"interactables\"));\n\n        try {\n            commentedConfig.save(file);\n            cfg.set(\"interactables\", null);\n        } catch (Exception error) {\n            Log.errorFromFile(error, file.getName(), \"An unexpected error occurred while saving file:\");\n        }\n\n    }\n\n    private void convertEntityCategories(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) {\n        if (!cfg.isConfigurationSection(\"entity-categories\"))\n            return;\n\n        File file = new File(plugin.getDataFolder(), \"entity-categories.yml\");\n\n        if (!file.exists())\n            plugin.saveResource(\"entity-categories.yml\", false);\n\n        CommentedConfiguration commentedConfig = CommentedConfiguration.loadConfiguration(file);\n\n        for (String categoryName : cfg.getConfigurationSection(\"entity-categories\").getKeys(false)) {\n            List<String> entities = cfg.getStringList(\"entity-categories.\" + categoryName);\n            if (!entities.isEmpty()) {\n                categoryName = categoryName.toUpperCase(Locale.ENGLISH);\n                commentedConfig.set(categoryName + \".entities\", entities);\n                commentedConfig.set(categoryName + \".actions.SPAWN\", categoryName + \"_SPAWN\");\n                commentedConfig.set(categoryName + \".actions.DAMAGE\", categoryName + \"_DAMAGE\");\n                commentedConfig.set(categoryName + \".actions.SPAWNER_SPAWN\", \"SPAWNER_\" + categoryName + \"_SPAWN\");\n                commentedConfig.set(categoryName + \".actions.NATURAL_SPAWN\", \"NATURAL_\" + categoryName + \"_SPAWN\");\n            }\n        }\n\n        try {\n            commentedConfig.save(file);\n            cfg.set(\"entity-categories\", null);\n        } catch (Exception error) {\n            Log.errorFromFile(error, file.getName(), \"An unexpected error occurred while saving file:\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/AFKIntegrationsSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\npublic class AFKIntegrationsSection extends SettingsContainerHolder implements SettingsManager.AFKIntegrations {\n\n    @Override\n    public boolean isDisableRedstone() {\n        return getContainer().disableRedstoneAFK;\n    }\n\n    @Override\n    public boolean isDisableSpawning() {\n        return getContainer().disableSpawningAFK;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/DatabaseSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\npublic class DatabaseSection extends SettingsContainerHolder implements SettingsManager.Database {\n\n    @Override\n    public String getType() {\n        return getContainer().databaseType;\n    }\n\n    @Override\n    public boolean isBackup() {\n        return getContainer().databaseBackup;\n    }\n\n    @Override\n    public String getAddress() {\n        return getContainer().databaseMySQLAddress;\n    }\n\n    @Override\n    public int getPort() {\n        return getContainer().databaseMySQLPort;\n    }\n\n    @Override\n    public String getDBName() {\n        return getContainer().databaseMySQLDBName;\n    }\n\n    @Override\n    public String getUsername() {\n        return getContainer().databaseMySQLUsername;\n    }\n\n    @Override\n    public String getPassword() {\n        return getContainer().databaseMySQLPassword;\n    }\n\n    @Override\n    public String getPrefix() {\n        return getContainer().databaseMySQLPrefix;\n    }\n\n    @Override\n    public boolean hasSSL() {\n        return getContainer().databaseMySQLSSL;\n    }\n\n    @Override\n    public boolean hasPublicKeyRetrieval() {\n        return getContainer().databaseMySQLPublicKeyRetrieval;\n    }\n\n    @Override\n    public long getWaitTimeout() {\n        return getContainer().databaseMySQLWaitTimeout;\n    }\n\n    @Override\n    public long getMaxLifetime() {\n        return getContainer().databaseMySQLMaxLifetime;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultContainersSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport org.bukkit.event.inventory.InventoryType;\n\npublic class DefaultContainersSection extends SettingsContainerHolder implements SettingsManager.DefaultContainers {\n\n    @Override\n    public boolean isEnabled() {\n        return getContainer().defaultContainersEnabled;\n    }\n\n    public ListTag getContents(InventoryType inventoryType) {\n        return getContainer().defaultContainersContents.get(inventoryType);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class DefaultValuesSection extends SettingsContainerHolder implements SettingsManager.DefaultValues {\n\n    @Override\n    public int getIslandSize() {\n        return getContainer().defaultIslandSize;\n    }\n\n    @Override\n    public Map<Key, Integer> getBlockLimits() {\n        return getContainer().defaultBlockLimits;\n    }\n\n    @Override\n    public Map<Key, Integer> getEntityLimits() {\n        return getContainer().defaultEntityLimits;\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return getContainer().defaultWarpsLimit;\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return getContainer().defaultTeamLimit;\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return getContainer().defaultCoopLimit;\n    }\n\n    @Override\n    public double getCropGrowth() {\n        return getContainer().defaultCropGrowth;\n    }\n\n    @Override\n    public double getSpawnerRates() {\n        return getContainer().defaultSpawnerRates;\n    }\n\n    @Override\n    public double getMobDrops() {\n        return getContainer().defaultMobDrops;\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return getContainer().defaultBankLimit;\n    }\n\n    @Override\n    public Map<Key, Integer>[] getGenerators() {\n        Map<Key, Integer>[] generators = new Map[Dimension.values().size()];\n\n        if (!getContainer().defaultGenerator.isEmpty()) {\n            for (Dimension dimension : Dimension.values()) {\n                Map<Key, Integer> dimensionGeneratorRates = getContainer().defaultGenerator.get(dimension);\n                if (dimensionGeneratorRates != null)\n                    generators[dimension.ordinal()] = dimensionGeneratorRates;\n            }\n        }\n\n        return generators;\n    }\n\n    @Override\n    public Map<Dimension, Map<Key, Integer>> getGeneratorsMap() {\n        return getContainer().defaultGenerator.collect(Dimension.values());\n    }\n\n    public EnumerateMap<Dimension, Map<Key, Integer>> getRealGeneratorsMap() {\n        return getContainer().defaultGenerator;\n    }\n\n    @Override\n    public Map<Integer, Integer> getRoleLimits() {\n        return Collections.unmodifiableMap(getContainer().defaultRoleLimits.asMap());\n    }\n\n    public Int2IntMapView getRoleLimitsAsView() {\n        return getContainer().defaultRoleLimits;\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getIslandEffects() {\n        return getContainer().defaultIslandEffects;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport com.bgsoftware.superiorskyblock.world.entity.EntityCategoryImpl;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.entity.EntityType;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class EntityCategoriesSection implements SettingsManager.EntityCategories {\n\n    private final Map<String, EntityCategory> nameToCategory;\n    private final KeyMap<List<EntityCategory>> entityToCategory;\n\n    private final LazyReference<List<EntityCategory>> entityCategories = new LazyReference<List<EntityCategory>>() {\n        @Override\n        protected List<EntityCategory> create() {\n            return nameToCategory.isEmpty() ? Collections.emptyList() :\n                    Collections.unmodifiableList(new LinkedList<>(nameToCategory.values()));\n        }\n    };\n\n    public EntityCategoriesSection(YamlConfiguration cfg) {\n        this.nameToCategory = loadInternal(cfg);\n        this.entityToCategory = convertEntityToCategoryInternal(this.nameToCategory.values());\n    }\n\n    public static void removeInvalidEntityKeys(YamlConfiguration cfg, File file) {\n        boolean removed = false;\n        for (String categoryName : cfg.getKeys(false)) {\n            if (EnumHelper.getEnum(BuiltinEntityCategory.class, categoryName) == null) {\n                List<String> entities = cfg.getStringList(categoryName + \".entities\");\n                Iterator<String> iterator = entities.iterator();\n                while (iterator.hasNext()) {\n                    EntityType entityType = EnumHelper.getEnum(EntityType.class, iterator.next());\n                    if (entityType == null) {\n                        iterator.remove();\n                        removed = true;\n                    }\n                }\n                if (entities.isEmpty()) {\n                    cfg.set(categoryName, null);\n                } else {\n                    cfg.set(categoryName + \".entities\", entities);\n                }\n            }\n        }\n\n        if (removed) {\n            try {\n                cfg.save(file);\n            } catch (IOException ignored) {\n            }\n        }\n\n    }\n\n    private static Map<String, EntityCategory> loadInternal(YamlConfiguration cfg) {\n        Map<String, EntityCategory> entityCategories = new HashMap<>();\n\n        for (String categoryName : cfg.getKeys(false)) {\n            String key = categoryName.toLowerCase(Locale.ENGLISH);\n\n            if (entityCategories.containsKey(categoryName)) {\n                Log.warnFromFile(\"entity-categories.yml\", \"Duplicate entity category \", categoryName, \" - skipping...\");\n                continue;\n            }\n\n            ConfigurationSection section = cfg.getConfigurationSection(categoryName);\n\n            BuiltinEntityCategory builtinEntityCategory = EnumHelper.getEnum(BuiltinEntityCategory.class,\n                    categoryName.toUpperCase(Locale.ENGLISH));\n\n            KeySet entities = builtinEntityCategory != null ? builtinEntityCategory.getEntities() :\n                    KeySets.createHashSet(KeyIndicator.ENTITY_TYPE, section.getStringList(\"entities\"));\n\n            IslandPrivilege spawnPrivilege = getOrRegisterPrivilege(section.getString(\"actions.SPAWN\"));\n            IslandPrivilege damagePrivilege = getOrRegisterPrivilege(section.getString(\"actions.DAMAGE\"));\n            IslandPrivilege interactPrivilege = getOrRegisterPrivilege(section.getString(\"actions.INTERACT\"));\n            IslandFlag spawnerSpawnFlag = getOrRegisterFlag(section.getString(\"actions.SPAWNER_SPAWN\"));\n            IslandFlag naturalSpawnFlag = getOrRegisterFlag(section.getString(\"actions.NATURAL_SPAWN\"));\n\n            entityCategories.put(key, new EntityCategoryImpl(categoryName, entities, spawnPrivilege, damagePrivilege,\n                    interactPrivilege, spawnerSpawnFlag, naturalSpawnFlag));\n        }\n\n        // Add rest of built-in entity categories\n        for (BuiltinEntityCategory builtinEntityCategory : BuiltinEntityCategory.values()) {\n            if (!entityCategories.containsKey(builtinEntityCategory.name())) {\n                entityCategories.put(builtinEntityCategory.name(), new EntityCategoryImpl(builtinEntityCategory.name(),\n                        builtinEntityCategory.getEntities(), null, null,\n                        null, null, null));\n            }\n        }\n\n        return Collections.unmodifiableMap(entityCategories);\n    }\n\n    private static KeyMap<List<EntityCategory>> convertEntityToCategoryInternal(Collection<EntityCategory> entityCategories) {\n        KeyMap<List<EntityCategory>> categories = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE);\n        for (EntityCategory entityCategory : entityCategories) {\n            for (Key key : entityCategory.getEntities()) {\n                categories.computeIfAbsent(key, k -> new LinkedList<>()).add(entityCategory);\n            }\n        }\n        if (categories.isEmpty())\n            return KeyMaps.createEmptyMap();\n\n        // Convert keyMap to unmodifiable.\n        KeyMap<List<EntityCategory>> categoriesUnmodifiable = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE);\n        categories.forEach((key, value) -> categoriesUnmodifiable.put(key, Collections.unmodifiableList(value)));\n        return KeyMaps.unmodifiableKeyMap(categoriesUnmodifiable);\n    }\n\n    @Override\n    public List<EntityCategory> getCategories() {\n        return this.entityCategories.get();\n    }\n\n    @Override\n    public List<EntityCategory> getCategories(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        return this.entityToCategory.getOrDefault(key, Collections.emptyList());\n    }\n\n    @Override\n    public EntityCategory getCategoryByName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null\");\n        return this.nameToCategory.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Nullable\n    private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) {\n        if (name == null)\n            return null;\n\n        try {\n            return IslandPrivilege.getByName(name);\n        } catch (NullPointerException error) {\n            IslandPrivilege.register(name);\n            return IslandPrivilege.getByName(name);\n        }\n    }\n\n    @Nullable\n    private static IslandFlag getOrRegisterFlag(@Nullable String name) {\n        if (name == null)\n            return null;\n\n        try {\n            return IslandFlag.getByName(name);\n        } catch (NullPointerException error) {\n            IslandFlag.register(name);\n            return IslandFlag.getByName(name);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\nimport java.math.BigInteger;\nimport java.math.RoundingMode;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class GlobalSection extends SettingsContainerHolder {\n\n    public long getCalcInterval() {\n        return getContainer().calcInterval;\n    }\n\n    public String getIslandCommand() {\n        return getContainer().islandCommand;\n    }\n\n    public int getMaxIslandSize() {\n        return getContainer().maxIslandSize;\n    }\n\n    public int getIslandHeight() {\n        return getContainer().islandsHeight;\n    }\n\n    public int getSeaLevelHeight() {\n        return getContainer().seaLevelHeight;\n    }\n\n    public boolean isWorldBorders() {\n        return getContainer().worldBordersEnabled;\n    }\n\n    public String getBlockLevelFormula() {\n        return getContainer().blockLevelFormula;\n    }\n\n    public boolean isRoundedIslandLevels() {\n        return getContainer().roundedIslandLevel;\n    }\n\n    public RoundingMode getIslandLevelRoundingMode() {\n        return getContainer().islandLevelRoundingMode;\n    }\n\n    public boolean isAutoBlocksTracking() {\n        return getContainer().autoBlocksTracking;\n    }\n\n    public SortingType getIslandTopOrder() {\n        return getContainer().islandTopOrder;\n    }\n\n    public SortingType getGlobalWarpsOrder() {\n        return getContainer().globalWarpsOrder;\n    }\n\n    public boolean isCoopMembers() {\n        return getContainer().coopMembers;\n    }\n\n    public boolean isEditPlayerPermissions() {\n        return getContainer().editPlayerPermissions;\n    }\n\n    public String getSignWarpLine() {\n        return getContainer().signWarpLine;\n    }\n\n    public List<String> getSignWarp() {\n        return getContainer().signWarp;\n    }\n\n    public SettingsManager.Interactables getInteractablesMap() {\n        return getContainer().interactables;\n    }\n\n    public Collection<Key> getSafeBlocks() {\n        return getContainer().safeBlocks;\n    }\n\n    public Collection<String> getWorldPermissions() {\n        return getContainer().worldPermissions;\n    }\n\n    public boolean isVisitorsDamage() {\n        return getContainer().visitorsDamage;\n    }\n\n    public boolean isCoopDamage() {\n        return getContainer().coopDamage;\n    }\n\n    public int getDisbandCount() {\n        return getContainer().defaultDisbandCount;\n    }\n\n    public boolean isIslandTopIncludeLeader() {\n        return getContainer().islandTopIncludeLeader;\n    }\n\n    public Map<String, String> getDefaultPlaceholders() {\n        return getContainer().defaultPlaceholders;\n    }\n\n    public boolean isBanConfirm() {\n        return getContainer().banConfirm;\n    }\n\n    public boolean isDisbandConfirm() {\n        return getContainer().disbandConfirm;\n    }\n\n    public boolean isKickConfirm() {\n        return getContainer().kickConfirm;\n    }\n\n    public boolean isLeaveConfirm() {\n        return getContainer().leaveConfirm;\n    }\n\n    public boolean isTransferConfirm() {\n        return getContainer().transferConfirm;\n    }\n\n    public String getSpawnersProvider() {\n        return getContainer().spawnersProvider;\n    }\n\n    public String getStackedBlocksProvider() {\n        return getContainer().stackedBlocksProvider;\n    }\n\n    public boolean isTeleportOnCreate() {\n        return getContainer().teleportOnCreate;\n    }\n\n    public boolean isTeleportOnJoin() {\n        return getContainer().teleportOnJoin;\n    }\n\n    public boolean isTeleportOnKick() {\n        return getContainer().teleportOnKick;\n    }\n\n    public boolean isTeleportOnLeave() {\n        return getContainer().teleportOnLeave;\n    }\n\n    public List<ClearAction> getClearActionsOnDisband() {\n        return getContainer().clearActionsOnDisband;\n    }\n\n    public List<ClearAction> getClearActionsOnJoin() {\n        return getContainer().clearActionsOnJoin;\n    }\n\n    public List<ClearAction> getClearActionsOnKick() {\n        return getContainer().clearActionsOnKick;\n    }\n\n    public List<ClearAction> getClearActionsOnLeave() {\n        return getContainer().clearActionsOnLeave;\n    }\n\n    public boolean isRateOwnIsland() {\n        return getContainer().rateOwnIsland;\n    }\n\n    public boolean isChangeIslandRating() {\n        return getContainer().changeIslandRating;\n    }\n\n    public List<String> getDefaultSettings() {\n        return getContainer().defaultSettings;\n    }\n\n    public boolean isDisableRedstoneOffline() {\n        return getContainer().disableRedstoneOffline;\n    }\n\n    public Map<String, Pair<Integer, String>> getCommandsCooldown() {\n        return getContainer().commandsCooldown;\n    }\n\n    public long getUpgradeCooldown() {\n        return getContainer().upgradeCooldown;\n    }\n\n    public String getNumbersFormat() {\n        return getContainer().numberFormat;\n    }\n\n    public String getDateFormat() {\n        return getContainer().dateFormat;\n    }\n\n    public boolean isSkipOneItemMenus() {\n        return getContainer().skipOneItemMenus;\n    }\n\n    public boolean isTeleportOnPvPEnable() {\n        return getContainer().teleportOnPVPEnable;\n    }\n\n    public boolean isImmuneToPvPWhenTeleport() {\n        return getContainer().immuneToPVPWhenTeleport;\n    }\n\n    public List<String> getBlockedVisitorsCommands() {\n        return getContainer().blockedVisitorsCommands;\n    }\n\n    public List<String> getDefaultSign() {\n        return getContainer().defaultSignLines;\n    }\n\n    public Map<String, List<String>> getEventCommands() {\n        return getContainer().eventCommands;\n    }\n\n    public long getWarpsWarmup() {\n        return getContainer().warpsWarmup;\n    }\n\n    public long getHomeWarmup() {\n        return getContainer().homeWarmup;\n    }\n\n    public long getVisitWarmup() {\n        return getContainer().visitWarmup;\n    }\n\n    public boolean isLiquidUpdate() {\n        return getContainer().liquidUpdate;\n    }\n\n    public boolean isLightsUpdate() {\n        return getContainer().lightsUpdate;\n    }\n\n    public List<String> getPvPWorlds() {\n        return getContainer().pvpWorlds;\n    }\n\n    public boolean isStopLeaving() {\n        return getContainer().stopLeaving;\n    }\n\n    public boolean isValuesMenu() {\n        return getContainer().valuesMenu;\n    }\n\n    public List<String> getCropsToGrow() {\n        return getContainer().cropsToGrow;\n    }\n\n    public int getCropsInterval() {\n        return getContainer().cropsInterval;\n    }\n\n    public boolean isOnlyBackButton() {\n        return getContainer().onlyBackButton;\n    }\n\n    public boolean isBuildOutsideIsland() {\n        return getContainer().buildOutsideIsland;\n    }\n\n    public String getDefaultLanguage() {\n        return getContainer().defaultLanguage;\n    }\n\n    public boolean isDefaultWorldBorder() {\n        return getContainer().defaultWorldBorder;\n    }\n\n    public boolean isDefaultStackedBlocks() {\n        return getContainer().defaultBlocksStacker;\n    }\n\n    public boolean isDefaultToggledPanel() {\n        return getContainer().defaultToggledPanel;\n    }\n\n    public boolean isDefaultIslandFly() {\n        return getContainer().defaultIslandFly;\n    }\n\n    public String getDefaultBorderColor() {\n        return getContainer().defaultBorderColor;\n    }\n\n    public boolean isObsidianToLava() {\n        return getContainer().obsidianToLava;\n    }\n\n    public BlockValuesManager.SyncWorthStatus getSyncWorth() {\n        return getContainer().syncWorth;\n    }\n\n    public boolean isNegativeWorth() {\n        return getContainer().negativeWorth;\n    }\n\n    public boolean isNegativeLevel() {\n        return getContainer().negativeLevel;\n    }\n\n    public List<String> getDisabledEvents() {\n        return getContainer().disabledEvents;\n    }\n\n    public List<String> getDisabledCommands() {\n        return getContainer().disabledCommands;\n    }\n\n    public List<String> getDisabledHooks() {\n        return getContainer().disabledHooks;\n    }\n\n    public boolean isSchematicNameArgument() {\n        return getContainer().schematicNameArgument;\n    }\n\n    public Map<String, List<String>> getCommandAliases() {\n        return getContainer().commandAliases;\n    }\n\n    public Set<Key> getValuableBlocks() {\n        return getContainer().valuableBlocks;\n    }\n\n    public boolean isTabCompleteHideVanished() {\n        return getContainer().tabCompleteHideVanished;\n    }\n\n    public boolean isDropsUpgradePlayersMultiply() {\n        return getContainer().dropsUpgradePlayersMultiply;\n    }\n\n    public Map<String, Long> getMessageDelays() {\n        return getContainer().messageDelays;\n    }\n\n    public boolean isWarpCategories() {\n        return getContainer().warpCategories;\n    }\n\n    public boolean isPhysicsListener() {\n        return getContainer().physicsListener;\n    }\n\n    public double getChargeOnWarp() {\n        return getContainer().chargeOnWarp;\n    }\n\n    public boolean isPublicWarps() {\n        return getContainer().publicWarps;\n    }\n\n    public boolean isLockedIslands() {\n        return getContainer().lockedIslands;\n    }\n\n    public long getRecalcTaskTimeout() {\n        return getContainer().recalcTaskTimeout;\n    }\n\n    public boolean isAutoLanguageDetection() {\n        return getContainer().autoLanguageDetection;\n    }\n\n    public boolean isAutoUncoopWhenAlone() {\n        return getContainer().autoUncoopWhenAlone;\n    }\n\n    public TopIslandMembersSorting getTopIslandMembersSorting() {\n        return getContainer().islandTopMembersSorting;\n    }\n\n    public int getBossbarLimit() {\n        return getContainer().bossBarLimit;\n    }\n\n    public boolean getDeleteUnsafeWarps() {\n        return getContainer().deleteUnsafeWarps;\n    }\n\n    public List<RespawnAction> getPlayerRespawn() {\n        return getContainer().playerRespawnActions;\n    }\n\n    public BigInteger getBlockCountsSaveThreshold() {\n        return getContainer().blockCountsSaveThreshold;\n    }\n\n    public boolean getChatSigningSupport() {\n        return getContainer().chatSigningSupport;\n    }\n\n    public int getCommandsPerPage() {\n        return getContainer().commandsPerPage;\n    }\n\n    public boolean isHelpOnInvalidCommand() {\n        return getContainer().helpOnInvalidCommand;\n    }\n\n    public boolean isHelpOnNoPermission() {\n        return getContainer().helpOnNoPermission;\n    }\n\n    public boolean isCacheSchematics() {\n        return getContainer().cacheSchematics;\n    }\n\n    public SettingsManager.EntityCategories getEntityCategoriesMap() {\n        return getContainer().entityCategories;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\npublic class InteractablesSection implements SettingsManager.Interactables {\n\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_CHEST_ACCESS = lazyIslandPrivilege(\"CHEST_ACCESS\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_FARM_TRAMPING = lazyIslandPrivilege(\"FARM_TRAMPING\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_INTERACT = lazyIslandPrivilege(\"INTERACT\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_PICKUP_LECTERN_BOOK = lazyIslandPrivilege(\"PICKUP_LECTERN_BOOK\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_SIGN_INTERACT = lazyIslandPrivilege(\"SIGN_INTERACT\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_SPAWNER_BREAK = lazyIslandPrivilege(\"SPAWNER_BREAK\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_TURTLE_EGG_TRAMPING = lazyIslandPrivilege(\"TURTLE_EGG_TRAMPING\");\n    private static final LazyReference<IslandPrivilege> PRIVILEGE_USE = lazyIslandPrivilege(\"USE\");\n\n    private static final Material FARMLAND = EnumHelper.getEnum(Material.class, \"FARMLAND\", \"SOIL\");\n    @Nullable\n    private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, \"ROOTED_DIRT\");\n    @Nullable\n    private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, \"TURTLE_EGG\");\n    @Nullable\n    private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, \"SWEET_BERRY_BUSH\");\n    @Nullable\n    private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, \"CAVE_VINES\");\n    @Nullable\n    private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, \"CAVE_VINES_PLANT\");\n    @Nullable\n    private static final Material LECTERN = EnumHelper.getEnum(Material.class, \"LECTERN\");\n    @Nullable\n    private static final Material VAULT = EnumHelper.getEnum(Material.class, \"VAULT\");\n    @Nullable\n    private static final Material BLAST_FURNACE = EnumHelper.getEnum(Material.class, \"BLAST_FURNACE\");\n    @Nullable\n    private static final Material BURNING_FURNACE = EnumHelper.getEnum(Material.class, \"BURNING_FURNACE\");\n    @Nullable\n    private static final Material CHISELED_BOOKSHELF = EnumHelper.getEnum(Material.class, \"CHISELED_BOOKSHELF\");\n    @Nullable\n    private static final Material CRAFTER = EnumHelper.getEnum(Material.class, \"CRAFTER\");\n    @Nullable\n    private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, \"DECORATED_POT\");\n    @Nullable\n    private static final Material SMOKER = EnumHelper.getEnum(Material.class, \"SMOKER\");\n\n    private final Map<IslandPrivilege, KeySet> privilegeToInteractables;\n    private final KeyMap<IslandPrivilege> interactableToPrivilege;\n    private final SuperiorSkyblockPlugin plugin;\n    private final boolean legacy;\n\n    public InteractablesSection(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) {\n        this.plugin = plugin;\n        this.legacy = cfg.getKeys(false).size() == 1 && cfg.isList(\"interactables\");\n\n        Map<IslandPrivilege, KeySet> privilegeToInteractables = new IdentityHashMap<>();\n        if (this.legacy) {\n            loadLegacyInternal(cfg, privilegeToInteractables);\n        } else {\n            loadInternal(cfg, privilegeToInteractables);\n        }\n        this.privilegeToInteractables = privilegeToInteractables.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(privilegeToInteractables);\n        this.interactableToPrivilege = convertView(privilegeToInteractables);\n    }\n\n    private static KeyMap<IslandPrivilege> convertView(Map<IslandPrivilege, KeySet> base) {\n        KeyMap<IslandPrivilege> converted = KeyMaps.createHashMap(KeyIndicator.MATERIAL);\n        base.forEach((islandPrivilege, keySet) -> {\n            for (Key key : keySet) {\n                IslandPrivilege oldPrivilege = converted.put(key, islandPrivilege);\n                if (oldPrivilege != null) {\n                    Log.warnFromFile(\"interactables.yml\", \"The interactable block \", key, \" had two privileges: \", oldPrivilege, \", \", islandPrivilege);\n                }\n            }\n        });\n        return KeyMaps.unmodifiableKeyMap(converted);\n    }\n\n    public boolean isLegacy() {\n        return legacy;\n    }\n\n    @Override\n    public Set<Key> getInteractables() {\n        return Collections.unmodifiableSet(this.interactableToPrivilege.keySet());\n    }\n\n    @Override\n    @Nullable\n    public Set<Key> getInteractables(IslandPrivilege islandPrivilege) {\n        Set<Key> interactables = this.privilegeToInteractables.get(islandPrivilege);\n        return interactables == null || interactables.isEmpty() ? null : Collections.unmodifiableSet(interactables);\n    }\n\n    @Override\n    @Nullable\n    public IslandPrivilege getRequiredPrivilege(Key key) {\n        return this.interactableToPrivilege.get(key);\n    }\n\n    public void saveToFile(File file) throws IOException {\n        CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(plugin.getResource(\"interactables.yml\"));\n\n        Set<IslandPrivilege> islandPrivileges = new TreeSet<>(Comparator.comparing(IslandPrivilege::getName));\n        islandPrivileges.addAll(this.privilegeToInteractables.keySet());\n\n        boolean copyHeaderComment = true;\n        for(IslandPrivilege islandPrivilege : islandPrivileges) {\n            Set<String> keys = new TreeSet<>(String::compareTo);\n            this.privilegeToInteractables.get(islandPrivilege).forEach(key -> keys.add(key.toString()));\n            cfg.set(islandPrivilege.getName(), new LinkedList<>(keys));\n\n            if (copyHeaderComment) {\n                copyHeaderComment = false;\n                cfg.setComment(islandPrivilege.getName(), cfg.getComment(\"interactables\"));\n            } else {\n                cfg.setComment(islandPrivilege.getName(), \"\");\n            }\n        }\n\n        // Remove the default interactables\n        cfg.set(\"interactables\", null);\n\n        cfg.save(file);\n    }\n\n    private static void loadLegacyInternal(YamlConfiguration cfg, Map<IslandPrivilege, KeySet> interactablesMap) {\n        List<String> interactables = cfg.getStringList(\"interactables\");\n\n        for (String blockType : interactables) {\n            Key blockKey = Key.ofMaterialAndData(blockType);\n\n            IslandPrivilege islandPrivilege;\n            try {\n                Material material = ((MaterialKey) blockKey).getMaterial();\n\n                if (Materials.isChest(material)) {\n                    islandPrivilege = PRIVILEGE_CHEST_ACCESS.get();\n                } else if (material == LECTERN) {\n                    islandPrivilege = PRIVILEGE_PICKUP_LECTERN_BOOK.get();\n                } else if (isInventoryHolder(material)) {\n                    islandPrivilege = PRIVILEGE_USE.get();\n                } else if (Materials.isSign(material)) {\n                    islandPrivilege = PRIVILEGE_SIGN_INTERACT.get();\n                } else if (material == Materials.SPAWNER.toBukkitType()) {\n                    islandPrivilege = PRIVILEGE_SPAWNER_BREAK.get();\n                } else if (material == FARMLAND || material == ROOTED_DIRT || material == SWEET_BERRY_BUSH ||\n                        material == CAVE_VINES || material == CAVE_VINES_PLANT) {\n                    islandPrivilege = PRIVILEGE_FARM_TRAMPING.get();\n                } else if (material == TURTLE_EGG) {\n                    islandPrivilege = PRIVILEGE_TURTLE_EGG_TRAMPING.get();\n                } else {\n                    islandPrivilege = PRIVILEGE_INTERACT.get();\n                }\n\n            } catch (Throwable ignored) {\n                // In the case this is a custom block or something, default to INTERACT privilege.\n                islandPrivilege = PRIVILEGE_INTERACT.get();\n            }\n\n            interactablesMap.computeIfAbsent(islandPrivilege, p -> KeySets.createHashSet(KeyIndicator.MATERIAL))\n                    .add(blockKey);\n        }\n    }\n\n    private static boolean isInventoryHolder(Material material) {\n        return Materials.isShelf(material) || material == BLAST_FURNACE || material == Material.BREWING_STAND ||\n                material == BURNING_FURNACE || material == CHISELED_BOOKSHELF || material == CRAFTER ||\n                material == DECORATED_POT || material == Material.DISPENSER || material == Material.DROPPER ||\n                material == Material.FURNACE || material == Material.HOPPER || material == Material.JUKEBOX ||\n                material == SMOKER || material == VAULT;\n    }\n\n    private static void loadInternal(YamlConfiguration cfg, Map<IslandPrivilege, KeySet> interactablesMap) {\n        for (String islandPrivilegeName : cfg.getKeys(false)) {\n            try {\n                IslandPrivilege.register(islandPrivilegeName);\n            } catch (IllegalStateException ignored) {\n            }\n\n            IslandPrivilege islandPrivilege = IslandPrivilege.getByName(islandPrivilegeName);\n            KeySet keys = KeySets.createHashSet(KeyIndicator.MATERIAL, cfg.getStringList(islandPrivilegeName));\n            interactablesMap.put(islandPrivilege, keys);\n        }\n    }\n\n    private static LazyReference<IslandPrivilege> lazyIslandPrivilege(String name) {\n        return new LazyReference<IslandPrivilege>() {\n            @Override\n            protected IslandPrivilege create() {\n                try {\n                    IslandPrivilege.register(name);\n                } catch (IllegalStateException ignored) {\n                }\n\n                return IslandPrivilege.getByName(name);\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandChestsSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\npublic class IslandChestsSection extends SettingsContainerHolder implements SettingsManager.IslandChests {\n\n    @Override\n    public String getChestTitle() {\n        return getContainer().islandChestTitle;\n    }\n\n    @Override\n    public int getDefaultPages() {\n        return getContainer().islandChestsDefaultPage;\n    }\n\n    @Override\n    public int getDefaultSize() {\n        return getContainer().islandChestsDefaultSize;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\nimport java.util.List;\n\npublic class IslandNamesSection extends SettingsContainerHolder implements SettingsManager.IslandNames {\n\n    @Override\n    public boolean isRequiredForCreation() {\n        return getContainer().islandNamesRequiredForCreation;\n    }\n\n    @Override\n    public int getMaxLength() {\n        return getContainer().islandNamesMaxLength;\n    }\n\n    @Override\n    public int getMinLength() {\n        return getContainer().islandNamesMinLength;\n    }\n\n    @Override\n    public List<String> getFilteredNames() {\n        return getContainer().filteredIslandNames;\n    }\n\n    @Override\n    public boolean isColorSupport() {\n        return getContainer().islandNamesColorSupport;\n    }\n\n    @Override\n    public boolean isIslandTop() {\n        return getContainer().islandNamesIslandTop;\n    }\n\n    @Override\n    public boolean isPreventPlayerNames() {\n        return getContainer().islandNamesPreventPlayerNames;\n    }\n\n    @Override\n    public boolean isAnnounceChangeToAll() {\n        return getContainer().islandNamesAnnounceChangeToAll;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class IslandPreviewsSection extends SettingsContainerHolder implements SettingsManager.IslandPreviews {\n\n    @Override\n    public GameMode getGameMode() {\n        return getContainer().islandPreviewsGameMode;\n    }\n\n    @Override\n    public int getMaxDistance() {\n        return getContainer().islandPreviewsMaxDistance;\n    }\n\n    @Override\n    public List<String> getBlockedCommands() {\n        return getContainer().islandPreviewsBlockedCommands;\n    }\n\n    @Override\n    public Map<String, Location> getLocations() {\n        return getContainer().islandPreviewsLocations;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandRolesSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\nimport org.bukkit.configuration.ConfigurationSection;\n\npublic class IslandRolesSection extends SettingsContainerHolder implements SettingsManager.IslandRoles {\n\n    @Override\n    public ConfigurationSection getSection() {\n        return getContainer().islandRolesSection;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/SpawnSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\nimport java.util.List;\n\npublic class SpawnSection extends SettingsContainerHolder implements SettingsManager.Spawn {\n\n    @Override\n    public String getLocation() {\n        return getContainer().spawnLocation;\n    }\n\n    @Override\n    public boolean isProtected() {\n        return getContainer().spawnProtection;\n    }\n\n    @Override\n    public List<String> getSettings() {\n        return getContainer().spawnSettings;\n    }\n\n    @Override\n    public List<String> getPermissions() {\n        return getContainer().spawnPermissions;\n    }\n\n    @Override\n    public boolean isWorldBorder() {\n        return getContainer().spawnWorldBorder;\n    }\n\n    @Override\n    public int getSize() {\n        return getContainer().spawnSize;\n    }\n\n    @Override\n    public boolean isPlayersDamage() {\n        return getContainer().spawnDamage;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/StackedBlocksSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class StackedBlocksSection extends SettingsContainerHolder implements SettingsManager.StackedBlocks {\n    private final DepositMenu depositMenu = new DepositMenuSection();\n\n    @Override\n    public boolean isEnabled() {\n        return getContainer().stackedBlocksEnabled;\n    }\n\n    @Override\n    public String getCustomName() {\n        return getContainer().stackedBlocksName;\n    }\n\n    @Override\n    public List<String> getDisabledWorlds() {\n        return getContainer().stackedBlocksDisabledWorlds;\n    }\n\n    @Override\n    public Set<Key> getWhitelisted() {\n        return getContainer().whitelistedStackedBlocks;\n    }\n\n    @Override\n    public Map<Key, Integer> getLimits() {\n        return getContainer().stackedBlocksLimits;\n    }\n\n    @Override\n    public boolean isAutoCollect() {\n        return getContainer().stackedBlocksAutoPickup;\n    }\n\n    @Override\n    public DepositMenu getDepositMenu() {\n        return this.depositMenu;\n    }\n\n    private class DepositMenuSection implements DepositMenu {\n\n        @Override\n        public boolean isEnabled() {\n            return getContainer().stackedBlocksMenuEnabled;\n        }\n\n        @Override\n        public String getTitle() {\n            return getContainer().stackedBlocksMenuTitle;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\npublic class VisitorsSignSection extends SettingsContainerHolder implements SettingsManager.VisitorsSign {\n\n    @Override\n    public boolean isRequiredForVisit() {\n        return getContainer().visitorsSignRequiredForVisit;\n    }\n\n    @Override\n    public String getLine() {\n        return getContainer().visitorsSignLine;\n    }\n\n    @Override\n    public String getActive() {\n        return getContainer().visitorsSignActive;\n    }\n\n    @Override\n    public String getInactive() {\n        return getContainer().visitorsSignInactive;\n    }\n\n    @Override\n    public String getDescriptionLineFormat() {\n        return getContainer().visitorsSignDescriptionLineFormat;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/VoidTeleportSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\n\npublic class VoidTeleportSection extends SettingsContainerHolder implements SettingsManager.VoidTeleport {\n\n    @Override\n    public boolean isMembers() {\n        return getContainer().voidTeleportMembers;\n    }\n\n    @Override\n    public boolean isVisitors() {\n        return getContainer().voidTeleportVisitors;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java",
    "content": "package com.bgsoftware.superiorskyblock.config.section;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.config.SettingsContainerHolder;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\npublic class WorldsSection extends SettingsContainerHolder implements SettingsManager.Worlds {\n\n    @Override\n    public Dimension getDefaultWorldDimension() {\n        return getContainer().defaultWorldDimension;\n    }\n\n    @Override\n    @Deprecated\n    public World.Environment getDefaultWorld() {\n        return getDefaultWorldDimension().getEnvironment();\n    }\n\n    @Override\n    public String getWorldName() {\n        return getContainer().islandWorldName;\n    }\n\n    @Override\n    public String getDefaultWorldName() {\n        return getContainer().defaultWorldName;\n    }\n\n    @Override\n    public Normal getNormal() {\n        return (Normal) getDimensionConfig(Dimension.getByName(\"NORMAL\"));\n    }\n\n    @Override\n    public Nether getNether() {\n        return (Nether) getDimensionConfig(Dimension.getByName(\"NETHER\"));\n    }\n\n    @Override\n    public End getEnd() {\n        return (End) getDimensionConfig(Dimension.getByName(\"THE_END\"));\n    }\n\n    @Override\n    public String getDifficulty() {\n        return getContainer().worldsDifficulty;\n    }\n\n    @Override\n    public int getSeaLevelHeight() {\n        return getContainer().seaLevelHeight;\n    }\n\n    @Override\n    public DimensionConfig getDimensionConfig(Dimension dimension) {\n        return getContainer().dimensionConfigs.get(dimension);\n    }\n\n    public static abstract class BaseDimensionConfig implements DimensionConfig {\n\n        private final boolean isEnabled;\n        private final boolean isUnlocked;\n        private final boolean isSchematicOffset;\n        private final String biome;\n        private final String name;\n        private final Map<PortalType, Dimension> portalAgents;\n\n        protected BaseDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) {\n            this.isEnabled = section.getBoolean(\"enabled\");\n            this.isUnlocked = section.getBoolean(\"unlock\");\n            this.isSchematicOffset = section.getBoolean(\"schematic-offset\");\n            this.biome = section.getString(\"biome\");\n            String name = section.getString(\"name\");\n            this.name = Text.isBlank(name) ? defaultName : name;\n            this.portalAgents = loadPortalAgents(section.getConfigurationSection(\"portals\"), dimension);\n        }\n\n        private static Map<PortalType, Dimension> loadPortalAgents(@Nullable ConfigurationSection portals, Dimension dimension) {\n            EnumMap<PortalType, Dimension> portalAgents = new EnumMap<>(PortalType.class);\n            if (portals == null) {\n                // Map environment to dimension\n                Dimension normalDimension;\n                Dimension netherDimension;\n                Dimension endDimension;\n                {\n                    EnumMap<World.Environment, Dimension> environmentToDimension = new EnumMap<>(World.Environment.class);\n                    for (Dimension dim : Dimension.values()) {\n                        Dimension currentDimension = environmentToDimension.get(dim.getEnvironment());\n                        if (currentDimension == null || dim.ordinal() < currentDimension.ordinal())\n                            environmentToDimension.put(dim.getEnvironment(), dim);\n                    }\n                    normalDimension = environmentToDimension.get(World.Environment.NORMAL);\n                    netherDimension = environmentToDimension.get(World.Environment.NETHER);\n                    endDimension = environmentToDimension.get(World.Environment.THE_END);\n                }\n                // Set portal agent\n                switch (dimension.getEnvironment()) {\n                    case NORMAL:\n                        if (netherDimension != null)\n                            portalAgents.put(PortalType.NETHER, netherDimension);\n                        if (endDimension != null)\n                            portalAgents.put(PortalType.ENDER, endDimension);\n                        break;\n                    case NETHER:\n                        if (normalDimension != null)\n                            portalAgents.put(PortalType.NETHER, normalDimension);\n                        if (endDimension != null)\n                            portalAgents.put(PortalType.ENDER, endDimension);\n                        break;\n                    case THE_END:\n                        if (netherDimension != null)\n                            portalAgents.put(PortalType.NETHER, netherDimension);\n                        if (normalDimension != null)\n                            portalAgents.put(PortalType.ENDER, normalDimension);\n                        break;\n                }\n            } else {\n                for (PortalType portalType : PortalType.values()) {\n                    String destination = portals.getString(portalType.name());\n                    if (destination != null) {\n                        try {\n                            portalAgents.put(portalType, Dimension.getByName(destination));\n                        } catch (NullPointerException error) {\n                            Log.warnFromFile(\"config.yml\", \"Cannot find valid dimension \", destination, \" - skipping...\");\n                        }\n                    }\n                }\n            }\n            return portalAgents.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(portalAgents);\n        }\n\n        @Override\n        public boolean isEnabled() {\n            return this.isEnabled;\n        }\n\n        @Override\n        public boolean isUnlocked() {\n            return this.isUnlocked;\n        }\n\n        @Override\n        public boolean isSchematicOffset() {\n            return this.isSchematicOffset;\n        }\n\n        @Override\n        public String getBiome() {\n            return this.biome;\n        }\n\n        @Override\n        public String getName() {\n            return this.name;\n        }\n\n        @Override\n        public Dimension getPortalDestination(PortalType portalType) {\n            return this.portalAgents.get(portalType);\n        }\n    }\n\n    public static class NormalDimensionConfig extends BaseDimensionConfig implements Normal {\n\n        public NormalDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) {\n            super(section, dimension, defaultName);\n        }\n\n    }\n\n    public static class NetherDimensionConfig extends BaseDimensionConfig implements Nether {\n\n        public NetherDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) {\n            super(section, dimension, defaultName);\n        }\n\n    }\n\n    public static class EndDimensionConfig extends BaseDimensionConfig implements End {\n\n        private final boolean isDragonFlight;\n        private final BlockOffset portalOffset;\n\n        public EndDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) {\n            super(section, dimension, defaultName);\n            this.isDragonFlight = section.getBoolean(\"dragon-fight.enabled\") && ServerVersion.isAtLeast(ServerVersion.v1_9);\n            String portalOffset = section.getString(\"dragon-fight.portal-offset\");\n            BlockOffset endDragonFightPortalOffset = Serializers.OFFSET_SPACED_SERIALIZER.deserialize(portalOffset);\n            if (endDragonFightPortalOffset == null) {\n                Log.warnFromFile(\"config.yml\", \"Cannot parse portal-offset '\", portalOffset, \"' to a valid offset, skipping...\");\n                this.portalOffset = SBlockOffset.ZERO;\n            } else {\n                this.portalOffset = endDragonFightPortalOffset;\n            }\n        }\n\n        @Override\n        public boolean isDragonFight() {\n            return this.isDragonFlight;\n        }\n\n        @Override\n        public BlockOffset getPortalOffset() {\n            return this.portalOffset;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.function.Function;\n\n@SuppressWarnings(\"unchecked\")\npublic class BaseCacheImpl<K extends Enumerable> {\n\n    private final Synchronized<EnumerateMap<K, Object>> cache;\n\n    public BaseCacheImpl(Collection<K> keys) {\n        this.cache = Synchronized.of(new EnumerateMap<>(keys));\n    }\n\n    public final <T> T store(K key, T value) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(value, \"value parameter cannot be null\");\n\n        Object oldValue = this.cache.writeAndGet(cache -> cache.put(key, value));\n        return oldValue == null ? null : (T) oldValue;\n    }\n\n    public <T> T remove(K key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n\n        Object oldValue = this.cache.writeAndGet(cache -> cache.remove(key));\n        return oldValue == null ? null : (T) oldValue;\n    }\n\n    public <T> T get(K key) {\n        return getOrDefault(key, null);\n    }\n\n    public <T> T getOrDefault(K key, T def) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n\n        Object oldValue = this.cache.readAndGet(cache -> cache.get(key));\n        return oldValue == null ? def : (T) oldValue;\n    }\n\n    public <T> T computeIfAbsent(K key, Function<K, T> mappingFunction) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(mappingFunction, \"mappingFunction parameter cannot be null\");\n\n        return (T) this.cache.writeAndGet(cache -> {\n            Object value = cache.get(key);\n            if (value == null) {\n                value = mappingFunction.apply(key);\n                cache.put(key, value);\n            }\n            return value;\n        });\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.util.BitSet;\n\npublic class BigBitSet {\n\n    private static final int DEFAULT_CAPACITY = 4096 * 64;\n\n    private final BitSet[] backend;\n\n    private int size;\n\n    public BigBitSet(int nbits) {\n        this.backend = new BitSet[(int) Math.ceil((double) nbits / DEFAULT_CAPACITY)];\n        this.size = 0;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public void set(int pos) {\n        try {\n            int backendIdx = pos / DEFAULT_CAPACITY;\n            int bitSetIdx = pos % DEFAULT_CAPACITY;\n            BitSet bitSet = this.backend[backendIdx];\n            if (bitSet == null)\n                bitSet = this.backend[backendIdx] = new BitSet(DEFAULT_CAPACITY);\n            bitSet.set(bitSetIdx);\n            ++this.size;\n        } catch (IndexOutOfBoundsException error) {\n            throw new IndexOutOfBoundsException(\"Out of bounds for pos \" + pos);\n        }\n    }\n\n    public int nextSetBit(int fromIndex) {\n        int backendIdx = fromIndex / DEFAULT_CAPACITY;\n        int bitSetIdx = fromIndex % DEFAULT_CAPACITY;\n\n        return nextSetBitInternal(backendIdx, bitSetIdx);\n    }\n\n    private int nextSetBitInternal(int backendIdx, int bitSetIdx) {\n        if (backendIdx < 0 || backendIdx >= this.backend.length)\n            return -1;\n\n        BitSet bitSet = this.backend[backendIdx];\n        if (bitSet != null) {\n            int next = bitSet.nextSetBit(bitSetIdx);\n            if (next != -1) {\n                return backendIdx * DEFAULT_CAPACITY + next;\n            }\n        }\n\n        return nextSetBitInternal(backendIdx + 1, 0);\n    }\n\n    public int cardinality() {\n        int cardinality = 0;\n        for (BitSet bitSet : backend) {\n            if (bitSet != null)\n                cardinality += bitSet.cardinality();\n        }\n        return cardinality;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/ByteBigArray.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.util.Arrays;\n\npublic class ByteBigArray {\n\n    private static final short DEFAULT_CAPACITY = 4096;\n    private static final byte[][] EMPTY_BIG_ARRAY = {};\n\n    private byte[][] backend;\n\n    private final short capacity;\n\n    private int backendIdx = 0;\n    private short innerSize = 0;\n    private int size = 0;\n\n    private boolean readOnly = false;\n\n    public ByteBigArray() {\n        this(DEFAULT_CAPACITY);\n    }\n\n    public ByteBigArray(short capacity) {\n        this.capacity = capacity;\n        this.backend = EMPTY_BIG_ARRAY;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public void add(byte val) {\n        if (this.readOnly)\n            throw new IllegalStateException(\"Cannot alter big arrays that are finalized\");\n\n        getNextInnerArray()[this.innerSize++] = val;\n        ++this.size;\n    }\n\n    public byte get() {\n        return getNextInnerArray()[this.innerSize];\n    }\n\n    public byte get(int pos) {\n        int backendIdx = pos / this.capacity;\n        int innerIdx = pos % this.capacity;\n        return this.backend[backendIdx][innerIdx];\n    }\n\n    public ByteBigArray readOnly() {\n        int backendIdx = this.size / this.capacity;\n        int innerSize = this.size % this.capacity;\n\n        this.backend = Arrays.copyOf(this.backend, backendIdx + 1);\n        this.backend[this.backend.length - 1] = Arrays.copyOf(this.backend[this.backend.length - 1], innerSize);\n\n        this.readOnly = true;\n        return this;\n    }\n\n    private byte[] getNextInnerArray() {\n        if (this.innerSize >= this.capacity) {\n            ++this.backendIdx;\n            this.innerSize = 0;\n        }\n        if (this.backendIdx >= this.backend.length) {\n            this.backend = Arrays.copyOf(this.backend, this.backend.length + 1);\n            this.backend[this.backendIdx] = new byte[this.capacity];\n            this.innerSize = 0;\n        }\n\n        return this.backend[this.backendIdx];\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport org.bukkit.Location;\n\nimport java.util.List;\n\npublic class CalculatedChunk {\n\n    private final ChunkPosition chunkPosition;\n\n    protected CalculatedChunk(ChunkPosition chunkPosition) {\n        this.chunkPosition = chunkPosition;\n    }\n\n    public ChunkPosition getPosition() {\n        return chunkPosition;\n    }\n\n    public static class Blocks extends CalculatedChunk {\n\n        private final KeyMap<Counter> blockCounts;\n        private final List<Location> spawners;\n\n        public Blocks(ChunkPosition chunkPosition, KeyMap<Counter> blockCounts, List<Location> spawners) {\n            super(chunkPosition);\n            this.blockCounts = blockCounts;\n            this.spawners = spawners;\n        }\n\n        public KeyMap<Counter> getBlockCounts() {\n            return blockCounts;\n        }\n\n        public List<Location> getSpawners() {\n            return spawners;\n        }\n\n    }\n\n    public static class Entities extends CalculatedChunk {\n\n        private final KeyMap<Counter> entityCounts;\n\n        public Entities(ChunkPosition chunkPosition, KeyMap<Counter> entityCounts) {\n            super(chunkPosition);\n            this.entityCounts = entityCounts;\n        }\n\n        public KeyMap<Counter> getEntityCounts() {\n            return entityCounts;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\nimport java.util.Optional;\n\npublic class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable {\n\n    private static final ObjectsPool<ChunkPosition> POOL = new ObjectsPool<>(ChunkPosition::new);\n\n    protected WorldInfo worldInfo;\n    protected int x;\n    protected int z;\n\n    protected long pairedXZ = -1;\n    @Nullable\n    protected WeakReference<World> cachedBukkitWorld = new WeakReference<>(null);\n    private final boolean isPool;\n\n    public static ChunkPosition of(Location location) {\n        World world = location.getWorld();\n        return of(WorldInfo.of(world), location.getBlockX() >> 4, location.getBlockZ() >> 4).withBukkitWorld(world);\n    }\n\n    public static ChunkPosition of(WorldInfo worldInfo, WorldPosition worldPosition) {\n        BlockPosition blockPosition = worldPosition.toBlockPosition();\n        return of(worldInfo, blockPosition.getX() >> 4, blockPosition.getZ() >> 4);\n    }\n\n    public static ChunkPosition of(Chunk chunk) {\n        return of(chunk, true);\n    }\n\n    public static ChunkPosition of(Chunk chunk, boolean fromPool) {\n        World world = chunk.getWorld();\n        return of(WorldInfo.of(world), chunk.getX(), chunk.getZ(), fromPool).withBukkitWorld(world);\n    }\n\n    public static ChunkPosition of(World world, int x, int z) {\n        return of(world, x, z, true);\n    }\n\n    public static ChunkPosition of(World world, int x, int z, boolean fromPool) {\n        return of(WorldInfo.of(world), x, z, fromPool).withBukkitWorld(world);\n    }\n\n    public static ChunkPosition of(WorldInfo worldInfo, int x, int z) {\n        return of(worldInfo, x, z, true);\n    }\n\n    public static ChunkPosition of(WorldInfo worldInfo, int x, int z, boolean fromPool) {\n        ChunkPosition chunkPosition = fromPool ? POOL.obtain() : new ChunkPosition(false);\n        return chunkPosition.initialize(worldInfo, x, z);\n    }\n\n    public static ChunkPosition of(IslandWarp islandWarp) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return of(islandWarp.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    protected ChunkPosition() {\n        this(true);\n    }\n\n    protected ChunkPosition(boolean isPool) {\n        this.isPool = isPool;\n    }\n\n    private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) {\n        this.worldInfo = worldInfo;\n        this.x = x;\n        this.z = z;\n        return this;\n    }\n\n    public World getWorld() {\n        World cachedBukkitWorld = this.cachedBukkitWorld.get();\n        if (cachedBukkitWorld == null) {\n            cachedBukkitWorld = Bukkit.getWorld(getWorldName());\n            this.cachedBukkitWorld = new WeakReference<>(cachedBukkitWorld);\n        }\n\n        return cachedBukkitWorld;\n    }\n\n    public WorldInfo getWorldsInfo() {\n        return this.worldInfo;\n    }\n\n    public String getWorldName() {\n        return this.worldInfo.getName();\n    }\n\n    public int getX() {\n        return x;\n    }\n\n    public int getZ() {\n        return z;\n    }\n\n    public long asPair() {\n        if (this.pairedXZ < 0)\n            pairedXZ = (long) this.x & 4294967295L | ((long) this.z & 4294967295L) << 32;\n\n        return pairedXZ;\n    }\n\n    public boolean isInsideChunk(Location location) {\n        return location.getWorld().getName().equals(worldInfo.getName()) &&\n                location.getBlockX() >> 4 == x && location.getBlockZ() >> 4 == z;\n    }\n\n    public int distanceSquared(ChunkPosition other) {\n        int deltaX = this.x - other.x;\n        int deltaZ = this.z - other.z;\n        return (deltaX * deltaX) + (deltaZ * deltaZ);\n    }\n\n    @Override\n    public void release() {\n        if (!isPool)\n            return;\n\n        this.worldInfo = null;\n        this.pairedXZ = -1;\n        this.cachedBukkitWorld.clear();\n        POOL.release(this);\n    }\n\n    public ChunkPosition copy() {\n        return new ChunkPosition(false).initialize(this.worldInfo, this.x, this.z);\n    }\n\n    @Override\n    public void close() {\n        release();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(worldInfo.getName(), x, z);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        ChunkPosition that = (ChunkPosition) o;\n        return x == that.x &&\n                z == that.z &&\n                worldInfo.getName().equals(that.worldInfo.getName());\n    }\n\n    @Override\n    public String toString() {\n        return worldInfo.getName() + \", \" + x + \", \" + z;\n    }\n\n    private ChunkPosition withBukkitWorld(World world) {\n        this.cachedBukkitWorld = new WeakReference<>(world);\n        return this;\n    }\n\n    public static Optional<Chunk> getLoadedChunk(ChunkPosition chunkPosition) {\n        boolean isChunkLoaded = chunkPosition.getWorld().isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ());\n        if (!isChunkLoaded) return Optional.empty();\n        return Optional.of(chunkPosition.getWorld().getChunkAt(chunkPosition.getX(), chunkPosition.getZ()));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Counter.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\npublic class Counter {\n\n    private int value;\n\n    public Counter(int initialValue) {\n        this.value = initialValue;\n    }\n\n    public int inc(int delta) {\n        int original = this.value;\n        this.value += delta;\n        return original;\n    }\n\n    public int set(int value) {\n        int original = this.value;\n        this.value = value;\n        return original;\n    }\n\n    public int get() {\n        return this.value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/DirtyChunk.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.util.Objects;\n\npublic class DirtyChunk {\n\n    private final String worldName;\n    private final int x;\n    private final int z;\n\n    public DirtyChunk(String worldName, int x, int z) {\n        this.worldName = worldName;\n        this.x = x;\n        this.z = z;\n    }\n\n    public String getWorldName() {\n        return worldName;\n    }\n\n    public int getX() {\n        return x;\n    }\n\n    public int getZ() {\n        return z;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        DirtyChunk that = (DirtyChunk) o;\n        return x == that.x && z == that.z && worldName.equals(that.worldName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(worldName, x, z);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/DynamicArray.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class DynamicArray<E> {\n\n    private Object[] elements;\n\n    public DynamicArray() {\n        this(0);\n    }\n\n    public DynamicArray(int capacity) {\n        this.elements = new Object[capacity];\n    }\n\n    @Nullable\n    public E get(int index) {\n        rangeCheck(index);\n        return (E) elements[index];\n    }\n\n    @Nullable\n    public E set(int index, E element) {\n        ensureCapacity(index + 1);\n        E current = (E) elements[index];\n        elements[index] = element;\n        return current;\n    }\n\n    public int length() {\n        return this.elements.length;\n    }\n\n    public List<E> toList() {\n        return Arrays.asList((E[]) this.elements);\n    }\n\n    private void rangeCheck(int index) {\n        if (index < 0 || index > elements.length)\n            throw new ArrayIndexOutOfBoundsException(\"Index: \" + index + \", Size: \" + elements.length);\n    }\n\n    private void ensureCapacity(int capacity) {\n        if (capacity > elements.length) {\n            this.elements = Arrays.copyOf(this.elements, capacity);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Either.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.function.Consumer;\n\npublic abstract class Either<L, R> {\n\n    public static <R, L> Either<L, R> right(R value) {\n        return new Right<>(value);\n    }\n\n    public static <R, L> Either<L, R> left(L value) {\n        return new Left<>(value);\n    }\n\n    public abstract Either<L, R> ifRight(Consumer<R> consumer);\n\n    public abstract Either<L, R> ifLeft(Consumer<L> consumer);\n\n    @Nullable\n    public abstract R getRight();\n\n    @Nullable\n    public abstract L getLeft();\n\n    private static class Right<L, R> extends Either<L, R> {\n\n        private final R value;\n\n        Right(R value) {\n            this.value = value;\n        }\n\n        @Override\n        public Either<L, R> ifRight(Consumer<R> consumer) {\n            consumer.accept(this.value);\n            return this;\n        }\n\n        @Override\n        public Either<L, R> ifLeft(Consumer<L> consumer) {\n            // Do nothing\n            return this;\n        }\n\n        @Override\n        public R getRight() {\n            return this.value;\n        }\n\n        @Override\n        public L getLeft() {\n            return null;\n        }\n\n    }\n\n    private static class Left<L, R> extends Either<L, R> {\n\n        private final L value;\n\n        Left(L value) {\n            this.value = value;\n        }\n\n        @Override\n        public Either<L, R> ifRight(Consumer<R> consumer) {\n            // Do nothing\n            return this;\n        }\n\n        @Override\n        public Either<L, R> ifLeft(Consumer<L> consumer) {\n            consumer.accept(this.value);\n            return this;\n        }\n\n        @Override\n        public R getRight() {\n            return null;\n        }\n\n        @Override\n        public L getLeft() {\n            return this.value;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/EnumHelper.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.lang.reflect.Field;\n\npublic class EnumHelper {\n\n    private EnumHelper() {\n\n    }\n\n    @Nullable\n    public static <T> T getEnum(Class<T> enumClass, String name) {\n        return enumClass.isInterface() ? getInterfaceEnumValue(enumClass, name) : getEnumValue(enumClass, name);\n    }\n\n    public static <T> T getEnum(Class<T> enumClass, String... names) {\n        if(enumClass.isInterface()) {\n            for (String name : names) {\n                T enumValue = getInterfaceEnumValue(enumClass, name);\n                if (enumValue != null)\n                    return enumValue;\n            }\n        } else {\n            for (String name : names) {\n                T enumValue = getEnumValue(enumClass, name);\n                if (enumValue != null)\n                    return enumValue;\n            }\n        }\n\n        return null;\n    }\n\n    @Nullable\n    private static <T> T getInterfaceEnumValue(Class<T> enumClass, String name) {\n        try {\n            Field field = enumClass.getDeclaredField(name);\n            return (T) field.get(null);\n        } catch (Throwable error) {\n            return null;\n        }\n    }\n\n    @Nullable\n    private static <T> T getEnumValue(Class enumClass, String name) {\n        try {\n            return (T) Enum.valueOf(enumClass, name);\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport org.bukkit.Location;\nimport org.bukkit.Sound;\nimport org.bukkit.entity.HumanEntity;\nimport org.bukkit.entity.Player;\n\npublic class GameSoundImpl implements GameSound {\n\n    private final Sound sound;\n    private final float volume;\n    private final float pitch;\n\n    public GameSoundImpl(Sound sound, float volume, float pitch) {\n        this.sound = sound;\n        this.volume = volume;\n        this.pitch = pitch;\n    }\n\n    public Sound getSound() {\n        return sound;\n    }\n\n    public float getVolume() {\n        return volume;\n    }\n\n    public float getPitch() {\n        return pitch;\n    }\n\n    public static boolean isEmpty(@Nullable GameSound gameSound) {\n        return gameSound == null || gameSound.getSound() == null || gameSound.getVolume() <= 0 || gameSound.getPitch() <= 0;\n    }\n\n    public static void playSound(HumanEntity humanEntity, @Nullable GameSound gameSound) {\n        if (!isEmpty(gameSound))\n            playSound((Player) humanEntity, gameSound);\n    }\n\n    public static void playSound(Player player, @Nullable GameSound gameSound) {\n        if (!isEmpty(gameSound)) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                player.playSound(player.getLocation(wrapper.getHandle()), gameSound.getSound(),\n                        gameSound.getVolume(), gameSound.getPitch());\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\n\npublic class IslandArea {\n\n    private double minX;\n    private double minZ;\n    private double maxX;\n    private double maxZ;\n\n    public void update(BlockPosition center, double size) {\n        update(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size);\n    }\n\n    public void update(double minX, double minZ, double maxX, double maxZ) {\n        this.minX = minX;\n        this.minZ = minZ;\n        this.maxX = maxX;\n        this.maxZ = maxZ;\n    }\n\n    public boolean intercepts(double x, double z) {\n        return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ;\n    }\n\n    public boolean expandAndIntercepts(double x, double z, double expandFactor) {\n        if (expandFactor == 0)\n            return intercepts(x, z);\n        double minX = this.minX - expandFactor;\n        double minZ = this.minZ - expandFactor;\n        double maxX = this.maxX + expandFactor;\n        double maxZ = this.maxZ + expandFactor;\n        return x >= minX && x <= maxX && z >= minZ && z <= maxZ;\n    }\n\n    public boolean expandRshiftAndIntercepts(double x, double z, double expandFactor, int shiftFactor) {\n        if (shiftFactor == 0)\n            return intercepts(x, z);\n        int minX = (int) (this.minX - expandFactor) >> shiftFactor;\n        int minZ = (int) (this.minZ - expandFactor) >> shiftFactor;\n        int maxX = (int) (this.maxX + expandFactor) >> shiftFactor;\n        int maxZ = (int) (this.maxZ + expandFactor) >> shiftFactor;\n        return x >= minX && x <= maxX && z >= minZ && z <= maxZ;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\n\npublic class IslandPosition {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private IslandPosition() {\n    }\n\n    public static long calculatePackedPosFromLocation(int locX, int locZ) {\n        int radius = plugin.getSettings().getMaxIslandSize() * 3;\n        int x = (Math.abs(locX) + (radius / 2)) / radius;\n        int z = (Math.abs(locZ) + (radius / 2)) / radius;\n        return calculatePackedPos(locX < 0 ? -x : x, locZ < 0 ? -z : z);\n    }\n\n    public static long calculatePackedPos(int posX, int posZ) {\n        long posXLong = (long) posX & 0xFFFFFFFFL;\n        long posZLong = (long) posZ & 0xFFFFFFFFL;\n        return (posXLong) | (posZLong << 32);\n    }\n\n    public static int getXFromPacked(long packedPos) {\n        return (int) (packedPos & 0xFFFFFFFFL);\n    }\n\n    public static int getZFromPacked(long packedPos) {\n        return (int) ((packedPos >>> 32) & 0xFFFFFFFFL);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\nimport java.util.function.Consumer;\n\npublic class IslandWorlds {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static void accessIslandWorldsAsync(Island island, boolean loadWorld, Consumer<Either<World, Throwable>> consumer) {\n        for (Dimension dimension : Dimension.values()) {\n            if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) {\n                accessIslandWorldAsync(island, dimension, loadWorld, consumer);\n            }\n        }\n    }\n\n    public static void accessIslandWorldAsync(Island island, Location location, boolean loadWorld, Consumer<Either<World, Throwable>> consumer) {\n        World world = location.getWorld();\n        if (world != null) {\n            consumer.accept(Either.left(world));\n            return;\n        }\n\n        String worldName = LazyWorldLocation.getWorldName(location);\n\n        if (!loadWorld) {\n            consumer.accept(Either.right(new NullPointerException(\"World \" + worldName + \" is not loaded when requested\")));\n            return;\n        }\n\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, worldName);\n\n        Dimension dimension = worldInfo.getDimension();\n\n        WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider();\n        if (worldsProvider instanceof LazyWorldsProvider) {\n            ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () ->\n                    loadedWorldCallback(worldInfo, consumer));\n        } else {\n            loadedWorldCallback(worldInfo, consumer);\n        }\n    }\n\n    public static void accessIslandWorldAsync(Island island, Dimension dimension, boolean loadWorld, Consumer<Either<World, Throwable>> consumer) {\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n        if (worldInfo == null) {\n            consumer.accept(Either.right(new NullPointerException(\"Cannot find world for dimension \" + dimension.getName())));\n            return;\n        }\n\n        World world = Bukkit.getWorld(worldInfo.getName());\n        if (world != null) {\n            consumer.accept(Either.left(world));\n            return;\n        }\n\n        if (!loadWorld) {\n            consumer.accept(Either.right(new NullPointerException(\"World is not loaded for dimension \" + dimension.getName())));\n            return;\n        }\n\n        WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider();\n        if (worldsProvider instanceof LazyWorldsProvider) {\n            ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () ->\n                    loadedWorldCallback(worldInfo, consumer));\n        } else {\n            loadedWorldCallback(worldInfo, consumer);\n        }\n    }\n\n    public static Location setWorldToLocation(Island island, Dimension dimension, WorldPosition worldPosition) {\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n        return setWorldToLocation(worldInfo, worldPosition);\n    }\n\n    public static Location setWorldToLocation(WorldInfo worldInfo, WorldPosition worldPosition) {\n        World world = Bukkit.getWorld(worldInfo.getName());\n        Location location;\n        if (world != null) {\n            location = worldPosition.toLocation(world);\n        } else {\n            throw new IllegalStateException(\"You cannot call this method while the world is unloaded. Use Island#accessIslandWorld\");\n        }\n\n        return location;\n    }\n\n    public static void ensureWorldLoaded(Island island, Dimension dimension) {\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n        ensureWorldLoaded(worldInfo);\n    }\n\n    public static void ensureWorldLoaded(WorldInfo worldInfo) {\n        World world = Bukkit.getWorld(worldInfo.getName());\n        if (world == null)\n            throw new IllegalStateException(\"You cannot call this method while the world is unloaded. Use Island#accessIslandWorld\");\n    }\n\n    private static void loadedWorldCallback(WorldInfo worldInfo, Consumer<Either<World, Throwable>> consumer) {\n        World world = Bukkit.getWorld(worldInfo.getName());\n        if (world != null) {\n            consumer.accept(Either.left(world));\n        } else {\n            consumer.accept(Either.right(new NullPointerException(\"World does not exist\")));\n        }\n    }\n\n    private IslandWorlds() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.Player;\n\nimport java.util.List;\n\npublic abstract class IslandWorldsPlayersStrategy implements ObjectsPool.Releasable, AutoCloseable {\n\n    private static final LazyReference<ObjectsPool<IslandWorldsPlayersStrategy>> POOL = new LazyReference<ObjectsPool<IslandWorldsPlayersStrategy>>() {\n        @Override\n        protected ObjectsPool<IslandWorldsPlayersStrategy> create() {\n            return plugin.getProviders().hasCustomWorldsSupport() ? new ObjectsPool<>(IslandWorldsPlayersStrategyMultiWorld::new) :\n                    new ObjectsPool<>(IslandWorldsPlayersStrategySingleWorld::new);\n        }\n    };\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static IslandWorldsPlayersStrategy create(Island island) {\n        return POOL.get().obtain().initialize(island);\n    }\n\n    private IslandWorldsPlayersStrategy() {\n\n    }\n\n    protected abstract IslandWorldsPlayersStrategy initialize(Island island);\n\n    @Override\n    public void close() {\n        release();\n    }\n\n    public abstract List<Player> getPlayers(WorldInfo worldInfo);\n\n    public abstract List<SuperiorPlayer> getSuperiorPlayers(WorldInfo worldInfo);\n\n    private static class IslandWorldsPlayersStrategySingleWorld extends IslandWorldsPlayersStrategy {\n\n        private List<SuperiorPlayer> playersInIsland = null;\n\n        private IslandWorldsPlayersStrategySingleWorld() {\n        }\n\n        protected IslandWorldsPlayersStrategySingleWorld initialize(Island island) {\n            this.playersInIsland = island.getAllPlayersInside();\n            return this;\n        }\n\n        @Override\n        public void release() {\n            this.playersInIsland = null;\n        }\n\n        @Override\n        public List<Player> getPlayers(WorldInfo worldInfo) {\n            return new SequentialListBuilder<Player>()\n                    .filter(player -> player.getWorld().getName().equals(worldInfo.getName()))\n                    .build(this.playersInIsland, SuperiorPlayer::asPlayer);\n        }\n\n        @Override\n        public List<SuperiorPlayer> getSuperiorPlayers(WorldInfo worldInfo) {\n            return new SequentialListBuilder<SuperiorPlayer>()\n                    .filter(player -> player.getWorld().getName().equals(worldInfo.getName()))\n                    .build(this.playersInIsland);\n        }\n\n    }\n\n\n    private static class IslandWorldsPlayersStrategyMultiWorld extends IslandWorldsPlayersStrategy {\n\n        private Island island = null;\n\n        private IslandWorldsPlayersStrategyMultiWorld() {\n\n        }\n\n        protected IslandWorldsPlayersStrategyMultiWorld initialize(Island island) {\n            this.island = island;\n            return this;\n        }\n\n        @Override\n        public void release() {\n            this.island = null;\n        }\n\n        @Override\n        public List<Player> getPlayers(WorldInfo worldInfo) {\n            World bukkitWorld = Bukkit.getWorld(worldInfo.getName());\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                return new SequentialListBuilder<Player>()\n                        .filter(player -> island.isInside(player.getLocation(wrapper.getHandle())))\n                        .build(bukkitWorld.getPlayers());\n            }\n        }\n\n        @Override\n        public List<SuperiorPlayer> getSuperiorPlayers(WorldInfo worldInfo) {\n            World bukkitWorld = Bukkit.getWorld(worldInfo.getName());\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                return new SequentialListBuilder<SuperiorPlayer>()\n                        .filter(player -> island.isInside(player.getLocation(wrapper.getHandle())))\n                        .build(bukkitWorld.getPlayers(), plugin.getPlayers()::getSuperiorPlayer);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/JavaVersion.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\npublic class JavaVersion {\n\n    private static final int currentJavaVersion = detectJavaVersion();\n\n    private static int detectJavaVersion() {\n        String[] javaVersionSections = System.getProperty(\"java.version\").split(\"\\\\.\");\n        if(javaVersionSections[0].equals(\"1\"))\n            return Integer.parseInt(javaVersionSections[1]);\n\n        return Integer.parseInt(javaVersionSections[0]);\n    }\n\n    public static boolean isAtLeast(int version) {\n        return currentJavaVersion >= version;\n    }\n\n    private JavaVersion() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/LazyReference.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.util.Optional;\n\npublic abstract class LazyReference<E> {\n\n    private E instance;\n\n    public E get() {\n        return instance == null ? (instance = create()) : instance;\n    }\n\n    protected abstract E create();\n\n    public Optional<E> getIfPresent() {\n        return Optional.ofNullable(this.instance);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\n/**\n * LazyWorldLocation will update the world again if it's null on initialize.\n */\npublic class LazyWorldLocation extends Location {\n\n    @Nullable\n    private String worldName;\n    private boolean updatedWorld = false;\n\n    public static LazyWorldLocation of(Location location) {\n        if (location instanceof LazyWorldLocation)\n            return (LazyWorldLocation) ((LazyWorldLocation) location).clone(true);\n\n        return new LazyWorldLocation(location.getWorld().getName(), location.getX(), location.getY(), location.getZ(),\n                location.getYaw(), location.getPitch());\n    }\n\n    public static LazyWorldLocation of(WorldInfo worldInfo, BlockPosition blockPosition) {\n        return new LazyWorldLocation(worldInfo.getName(), blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(),\n                0f, 0f);\n    }\n\n    public static LazyWorldLocation of(WorldInfo worldInfo, WorldPosition worldPosition) {\n        return new LazyWorldLocation(worldInfo.getName(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(),\n                worldPosition.getYaw(), worldPosition.getPitch());\n    }\n\n    public LazyWorldLocation(World world, double x, double y, double z) {\n        super(world, x, y, z);\n        this.worldName = null;\n        this.updatedWorld = false;\n    }\n\n    public LazyWorldLocation(String worldName, double x, double y, double z, float yaw, float pitch) {\n        super(Bukkit.getWorld(worldName), x, y, z, yaw, pitch);\n        this.worldName = worldName;\n        this.updatedWorld = false;\n    }\n\n    public String getWorldName() {\n        return this.worldName;\n    }\n\n    public void setWorldName(String worldName) {\n        this.worldName = worldName;\n        this.updatedWorld = false;\n    }\n\n    @Override\n    public World getWorld() {\n        if (!this.updatedWorld) {\n            updateWorldInternal(worldName == null ? null : Bukkit.getWorld(worldName));\n        }\n\n        return super.getWorld();\n    }\n\n    @Override\n    public void setWorld(World world) {\n        updateWorldInternal(world);\n        this.worldName = world == null ? null : world.getName();\n    }\n\n    private void updateWorldInternal(@Nullable World world) {\n        super.setWorld(world);\n        this.updatedWorld = true;\n    }\n\n    @Override\n    public Location clone() {\n        return clone(false);\n    }\n\n    public Location clone(boolean keepLazy) {\n        return keepLazy || getWorld() == null ? new LazyWorldLocation(this.worldName, getX(), getY(), getZ(), getYaw(), getPitch()) :\n                super.clone();\n    }\n\n    public static String getWorldName(Location location) {\n        if (location instanceof LazyWorldLocation)\n            return ((LazyWorldLocation) location).getWorldName();\n\n        World world = location.getWorld();\n        return world == null ? \"null\" : world.getName();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Manager.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\n\npublic abstract class Manager {\n\n    protected final SuperiorSkyblockPlugin plugin;\n\n    protected Manager(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public abstract void loadData() throws ManagerLoadException;\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Material;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic enum Materials {\n\n    CLOCK(\"WATCH\"),\n    PLAYER_HEAD(\"SKULL_ITEM\", 3),\n    GOLDEN_AXE(\"GOLD_AXE\"),\n    SPAWNER(\"MOB_SPAWNER\"),\n    SUNFLOWER(\"DOUBLE_PLANT\"),\n    BLACK_STAINED_GLASS_PANE(\"STAINED_GLASS_PANE\", 15),\n    BONE_MEAL(\"INK_SACK\", 15),\n    NETHER_PORTAL(\"PORTAL\"),\n    END_PORTAL_FRAME(\"ENDER_PORTAL_FRAME\");\n\n\n    private static final EnumMap<Material, EnumSet<Tag>> MATERIAL_TAGS = setupMaterialTags();\n    private static final EnumSet<Material> BLOCK_NON_LEGACY_MATERIALS = allOf(material -> material.isBlock() && !isLegacy(material));\n    private static final EnumSet<Material> SOLID_MATERIALS = allOf(Material::isSolid);\n    private static final Map<String, String> PATCHED_MATERIAL_NAMES = setupPatchedMaterialNames();\n\n    private final String bukkitType;\n    private final short bukkitData;\n\n    Materials(String bukkitType) {\n        this(bukkitType, 0);\n    }\n\n    Materials(String bukkitType, int bukkitData) {\n        this.bukkitType = bukkitType;\n        this.bukkitData = (short) bukkitData;\n    }\n\n    public Material toBukkitType() {\n        try {\n            return Material.valueOf(ServerVersion.isLegacy() ? bukkitType : name());\n        } catch (Exception ex) {\n            throw new IllegalArgumentException(\"Couldn't cast \" + name() + \" into a bukkit enum. Contact Ome_R!\");\n        }\n    }\n\n    public ItemStack toBukkitItem() {\n        return toBukkitItem(1);\n    }\n\n    public ItemStack toBukkitItem(int amount) {\n        return ServerVersion.isLegacy() ? new ItemStack(toBukkitType(), amount, bukkitData) : new ItemStack(toBukkitType(), amount);\n    }\n\n    public static boolean hasTag(Material material, Tag tag) {\n        EnumSet<Tag> materialsTag = MATERIAL_TAGS.get(material);\n        return materialsTag != null && materialsTag.contains(tag);\n    }\n\n    public static boolean isSlab(Material material) {\n        return hasTag(material, Tag.SLAB);\n    }\n\n    public static boolean isWater(Material material) {\n        return hasTag(material, Tag.WATER);\n    }\n\n    public static boolean isLegacy(Material material) {\n        return hasTag(material, Tag.LEGACY);\n    }\n\n    public static boolean isRail(Material material) {\n        return hasTag(material, Tag.RAIL);\n    }\n\n    public static boolean isMinecart(Material material) {\n        return hasTag(material, Tag.MINECART);\n    }\n\n    public static boolean isChest(Material material) {\n        return hasTag(material, Tag.CHEST);\n    }\n\n    public static boolean isBoat(Material material) {\n        return hasTag(material, Tag.BOAT);\n    }\n\n    public static boolean isLava(Material material) {\n        return hasTag(material, Tag.LAVA);\n    }\n\n    public static boolean isSign(Material material) {\n        return hasTag(material, Tag.SIGN);\n    }\n\n    public static boolean isDye(Material material) {\n        return hasTag(material, Tag.DYE);\n    }\n\n    public static boolean isSpawnEgg(Material material) {\n        return hasTag(material, Tag.SPAWN_EGG);\n    }\n\n    public static boolean isCarpet(Material material) {\n        return hasTag(material, Tag.CARPET);\n    }\n\n    public static boolean isHarness(Material material) {\n        return hasTag(material, Tag.HARNESS);\n    }\n\n    public static boolean isBed(Material material) {\n        return hasTag(material, Tag.BED);\n    }\n\n    public static boolean isHoe(Material material) {\n        return hasTag(material, Tag.HOE);\n    }\n\n    public static boolean isShelf(Material material) {\n        return hasTag(material, Tag.SHELF);\n    }\n\n    public static Set<Material> getBlocksNonLegacy() {\n        return Collections.unmodifiableSet(BLOCK_NON_LEGACY_MATERIALS);\n    }\n\n    public static Set<Material> getSolids() {\n        return Collections.unmodifiableSet(SOLID_MATERIALS);\n    }\n\n    public static String patchOldMaterialName(String type) {\n        return PATCHED_MATERIAL_NAMES.getOrDefault(type, type);\n    }\n\n    public static void init() {\n\n    }\n\n    private static EnumSet<Material> allOf(Predicate<Material> predicate) {\n        EnumSet<Material> enumSet = EnumSet.noneOf(Material.class);\n        Arrays.stream(Material.values()).filter(predicate).forEach(enumSet::add);\n        return enumSet;\n    }\n\n    private static EnumMap<Material, EnumSet<Tag>> setupMaterialTags() {\n        EnumMap<Material, EnumSet<Tag>> enumMap = new EnumMap<>(Material.class);\n\n        for (Material material : Material.values()) {\n            EnumSet<Tag> materialTags = EnumSet.noneOf(Tag.class);\n\n            String materialName = material.name();\n            if (materialName.startsWith(\"LEGACY_\"))\n                materialTags.add(Tag.LEGACY);\n            if (materialName.contains(\"SLAB\"))\n                materialTags.add(Tag.SLAB);\n            if (materialName.contains(\"WATER\"))\n                materialTags.add(Tag.WATER);\n            if (materialName.contains(\"RAIL\"))\n                materialTags.add(Tag.RAIL);\n            if (materialName.contains(\"MINECART\"))\n                materialTags.add(Tag.MINECART);\n            if (material == Material.CHEST || materialName.endsWith(\"_CHEST\") ||\n                    materialName.contains(\"SHULKER_BOX\") || materialName.equals(\"BARREL\"))\n                materialTags.add(Tag.CHEST);\n            if (materialName.contains(\"BOAT\") || materialName.contains(\"_RAFT\"))\n                materialTags.add(Tag.BOAT);\n            if (materialName.contains(\"LAVA\"))\n                materialTags.add(Tag.LAVA);\n            if (materialName.contains(\"SIGN\"))\n                materialTags.add(Tag.SIGN);\n            if (ServerVersion.isLegacy() ? material == Material.INK_SACK : materialName.contains(\"_DYE\"))\n                materialTags.add(Tag.DYE);\n            if (ServerVersion.isLegacy() ? material == Material.MONSTER_EGG : materialName.contains(\"_SPAWN_EGG\"))\n                materialTags.add(Tag.SPAWN_EGG);\n            if (materialName.contains(\"CARPET\"))\n                materialTags.add(Tag.CARPET);\n            if (materialName.contains(\"HARNESS\"))\n                materialTags.add(Tag.HARNESS);\n            if (materialName.contains(\"BED\"))\n                materialTags.add(Tag.BED);\n            if (materialName.contains(\"_HOE\"))\n                materialTags.add(Tag.HOE);\n            if (materialName.contains(\"_SHELF\"))\n                materialTags.add(Tag.SHELF);\n\n            if (!materialTags.isEmpty())\n                enumMap.put(material, materialTags);\n        }\n\n        return enumMap;\n    }\n\n    private static Map<String, String> setupPatchedMaterialNames() {\n        Map<String, String> map = new HashMap<>();\n        try {\n            Material.valueOf(\"GRASS\");\n        } catch (IllegalArgumentException error) {\n            map.put(\"GRASS\", \"GRASS_BLOCK\");\n        }\n        return map.isEmpty() ? Collections.emptyMap() : map;\n    }\n\n    public enum Tag {\n\n        SLAB,\n        WATER,\n        LEGACY,\n        RAIL,\n        MINECART,\n        CHEST,\n        BOAT,\n        LAVA,\n        SIGN,\n        DYE,\n        SPAWN_EGG,\n        CARPET,\n        BED,\n        HARNESS,\n        HOE,\n        SHELF\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\n\npublic class MutableChunkPosition extends ChunkPosition {\n\n    public MutableChunkPosition() {\n        super(false);\n    }\n\n    public MutableChunkPosition reset(WorldInfo worldInfo, int x, int z) {\n        this.worldInfo = worldInfo;\n        this.x = x;\n        this.z = z;\n        this.pairedXZ = -1;\n        this.cachedBukkitWorld.clear();\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\n\npublic class ObjectsPool<T extends ObjectsPool.Releasable> {\n\n    private final Queue<T> backend = new LinkedList<>();\n    private final Creator<T> creator;\n\n    public ObjectsPool(Creator<T> creator) {\n        this(creator, 0);\n    }\n\n    public ObjectsPool(Creator<T> creator, int initialCapacity) {\n        this.creator = creator;\n        for (int i = 0; i < initialCapacity; ++i)\n            this.backend.offer(creator.create());\n    }\n\n    public T obtain() {\n        T obj;\n        synchronized (this) {\n            obj = this.backend.poll();\n        }\n        return obj == null ? this.creator.create() : obj;\n    }\n\n    public void release(T obj) {\n        synchronized (this) {\n            this.backend.offer(obj);\n        }\n    }\n\n    public interface Creator<T> {\n\n        T create();\n\n    }\n\n    public interface Releasable {\n\n        void release();\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.core.database.DBColumn;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableObject;\nimport org.bukkit.Location;\n\nimport javax.annotation.Nullable;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class ObjectsPools {\n\n    public static final ObjectsPool<Wrapper<Location>> LOCATION = createNewPool(() -> new Location(null, 0D, 0D, 0D));\n    public static final ObjectsPool<Wrapper<LazyWorldLocation>> LAZY_LOCATION = createNewPool(() -> new LazyWorldLocation(null, 0D, 0D, 0D));\n    public static final ObjectsPool<Wrapper<DBColumn>> DB_COLUMN = createNewPool(() -> new DBColumn(\"\", null));\n    public static final ObjectsPool<Batch<DBColumn>> DB_COLUMN_BATCH = new ObjectsPool<>(() -> new Batch<>(DB_COLUMN));\n\n    private ObjectsPools() {\n\n    }\n\n    public static <T> ObjectsPool<Wrapper<T>> createNewPool(ObjectsPool.Creator<T> creator) {\n        MutableObject<ObjectsPool<Wrapper<T>>> wrapperReference = new MutableObject<>(null);\n\n        ObjectsPool<Wrapper<T>> pool = new ObjectsPool<>(\n                () -> new Wrapper<>(creator.create(),\n                        obj -> onWrapperRelease(obj, wrapperReference.getValue())));\n\n        wrapperReference.setValue(pool);\n\n        return pool;\n    }\n\n    private static <T extends ObjectsPool.Releasable> void onWrapperRelease(T obj, @Nullable ObjectsPool<T> pool) {\n        if (pool != null)\n            pool.release(obj);\n    }\n\n    public static class Wrapper<T> implements ObjectsPool.Releasable, AutoCloseable {\n\n        private final T handle;\n        private final Consumer<Wrapper<T>> releaseMethod;\n\n        Wrapper(T handle, Consumer<Wrapper<T>> releaseMethod) {\n            this.handle = handle;\n            this.releaseMethod = releaseMethod;\n        }\n\n        public T getHandle() {\n            return handle;\n        }\n\n        @Override\n        public void release() {\n            this.releaseMethod.accept(this);\n        }\n\n        @Override\n        public void close() {\n            release();\n        }\n    }\n\n    public static class Batch<T> implements ObjectsPool.Releasable, AutoCloseable {\n\n        private final ObjectsPool<Wrapper<T>> pool;\n\n        private final List<Wrapper<T>> obtainedObjects = new LinkedList<>();\n\n        public Batch(ObjectsPool<Wrapper<T>> pool) {\n            this.pool = pool;\n        }\n\n        public T obtain() {\n            Wrapper<T> obj = this.pool.obtain();\n            this.obtainedObjects.add(obj);\n            return obj.getHandle();\n        }\n\n        @Override\n        public void release() {\n            obtainedObjects.forEach(Wrapper::release);\n            obtainedObjects.clear();\n        }\n\n        @Override\n        public void close() {\n            release();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/PlayerHand.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport org.bukkit.inventory.EquipmentSlot;\n\nimport java.util.function.Supplier;\n\npublic enum PlayerHand {\n\n    MAIN_HAND {\n        @Override\n        public EquipmentSlot getEquipmentSlot() {\n            return EquipmentSlot.HAND;\n        }\n    },\n    OFF_HAND {\n        @Override\n        public EquipmentSlot getEquipmentSlot() {\n            return EQUIPMENT_SLOT_OFF_HAND;\n        }\n    };\n\n    @Nullable\n    private static final EquipmentSlot EQUIPMENT_SLOT_OFF_HAND = ((Supplier<EquipmentSlot>) () -> {\n        try {\n            return EquipmentSlot.valueOf(\"OFF_HAND\");\n        } catch (IllegalArgumentException error) {\n            return null;\n        }\n    }).get();\n\n    public static PlayerHand of(EquipmentSlot equipmentSlot) {\n        if (equipmentSlot == EquipmentSlot.HAND) {\n            return PlayerHand.MAIN_HAND;\n        } else if (equipmentSlot == EQUIPMENT_SLOT_OFF_HAND) {\n            return PlayerHand.OFF_HAND;\n        }\n\n        throw new IllegalArgumentException(\"Cannot get PlayerHand from: \" + equipmentSlot);\n    }\n\n    public abstract EquipmentSlot getEquipmentSlot();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\npublic enum PluginLoadingStage {\n\n    START,\n    API_INITIALIZED,\n    SUPPORTED_SERVER_SOFTWARE,\n    NMS_INITIALIZED,\n    LOADED,\n    START_ENABLE,\n    SETTINGS_INITIALIZED,\n    MODULES_INITIALIZED,\n    COMMANDS_INITIALIZED,\n    WORLDS_PREPARED,\n    MANAGERS_INITIALIZED,\n    CHUNKS_PROVIDER_INITIALIZED,\n    ENABLED;\n\n    public boolean isAtLeast(PluginLoadingStage other) {\n        return this.ordinal() >= other.ordinal();\n    }\n\n    public PluginLoadingStage next() {\n        try {\n            return PluginLoadingStage.values()[this.ordinal() + 1];\n        } catch (ArrayIndexOutOfBoundsException error) {\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/PluginReloadReason.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\npublic enum PluginReloadReason {\n\n    STARTUP,\n\n    COMMAND\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Precision.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\n\npublic class Precision {\n\n    private Precision() {\n\n    }\n\n    public static double round(double value, int places) {\n        if (places < 0) throw new IllegalArgumentException();\n\n        BigDecimal bd = new BigDecimal(Double.toString(value));\n        bd = bd.setScale(places, RoundingMode.FLOOR);\n        return bd.doubleValue();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/SBlockOffset.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\n\nimport java.util.Objects;\n\npublic class SBlockOffset implements BlockOffset {\n\n    public static final SBlockOffset ZERO = new SBlockOffset(0, 0, 0);\n\n    private final double offsetX;\n    private final double offsetY;\n    private final double offsetZ;\n\n    public static BlockOffset fromOffsets(int offsetX, int offsetY, int offsetZ) {\n        return offsetX == 0 && offsetY == 0 && offsetZ == 0 ? ZERO : new SBlockOffset(offsetX, offsetY, offsetZ);\n    }\n\n    public static BlockOffset fromOffsets(double offsetX, double offsetY, double offsetZ) {\n        return offsetX == 0 && offsetY == 0 && offsetZ == 0 ? ZERO : new SBlockOffset(offsetX, offsetY, offsetZ);\n    }\n\n    private SBlockOffset(double offsetX, double offsetY, double offsetZ) {\n        this.offsetX = offsetX;\n        this.offsetY = offsetY;\n        this.offsetZ = offsetZ;\n    }\n\n    @Override\n    public int getOffsetX() {\n        return (int) this.offsetX;\n    }\n\n    @Override\n    public int getOffsetY() {\n        return (int) this.offsetY;\n    }\n\n    @Override\n    public int getOffsetZ() {\n        return (int) this.offsetZ;\n    }\n\n    @Override\n    public BlockOffset negate() {\n        return SBlockOffset.fromOffsets(-offsetX, -offsetY, -offsetZ);\n    }\n\n    @Override\n    public Location applyToLocation(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return location.clone().add(this.offsetX, this.offsetY, this.offsetZ);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SBlockOffset that = (SBlockOffset) o;\n        return offsetX == that.offsetX && offsetY == that.offsetY && offsetZ == that.offsetZ;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(offsetX, offsetY, offsetZ);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\n\nimport java.util.Objects;\n\npublic class SBlockPosition implements BlockPosition {\n\n    private final int x;\n    private final int y;\n    private final int z;\n\n    @Nullable\n    private WorldPosition cachedWorldPosition;\n\n    public static SBlockPosition of(Location location) {\n        return of(location.getBlockX(), location.getBlockY(), location.getBlockZ());\n    }\n\n    public static SBlockPosition of(Block block) {\n        return of(block.getX(), block.getY(), block.getZ());\n    }\n\n    public static SBlockPosition of(WorldPosition worldPosition) {\n        return new SBlockPosition(Location.locToBlock(worldPosition.getX()),\n                Location.locToBlock(worldPosition.getY()), Location.locToBlock(worldPosition.getZ()));\n    }\n\n    public static SBlockPosition of(int x, int y, int z) {\n        return new SBlockPosition(x, y, z);\n    }\n\n    private SBlockPosition(int x, int y, int z) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n    }\n\n    @Override\n    public int getX() {\n        return x;\n    }\n\n    @Override\n    public int getY() {\n        return y;\n    }\n\n    @Override\n    public int getZ() {\n        return z;\n    }\n\n    @Override\n    public BlockPosition offset(int x, int y, int z) {\n        return new SBlockPosition(this.x + x, this.y + y, this.z + z);\n    }\n\n    @Override\n    public Location toLocation(@Nullable World world) {\n        return new Location(world, x, y, z);\n    }\n\n    @Override\n    public Location toLocation(@Nullable World world, @Nullable Location location) {\n        if (location != null) {\n            location.setWorld(world);\n            location.setX(this.x);\n            location.setY(this.y);\n            location.setZ(this.z);\n            location.setYaw(0f);\n            location.setPitch(0f);\n        }\n\n        return location;\n    }\n\n    @Override\n    public Location toLocation(WorldInfo worldInfo) {\n        return LazyWorldLocation.of(worldInfo, this);\n    }\n\n    @Override\n    public Location toLocation(WorldInfo worldInfo, @Nullable Location location) {\n        if (location != null) {\n            location.setX(this.x);\n            location.setY(this.y);\n            location.setZ(this.z);\n            location.setYaw(0f);\n            location.setPitch(0f);\n\n            if (location instanceof LazyWorldLocation) {\n                ((LazyWorldLocation) location).setWorldName(worldInfo.getName());\n            } else {\n                World world = Bukkit.getWorld(worldInfo.getName());\n                location.setWorld(world);\n            }\n\n        }\n\n        return location;\n    }\n\n    @Override\n    public WorldPosition toWorldPosition() {\n        if (this.cachedWorldPosition == null)\n            this.cachedWorldPosition = SWorldPosition.of(this);\n\n        return this.cachedWorldPosition;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SBlockPosition that = (SBlockPosition) o;\n        return x == that.x && y == that.y && z == that.z;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(x, y, z);\n    }\n\n    @Override\n    public String toString() {\n        return x + \", \" + y + \", \" + z;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\n\nimport java.util.Objects;\n\npublic class SWorldPosition implements WorldPosition {\n\n    private final double x;\n    private final double y;\n    private final double z;\n    private final float yaw;\n    private final float pitch;\n\n    @Nullable\n    private BlockPosition cachedBlockPosition;\n\n    public static SWorldPosition of(Location location) {\n        return of(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());\n    }\n\n    public static SWorldPosition of(Block block) {\n        return of(block.getX(), block.getY(), block.getZ());\n    }\n\n    public static SWorldPosition of(double x, double y, double z) {\n        return of(x, y, z, 0f, 0f);\n    }\n\n    public static SWorldPosition of(BlockPosition blockPosition) {\n        return of(blockPosition.getX() + 0.5, blockPosition.getY(), blockPosition.getZ() + 0.5);\n    }\n\n    public static SWorldPosition of(double x, double y, double z, float yaw, float pitch) {\n        return new SWorldPosition(x, y, z, yaw, pitch);\n    }\n\n    private SWorldPosition(double x, double y, double z, float yaw, float pitch) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.yaw = yaw;\n        this.pitch = pitch;\n    }\n\n    @Override\n    public double getX() {\n        return this.x;\n    }\n\n    @Override\n    public double getY() {\n        return this.y;\n    }\n\n    @Override\n    public double getZ() {\n        return this.z;\n    }\n\n    @Override\n    public float getYaw() {\n        return this.yaw;\n    }\n\n    @Override\n    public float getPitch() {\n        return this.pitch;\n    }\n\n    @Override\n    public WorldPosition offset(double x, double y, double z) {\n        return of(this.x + x, this.y + y, this.z + z, this.yaw, this.pitch);\n    }\n\n    @Override\n    public WorldPosition rotate(float yaw, float pitch) {\n        return of(this.x, this.y, this.z, this.yaw + yaw, this.pitch + pitch);\n    }\n\n    @Override\n    public WorldPosition offset(double x, double y, double z, float yaw, float pitch) {\n        return of(this.x + x, this.y + y, this.z + z, this.yaw + yaw, this.pitch + pitch);\n    }\n\n    @Override\n    public Location toLocation(@Nullable World world) {\n        return new Location(world, this.x, this.y, this.z, this.yaw, this.pitch);\n    }\n\n    @Override\n    public Location toLocation(@Nullable World world, @Nullable Location location) {\n        if (location != null) {\n            location.setWorld(world);\n            location.setX(this.x);\n            location.setY(this.y);\n            location.setZ(this.z);\n            location.setYaw(this.yaw);\n            location.setPitch(this.pitch);\n        }\n\n        return location;\n    }\n\n    @Override\n    public Location toLocation(WorldInfo worldInfo) {\n        return LazyWorldLocation.of(worldInfo, this);\n    }\n\n    @Override\n    public Location toLocation(WorldInfo worldInfo, @Nullable Location location) {\n        if (location != null) {\n            location.setX(this.x);\n            location.setY(this.y);\n            location.setZ(this.z);\n            location.setYaw(this.yaw);\n            location.setPitch(this.pitch);\n\n            if (location instanceof LazyWorldLocation) {\n                ((LazyWorldLocation) location).setWorldName(worldInfo.getName());\n            } else {\n                World world = Bukkit.getWorld(worldInfo.getName());\n                location.setWorld(world);\n            }\n\n        }\n\n        return location;\n    }\n\n    @Override\n    public BlockPosition toBlockPosition() {\n        if (this.cachedBlockPosition == null)\n            this.cachedBlockPosition = SBlockPosition.of(this);\n\n        return this.cachedBlockPosition;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SWorldPosition that = (SWorldPosition) o;\n        return x == that.x && y == that.y && z == that.z && yaw == that.yaw && pitch == that.pitch;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(x, y, z, yaw, pitch);\n    }\n\n    @Override\n    public String toString() {\n        return x + \", \" + y + \", \" + z + \", \" + yaw + \", \" + pitch;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\npublic class SequentialListBuilder<E> {\n\n    @Nullable\n    private Comparator<? super E> comparator;\n    @Nullable\n    private Predicate<? super E> predicate;\n    private boolean mutable = false;\n\n    public SequentialListBuilder<E> sorted(@Nullable Comparator<? super E> comparator) {\n        this.comparator = comparator;\n        return this;\n    }\n\n    public SequentialListBuilder<E> filter(@Nullable Predicate<? super E> predicate) {\n        this.predicate = predicate;\n        return this;\n    }\n\n    public SequentialListBuilder<E> mutable() {\n        this.mutable = true;\n        return this;\n    }\n\n    public <O> List<E> build(Collection<O> collection, Function<O, E> mapper) {\n        LinkedList<E> sequentialList = new LinkedList<>();\n\n        collection.forEach(element -> {\n            E mappedElement = mapper.apply(element);\n            if (predicate == null || predicate.test(mappedElement))\n                sequentialList.add(mappedElement);\n        });\n\n        return completeBuild(sequentialList);\n    }\n\n    public <O> List<E> build(O[] collection, Function<O, E> mapper) {\n        LinkedList<E> sequentialList = new LinkedList<>();\n\n        for (O element : collection) {\n            E mappedElement = mapper.apply(element);\n            if (predicate == null || predicate.test(mappedElement))\n                sequentialList.add(mappedElement);\n        }\n\n        return completeBuild(sequentialList);\n    }\n\n    public <O> List<O> map(Collection<E> collection, Function<E, O> mapper) {\n        LinkedList<O> sequentialList = new LinkedList<>();\n\n        collection.forEach(element -> {\n            if (predicate == null || predicate.test(element))\n                sequentialList.add(mapper.apply(element));\n        });\n\n        return completeBuild(sequentialList, null, this.mutable);\n    }\n\n    public <O> List<O> map(E[] collection, Function<E, O> mapper) {\n        LinkedList<O> sequentialList = new LinkedList<>();\n\n        for (E element : collection) {\n            if (predicate == null || predicate.test(element))\n                sequentialList.add(mapper.apply(element));\n        }\n\n        return completeBuild(sequentialList, null, this.mutable);\n    }\n\n    public <O> List<O> map(Iterator<E> iterator, Function<E, O> mapper) {\n        LinkedList<O> sequentialList = new LinkedList<>();\n\n        while (iterator.hasNext()) {\n            E next = iterator.next();\n            if (predicate == null || predicate.test(next))\n                sequentialList.add(mapper.apply(next));\n        }\n\n        return completeBuild(sequentialList, null, this.mutable);\n    }\n\n    public List<E> build(Stream<E> stream) {\n        LinkedList<E> sequentialList = new LinkedList<>();\n\n        stream.forEach(element -> {\n            if (predicate == null || predicate.test(element))\n                sequentialList.add(element);\n        });\n\n        return completeBuild(sequentialList);\n    }\n\n    public List<E> build(Collection<E> collection) {\n        LinkedList<E> sequentialList;\n\n        if (predicate == null) {\n            sequentialList = new LinkedList<>(collection);\n        } else {\n            sequentialList = new LinkedList<>();\n            collection.forEach(element -> {\n                if (predicate.test(element))\n                    sequentialList.add(element);\n            });\n        }\n\n        return completeBuild(sequentialList);\n    }\n\n    public List<E> build(Iterator<E> iterator) {\n        LinkedList<E> sequentialList = new LinkedList<>();\n\n        if (predicate == null) {\n            while (iterator.hasNext())\n                sequentialList.add(iterator.next());\n        } else {\n            while (iterator.hasNext()) {\n                E next = iterator.next();\n                if (predicate.test(next))\n                    sequentialList.add(next);\n            }\n        }\n\n        return completeBuild(sequentialList);\n    }\n\n    private List<E> completeBuild(List<E> sequentialList) {\n        return completeBuild(sequentialList, this.comparator, this.mutable);\n    }\n\n    private static <E> List<E> completeBuild(List<E> sequentialList, @Nullable Comparator<? super E> comparator, boolean mutable) {\n        if (sequentialList.isEmpty())\n            return mutable ? sequentialList : Collections.emptyList();\n\n        if (comparator != null)\n            sequentialList.sort(comparator);\n\n        return mutable ? sequentialList : Collections.unmodifiableList(sequentialList);\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport org.bukkit.Bukkit;\n\nimport java.util.Arrays;\nimport java.util.Optional;\n\npublic enum ServerVersion {\n\n    v1_8(18),\n    v1_9(19),\n    v1_10(110),\n    v1_11(111),\n    v1_12(112),\n    v1_13(113),\n    v1_14(114),\n    v1_15(115),\n    v1_16(116),\n    v1_17(117),\n    v1_18(118),\n    v1_19(119),\n    v1_20(120),\n    v1_21(121),\n    v26_1(261),\n\n    UNKONWN(-1);\n\n    private static final ServerVersion currentVersion;\n    private static final String bukkitVersion;\n    private static final boolean legacy;\n\n    static {\n        bukkitVersion = Bukkit.getBukkitVersion().split(\"-\")[0];\n        String[] sections = bukkitVersion.split(\"\\\\.\");\n        currentVersion = Optional.ofNullable(EnumHelper.getEnum(ServerVersion.class, \"v\" + sections[0] + \"_\" + sections[1])).orElse(UNKONWN);\n        legacy = isLessThan(ServerVersion.v1_13);\n    }\n\n    private final int code;\n\n    ServerVersion(int code) {\n        this.code = code;\n    }\n\n    public static boolean isAtLeast(ServerVersion serverVersion) {\n        return isValidVersion(serverVersion) && currentVersion.code >= serverVersion.code;\n    }\n\n    public static boolean isLessThan(ServerVersion serverVersion) {\n        return isValidVersion(serverVersion) && currentVersion.code < serverVersion.code;\n    }\n\n    public static boolean isEquals(ServerVersion serverVersion) {\n        return isValidVersion(serverVersion) && currentVersion.code == serverVersion.code;\n    }\n\n    public static boolean isLegacy() {\n        return legacy;\n    }\n\n    public static String getBukkitVersion() {\n        return bukkitVersion;\n    }\n\n    public static ServerVersion[] getByOrder() {\n        ServerVersion[] versions = Arrays.copyOfRange(values(), 0, currentVersion.ordinal() + 1);\n\n        for (int i = 0; i < versions.length / 2; i++) {\n            ServerVersion temp = versions[i];\n            versions[i] = versions[versions.length - i - 1];\n            versions[versions.length - i - 1] = temp;\n        }\n\n        return versions;\n    }\n\n    private static boolean isValidVersion(ServerVersion compareVersion) {\n        return currentVersion != UNKONWN && compareVersion != UNKONWN;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/Text.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\npublic class Text {\n\n    private Text() {\n\n    }\n\n    public static boolean isBlank(@Nullable String string) {\n        return string == null || string.isEmpty();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.google.common.base.Preconditions;\n\nimport java.util.Arrays;\nimport java.util.NoSuchElementException;\n\npublic class VarintArray {\n\n    private static final ThreadLocal<byte[]> VARINT_BUF = ThreadLocal.withInitial(() -> new byte[10]);\n\n    private static final byte[] ZERO_BYTE = new byte[]{0};\n\n    private final ByteBigArray backend;\n    private int size;\n\n    public VarintArray() {\n        this.backend = new ByteBigArray();\n        this.size = 0;\n    }\n\n    public VarintArray(ByteBigArray data) {\n        Preconditions.checkState(data.size() == 0 || (data.get(data.size() - 1) & 0x80) == 0,\n                \"Last byte in data-stream cannot have its MSB on\");\n        this.backend = data;\n        this.size = data.size();\n    }\n\n    public void add(long value) {\n        byte[] varint = serializeVarint(value);\n        for (byte b : varint)\n            this.backend.add(b);\n        this.size += varint.length;\n    }\n\n    public ByteBigArray toArray() {\n        return this.backend.readOnly();\n    }\n\n    public Itr iterator() {\n        return new Itr();\n    }\n\n    private static byte[] serializeVarint(long value) {\n        if (value == 0)\n            return ZERO_BYTE;\n\n        byte[] varintBuf = VARINT_BUF.get();\n\n        int varintBytesCount = 0;\n        while (value != 0) {\n            byte nextByte = (byte) (value & 0x7f);\n            value >>= 7;\n            varintBuf[varintBytesCount++] = value == 0 ? nextByte : (byte) (nextByte | 0x80);\n        }\n        return Arrays.copyOf(varintBuf, varintBytesCount);\n    }\n\n    public class Itr {\n\n        private int index = 0;\n\n        public boolean hasNext() {\n            return index < size;\n        }\n\n        public long next() {\n            if (!hasNext())\n                throw new NoSuchElementException();\n\n            int i = 0;\n            long value = 0;\n            while (index < size) {\n                byte b = backend.get(index++);\n                value |= (long) (b & 0x7f) << i;\n                i += 7;\n                if ((b & 0x80) == 0)\n                    break;\n            }\n            return value;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/WorldInfoImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core;\n\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport org.bukkit.World;\n\nimport java.util.Objects;\n\npublic class WorldInfoImpl implements WorldInfo {\n\n    private final String worldName;\n    private final Dimension dimension;\n\n    public WorldInfoImpl(String worldName, Dimension dimension) {\n        this.worldName = worldName;\n        this.dimension = dimension;\n    }\n\n    @Override\n    public String getName() {\n        return this.worldName;\n    }\n\n    @Override\n    @Deprecated\n    public World.Environment getEnvironment() {\n        return this.dimension.getEnvironment();\n    }\n\n    @Override\n    public Dimension getDimension() {\n        return this.dimension;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        WorldInfoImpl worldInfo = (WorldInfoImpl) o;\n        return dimension.equals(worldInfo.dimension) && worldName.equals(worldInfo.worldName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(worldName, dimension);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.AbstractCollection;\nimport java.util.AbstractSet;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.Set;\n\npublic class ArrayMap<K, V> implements Map<K, V> {\n\n    private static final Object[] EMPTY_ARRAY = new Object[0];\n\n    private static final int DEFAULT_CAPACITY = 4;\n\n    private KeySet keySet;\n    private Values valuesCollection;\n    private EntrySet entrySet;\n\n    private Object[] keys = EMPTY_ARRAY;\n    private Object[] values = EMPTY_ARRAY;\n    private int size = 0;\n    private int capacity = 0;\n\n    private int findKeyPos(Object key) {\n        for (int i = 0; i < this.size; ++i) {\n            if (Objects.equals(keys[i], key))\n                return i;\n        }\n\n        return -1;\n    }\n\n    private void ensureCapacity() {\n        if (this.capacity == 0) {\n            this.capacity = DEFAULT_CAPACITY;\n            this.keys = new Object[DEFAULT_CAPACITY];\n            this.values = new Object[DEFAULT_CAPACITY];\n        } else if (this.size >= this.capacity) {\n            this.capacity *= 2;\n            this.keys = Arrays.copyOf(this.keys, this.capacity);\n            this.values = Arrays.copyOf(this.values, this.capacity);\n        }\n    }\n\n    @Override\n    public V get(Object key) {\n        int pos = findKeyPos(key);\n        return pos < 0 ? null : (V) this.values[pos];\n    }\n\n    @Override\n    public int size() {\n        return this.size;\n    }\n\n    @Override\n    public void clear() {\n        this.values = EMPTY_ARRAY;\n        this.keys = EMPTY_ARRAY;\n        this.size = 0;\n        this.capacity = 0;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return findKeyPos(key) >= 0;\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        for (Object curr : this.values) {\n            if (Objects.equals(value, curr))\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return this.size == 0;\n    }\n\n    @Override\n    public V put(Object key, Object value) {\n        int pos = findKeyPos(key);\n        if (pos >= 0) {\n            Object old = this.values[pos];\n            this.values[pos] = value;\n            return (V) old;\n        }\n\n        ensureCapacity();\n\n        this.keys[this.size] = key;\n        this.values[this.size] = value;\n        ++this.size;\n\n        return null;\n    }\n\n    @Override\n    public V remove(Object key) {\n        int pos = findKeyPos(key);\n        if (pos < 0) {\n            return null;\n        }\n\n        return remove(pos);\n    }\n\n    private V remove(int pos) {\n        Object oldValue = this.values[pos];\n        int tail = this.size - pos - 1;\n        System.arraycopy(this.keys, pos + 1, this.keys, pos, tail);\n        System.arraycopy(this.values, pos + 1, this.values, pos, tail);\n        --this.size;\n        this.values[this.size] = null;\n        return (V) oldValue;\n    }\n\n    @Override\n    public void putAll(@NotNull Map<? extends K, ? extends V> map) {\n        for (Entry<? extends K, ? extends V> curr : map.entrySet()) {\n            put(curr.getKey(), curr.getValue());\n        }\n    }\n\n    @NotNull\n    @Override\n    public Set<K> keySet() {\n        return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet;\n    }\n\n    @NotNull\n    @Override\n    public Collection<V> values() {\n        return this.valuesCollection == null ? (this.valuesCollection = new Values()) : this.valuesCollection;\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<K, V>> entrySet() {\n        return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet;\n    }\n\n    private class KeySet extends AbstractSet<K> {\n\n        @Override\n        public int size() {\n            return ArrayMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return ArrayMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return ArrayMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<K> iterator() {\n            return new KeySetItr();\n        }\n\n        @NotNull\n        @Override\n        public Object[] toArray() {\n            return Arrays.copyOf(ArrayMap.this.keys, size());\n        }\n\n        @NotNull\n        @Override\n        public <T> T[] toArray(@NotNull T[] ts) {\n            Object[] arr = ts.length >= size() ? ts : Arrays.copyOf(ts, size());\n            System.arraycopy(ArrayMap.this.keys, 0, arr, 0, size());\n            return (T[]) arr;\n        }\n\n        @Override\n        public void clear() {\n            ArrayMap.this.clear();\n        }\n    }\n\n    private class KeySetItr extends Itr<K> {\n\n        @Override\n        protected K getNext() {\n            return (K) ArrayMap.this.keys[this.lastRet];\n        }\n\n    }\n\n    private class Values extends AbstractCollection<V> {\n\n        @Override\n        public int size() {\n            return ArrayMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return ArrayMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return ArrayMap.this.containsValue(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<V> iterator() {\n            return new ValuesItr();\n        }\n\n        @NotNull\n        @Override\n        public Object[] toArray() {\n            return Arrays.copyOf(ArrayMap.this.values, size());\n        }\n\n        @NotNull\n        @Override\n        public <T> T[] toArray(@NotNull T[] ts) {\n            Object[] arr = ts.length >= size() ? ts : Arrays.copyOf(ts, size());\n            System.arraycopy(ArrayMap.this.values, 0, arr, 0, size());\n            return (T[]) arr;\n        }\n\n        @Override\n        public void clear() {\n            ArrayMap.this.clear();\n        }\n    }\n\n    private class ValuesItr extends Itr<V> {\n\n        @Override\n        protected V getNext() {\n            return (V) ArrayMap.this.values[this.lastRet];\n        }\n\n    }\n\n    private class EntrySet extends AbstractSet<Entry<K, V>> {\n\n        @Override\n        public int size() {\n            return ArrayMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return ArrayMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return ArrayMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Entry<K, V>> iterator() {\n            return new EntrySetItr();\n        }\n\n        @Override\n        public void clear() {\n            ArrayMap.this.clear();\n        }\n\n    }\n\n    private class EntrySetItr extends Itr<Entry<K, V>> {\n\n        @Override\n        protected Entry<K, V> getNext() {\n            return new EntryImpl(this.lastRet);\n        }\n\n    }\n\n    private class EntryImpl implements Entry<K, V> {\n\n        private final int pos;\n\n        EntryImpl(int pos) {\n            this.pos = pos;\n        }\n\n        @Override\n        public K getKey() {\n            return (K) ArrayMap.this.keys[this.pos];\n        }\n\n        @Override\n        public V getValue() {\n            return (V) ArrayMap.this.values[this.pos];\n        }\n\n        @Override\n        public V setValue(V v) {\n            Object old = ArrayMap.this.values[this.pos];\n            ArrayMap.this.values[this.pos] = v;\n            return (V) old;\n        }\n    }\n\n    private abstract class Itr<T> implements Iterator<T> {\n\n        protected int pos = 0;\n        protected int lastRet = -1;\n\n        @Override\n        public final boolean hasNext() {\n            return this.pos < size();\n        }\n\n        @Override\n        public final T next() {\n            if (!hasNext())\n                throw new NoSuchElementException();\n            this.lastRet = this.pos++;\n            return getNext();\n        }\n\n        protected abstract T getNext();\n\n        @Override\n        public final void remove() {\n            if (this.lastRet < 0)\n                throw new IllegalStateException();\n            ArrayMap.this.remove(this.lastRet);\n            this.pos = this.lastRet;\n            this.lastRet = -1;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalCollection.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.google.common.cache.Cache;\nimport com.google.common.cache.CacheBuilder;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\n\n@SuppressWarnings(\"UnstableApiUsage\")\npublic class AutoRemovalCollection<E> implements Collection<E> {\n\n    private static final Object DUMMY = new Object();\n\n    private final Collection<E> elements;\n    private final Cache<E, Object> elementsLifeTime;\n\n    public static <E> AutoRemovalCollection<E> newHashSet(long removalDelay, TimeUnit timeUnit) {\n        return new AutoRemovalCollection<>(removalDelay, timeUnit, HashSet::new);\n    }\n\n    public static <E> AutoRemovalCollection<E> newArrayList(long removalDelay, TimeUnit timeUnit) {\n        return new AutoRemovalCollection<>(removalDelay, timeUnit, ArrayList::new);\n    }\n\n    private AutoRemovalCollection(long removalDelay, TimeUnit timeUnit, Supplier<Collection<E>> collectionSupplier) {\n        this.elements = collectionSupplier.get();\n        this.elementsLifeTime = CacheBuilder.newBuilder()\n                .expireAfterWrite(removalDelay, timeUnit)\n                .removalListener(removalNotification -> {\n                    elements.remove(removalNotification.getKey());\n                })\n                .build();\n    }\n\n    @Override\n    public int size() {\n        refreshLifeTime();\n        return elements.size();\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        refreshLifeTime(o);\n        return elements.contains(o);\n    }\n\n    @NotNull\n    @Override\n    public Iterator<E> iterator() {\n        refreshLifeTime();\n        return elements.iterator();\n    }\n\n    @NotNull\n    @Override\n    public Object[] toArray() {\n        refreshLifeTime();\n        return elements.toArray();\n    }\n\n    @NotNull\n    @Override\n    public <T> T[] toArray(@NotNull T[] a) {\n        refreshLifeTime();\n        return elements.toArray(a);\n    }\n\n    @Override\n    public boolean add(E e) {\n        refreshLifeTime(e);\n        boolean result = elements.add(e);\n        if (result)\n            this.elementsLifeTime.put(e, DUMMY);\n        return result;\n    }\n\n    @Override\n    public boolean remove(Object o) {\n        this.elementsLifeTime.invalidate(o);\n        return elements.remove(o);\n    }\n\n    @Override\n    public boolean containsAll(@NotNull Collection<?> c) {\n        c.forEach(this::refreshLifeTime);\n        return elements.containsAll(c);\n    }\n\n    @Override\n    public boolean addAll(@NotNull Collection<? extends E> c) {\n        boolean result = false;\n        for (E element : c)\n            result |= add(element);\n        return result;\n    }\n\n    @Override\n    public boolean retainAll(@NotNull Collection<?> c) {\n        return elements.retainAll(c);\n    }\n\n    @Override\n    public boolean removeAll(@NotNull Collection<?> c) {\n        this.elementsLifeTime.invalidateAll((Iterable<E>) c.iterator());\n        return elements.removeAll(c);\n    }\n\n    @Override\n    public void clear() {\n        elements.clear();\n        this.elementsLifeTime.invalidateAll();\n    }\n\n    private void refreshLifeTime(Object o) {\n        try {\n            this.elementsLifeTime.get((E) o, () -> null);\n        } catch (Throwable ignored) {\n\n        }\n    }\n\n    private void refreshLifeTime() {\n        this.elementsLifeTime.size();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.google.common.cache.Cache;\nimport com.google.common.cache.CacheBuilder;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\n\n@SuppressWarnings(\"UnstableApiUsage\")\npublic class AutoRemovalMap<K, V> implements Map<K, V> {\n\n    private static final Object DUMMY = new Object();\n\n    private final Map<K, V> elements;\n    private final Cache<K, Object> elementsLifeTime;\n\n    public static <K, V> AutoRemovalMap<K, V> newHashMap(long removalDelay, TimeUnit timeUnit) {\n        return newMap(removalDelay, timeUnit, HashMap::new);\n    }\n\n    public static <K, V> AutoRemovalMap<K, V> newMap(long removalDelay, TimeUnit timeUnit, Supplier<Map<K, V>> mapSupplier) {\n        return new AutoRemovalMap<>(removalDelay, timeUnit, mapSupplier);\n    }\n\n    private AutoRemovalMap(long removalDelay, TimeUnit timeUnit, Supplier<Map<K, V>> mapSupplier) {\n        this.elements = mapSupplier.get();\n        this.elementsLifeTime = CacheBuilder.newBuilder()\n                .expireAfterWrite(removalDelay, timeUnit)\n                .removalListener(removalNotification -> {\n                    elements.remove(removalNotification.getKey());\n                })\n                .build();\n    }\n\n    @Override\n    public int size() {\n        refreshLifeTime();\n        return elements.size();\n    }\n\n    @Override\n    public boolean isEmpty() {\n        refreshLifeTime();\n        return elements.isEmpty();\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        refreshLifeTime(key);\n        return elements.containsKey(key);\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        refreshLifeTime();\n        return elements.containsValue(value);\n    }\n\n    @Override\n    public V get(Object key) {\n        refreshLifeTime(key);\n        return elements.get(key);\n    }\n\n    @Nullable\n    @Override\n    public V put(K key, V value) {\n        refreshLifeTime(key);\n        V old = elements.put(key, value);\n        if (old != value)\n            this.elementsLifeTime.put(key, DUMMY);\n        return value;\n    }\n\n    @Override\n    public V remove(Object key) {\n        V value = elements.remove(key);\n        this.elementsLifeTime.invalidate(key);\n        return value;\n    }\n\n    @Override\n    public void putAll(@NotNull Map<? extends K, ? extends V> m) {\n        m.forEach(this::put);\n    }\n\n    @Override\n    public void clear() {\n        this.elementsLifeTime.invalidateAll();\n        elements.clear();\n    }\n\n    @NotNull\n    @Override\n    public Set<K> keySet() {\n        refreshLifeTime();\n        return elements.keySet();\n    }\n\n    @NotNull\n    @Override\n    public Collection<V> values() {\n        refreshLifeTime();\n        return elements.values();\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<K, V>> entrySet() {\n        refreshLifeTime();\n        return elements.entrySet();\n    }\n\n    private void refreshLifeTime(Object o) {\n        try {\n            this.elementsLifeTime.get((K) o, () -> null);\n        } catch (Throwable ignored) {\n\n        }\n    }\n\n    private void refreshLifeTime() {\n        this.elementsLifeTime.size();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.MutableChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.WorldInfoImpl;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\n\nimport java.util.AbstractCollection;\nimport java.util.AbstractMap;\nimport java.util.AbstractSet;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class Chunk2ObjectMap<V> extends AbstractMap<ChunkPosition, V> {\n\n    @Nullable\n    private KeySet keySet;\n    @Nullable\n    private Values values;\n    @Nullable\n    private EntrySet entrySet;\n\n    private final Map<String, Long2ObjectMapView<V>> backendMap = new LinkedHashMap<>();\n    private int size = 0;\n\n    @Override\n    public int size() {\n        return this.size;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return this.size == 0;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return get(key) != null;\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        return value != null && super.containsValue(value);\n    }\n\n    @Override\n    public V get(Object key) {\n        return key instanceof ChunkPosition ? get((ChunkPosition) key) : null;\n    }\n\n    @Nullable\n    public V get(ChunkPosition chunkPosition) {\n        return get(chunkPosition.getWorldName(), chunkPosition.asPair());\n    }\n\n    @Nullable\n    public V get(String worldName, long chunkPair) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.get(worldName);\n        if (worldBackendData == null)\n            return null;\n\n        return worldBackendData.get(chunkPair);\n    }\n\n    public V computeIfAbsent(String worldName, long chunkPair, Supplier<V> newValue) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.computeIfAbsent(worldName, n ->\n                CollectionsFactory.createLong2ObjectLinkedHashMap());\n\n        return worldBackendData.computeIfAbsent(chunkPair, p -> {\n            ++Chunk2ObjectMap.this.size;\n            return newValue.get();\n        });\n    }\n\n    @Nullable\n    @Override\n    public V put(ChunkPosition chunkPosition, V value) {\n        return put(chunkPosition.getWorldName(), chunkPosition.asPair(), value);\n    }\n\n    @Nullable\n    public V put(String worldName, long chunkPair, V value) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.computeIfAbsent(worldName, n ->\n                CollectionsFactory.createLong2ObjectLinkedHashMap());\n\n        V oldValue = worldBackendData.put(chunkPair, value);\n\n        if (oldValue == null)\n            ++this.size;\n\n        return oldValue;\n    }\n\n    @Override\n    public V remove(Object key) {\n        return key instanceof ChunkPosition ? remove((ChunkPosition) key) : null;\n    }\n\n    @Nullable\n    public V remove(ChunkPosition chunkPosition) {\n        return remove(chunkPosition.getWorldName(), chunkPosition.asPair());\n    }\n\n    @Nullable\n    public V remove(String worldName, long chunkPair) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.get(worldName);\n        if (worldBackendData == null)\n            return null;\n\n        V oldValue = onRemove(worldBackendData.remove(chunkPair));\n        if (oldValue == null)\n            return null;\n\n        if (worldBackendData.isEmpty())\n            Chunk2ObjectMap.this.backendMap.remove(worldName);\n\n        return oldValue;\n    }\n\n    @Nullable\n    private V onRemove(@Nullable V removedValue) {\n        if (removedValue != null)\n            --this.size;\n        return removedValue;\n    }\n\n    @Override\n    public void clear() {\n        this.backendMap.clear();\n        this.size = 0;\n    }\n\n    @NotNull\n    @Override\n    public Set<ChunkPosition> keySet() {\n        return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet;\n    }\n\n    @NotNull\n    @Override\n    public Collection<V> values() {\n        return this.values == null ? (this.values = new Values()) : this.values;\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<ChunkPosition, V>> entrySet() {\n        return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet;\n    }\n\n    static int getChunkXFromPair(long chunkPair) {\n        return (int) (chunkPair & 0xFFFFFFFFL);\n    }\n\n    static int getChunkZFromPair(long chunkPair) {\n        return (int) (chunkPair >> 32);\n    }\n\n    private class KeySet extends AbstractSet<ChunkPosition> {\n\n        @Override\n        public int size() {\n            return Chunk2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Chunk2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return Chunk2ObjectMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<ChunkPosition> iterator() {\n            return new KeySetItr();\n        }\n\n        @Override\n        public void clear() {\n            Chunk2ObjectMap.this.clear();\n        }\n\n        private class KeySetItr extends Itr<ChunkPosition> {\n\n            private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition();\n            private WorldInfoImpl cachedWorldInfo = null;\n\n            @Override\n            protected ChunkPosition getNext() {\n                return this.mutableChunkPosition.reset(this.cachedWorldInfo, getChunkXFromPair(this.currChunk),\n                        getChunkZFromPair(this.currChunk));\n            }\n\n            @Override\n            protected void onWorldChange() {\n                this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null);\n            }\n        }\n\n    }\n\n    private class Values extends AbstractCollection<V> {\n\n        @Override\n        public int size() {\n            return Chunk2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Chunk2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return Chunk2ObjectMap.this.containsValue(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<V> iterator() {\n            return new ValuesItr();\n        }\n\n        @Override\n        public void clear() {\n            Chunk2ObjectMap.this.clear();\n        }\n\n        private class ValuesItr extends Itr<V> {\n\n            @Override\n            protected V getNext() {\n                return this.currValue;\n            }\n\n        }\n\n    }\n\n    private class EntrySet extends AbstractSet<Entry<ChunkPosition, V>> {\n\n        @Override\n        public int size() {\n            return Chunk2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Chunk2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            ChunkPosition key = null;\n\n            if (o instanceof Entry) {\n                o = ((Entry<?, ?>) o).getKey();\n            }\n\n            if (o instanceof ChunkPosition)\n                key = (ChunkPosition) o;\n\n            return key != null && Chunk2ObjectMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Entry<ChunkPosition, V>> iterator() {\n            return new EntrySetItr();\n        }\n\n        @Override\n        public void clear() {\n            Chunk2ObjectMap.this.clear();\n        }\n\n        private class EntrySetItr extends Itr<Entry<ChunkPosition, V>> {\n\n            private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition();\n            private final EntryImpl mutableEntry = new EntryImpl();\n            private WorldInfoImpl cachedWorldInfo = null;\n\n            @Override\n            protected Entry<ChunkPosition, V> getNext() {\n                return mutableEntry.reset(\n                        this.mutableChunkPosition.reset(this.cachedWorldInfo,\n                                getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)),\n                        this.currValue);\n            }\n\n            @Override\n            protected void onWorldChange() {\n                this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null);\n            }\n\n            private class EntryImpl implements Entry<ChunkPosition, V> {\n\n                private ChunkPosition chunkPosition;\n                private V cachedValue;\n\n                EntryImpl() {\n\n                }\n\n                EntryImpl reset(ChunkPosition chunkPosition, V value) {\n                    this.chunkPosition = chunkPosition;\n                    this.cachedValue = value;\n                    return this;\n                }\n\n                @Override\n                public ChunkPosition getKey() {\n                    return this.chunkPosition;\n                }\n\n                @Override\n                public V getValue() {\n                    return this.cachedValue;\n                }\n\n                @Override\n                public V setValue(V v) {\n                    V oldValue = this.cachedValue;\n                    this.cachedValue = v;\n\n                    Long2ObjectMapView<V> worldBackendData = Chunk2ObjectMap.this.backendMap\n                            .get(this.chunkPosition.getWorldName());\n\n                    worldBackendData.put(this.chunkPosition.asPair(), this.cachedValue);\n\n                    return oldValue;\n                }\n            }\n\n        }\n\n    }\n\n    private abstract class Itr<T> implements Iterator<T> {\n\n        protected final Iterator<Entry<String, Long2ObjectMapView<V>>> worldsIterator;\n        protected Iterator<Long2ObjectMapView.Entry<V>> currWorldIterator = Collections.emptyIterator();\n        protected String currWorld;\n        protected long currChunk;\n        protected V currValue;\n\n        protected Itr() {\n            this.worldsIterator = Chunk2ObjectMap.this.backendMap.entrySet().iterator();\n        }\n\n        @Override\n        public final boolean hasNext() {\n            return this.currWorldIterator.hasNext() || this.worldsIterator.hasNext();\n        }\n\n        @Override\n        public final T next() {\n            if (!this.currWorldIterator.hasNext()) {\n                if (!this.worldsIterator.hasNext()) {\n                    throw new NoSuchElementException();\n                }\n\n                Entry<String, Long2ObjectMapView<V>> nextWorld = this.worldsIterator.next();\n                this.currWorldIterator = nextWorld.getValue().entryIterator();\n                this.currWorld = nextWorld.getKey();\n                onWorldChange();\n            }\n\n            Long2ObjectMapView.Entry<V> nextChunk = this.currWorldIterator.next();\n            this.currChunk = nextChunk.getKey();\n            this.currValue = nextChunk.getValue();\n\n            return getNext();\n        }\n\n        protected void onWorldChange() {\n\n        }\n\n        protected abstract T getNext();\n\n        @Override\n        public final void remove() {\n            Long2ObjectMapView<V> worldBackendData = Chunk2ObjectMap.this.backendMap.get(this.currWorld);\n\n            this.currWorldIterator.remove();\n            Chunk2ObjectMap.this.onRemove(this.currValue);\n\n            if (worldBackendData.isEmpty())\n                this.worldsIterator.remove();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/CollectionsFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.superiorskyblock.core.collections.creator.CollectionsCreator;\nimport com.bgsoftware.superiorskyblock.core.collections.creator.FastUtilCollectionsCreator;\nimport com.bgsoftware.superiorskyblock.core.collections.creator.JavaCollectionsCreator;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\n\npublic class CollectionsFactory {\n\n    private static final CollectionsCreator creator = findSuitableCollectionsCreator();\n\n    private CollectionsFactory() {\n\n    }\n\n    public static <V> Int2ObjectMapView<V> createInt2ObjectLinkedHashMap() {\n        return creator.createInt2ObjectLinkedHashMap();\n    }\n\n    public static <V> Int2ObjectMapView<V> createInt2ObjectArrayMap() {\n        return creator.createInt2ObjectArrayMap();\n    }\n\n    public static Int2IntMapView createInt2IntArrayMap() {\n        return creator.createInt2IntArrayMap();\n    }\n\n    public static Int2IntMapView createInt2IntHashMap() {\n        return creator.createInt2IntHashMap();\n    }\n\n    public static <V> Long2ObjectMapView<V> createLong2ObjectHashMap() {\n        return creator.createLong2ObjectHashMap();\n    }\n\n    public static <V> Long2ObjectMapView<V> createLong2ObjectLinkedHashMap() {\n        return creator.createLong2ObjectLinkedHashMap();\n    }\n\n    public static <V> Long2ObjectMapView<V> createLong2ObjectArrayMap() {\n        return creator.createLong2ObjectArrayMap();\n    }\n\n    public static <V> Char2ObjectMapView<V> createChar2ObjectArrayMap() {\n        return creator.createChar2ObjectArrayMap();\n    }\n\n    private static CollectionsCreator findSuitableCollectionsCreator() {\n        try {\n            Class.forName(\"it.unimi.dsi.fastutil.ints.Int2IntArrayMap\");\n            return FastUtilCollectionsCreator.INSTANCE;\n        } catch (ClassNotFoundException ignored) {\n        }\n\n        return JavaCollectionsCreator.INSTANCE;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/CompletableFutureList.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.util.ArrayList;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\npublic class CompletableFutureList<E> extends ArrayList<CompletableFuture<E>> {\n\n    private final long timeout;\n\n    public CompletableFutureList(long timeout) {\n        this.timeout = timeout;\n    }\n\n    public void forEachCompleted(Consumer<? super E> consumer, Consumer<Throwable> onFailure) {\n        CompletableFuture<Void> allTasks = CompletableFuture.allOf(toArray(new CompletableFuture[0])).thenRun(() -> {\n            for (CompletableFuture<E> completableFuture : this) {\n                E result = completableFuture.getNow(null);\n                assert result != null; // Result cannot be null as all CompletableFutures must be completed by now.\n                consumer.accept(result);\n            }\n        }).exceptionally(error -> {\n            onFailure.accept(error);\n            return null;\n        });\n\n        if (timeout <= 0L) {\n            allTasks.join();\n        } else try {\n            allTasks.get(timeout, TimeUnit.SECONDS);\n        } catch (Throwable error) {\n            Log.error(error, \"An unexpected error occurred while waiting for tasks to complete:\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.google.common.base.Preconditions;\n\nimport java.util.AbstractCollection;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.IdentityHashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\n\npublic class EnumerateMap<K extends Enumerable, V> {\n\n    private Object[] values;\n    private int size = 0;\n\n    private Values valuesView;\n\n    public EnumerateMap(Collection<K> enumerables) {\n        this.values = new Object[enumerables.size()];\n    }\n\n    public EnumerateMap(V[] values) {\n        this.values = values.clone();\n        for (V value : values)\n            if (value != null) ++size;\n    }\n\n    public EnumerateMap(EnumerateMap<K, V> other) {\n        this.values = other.values.clone();\n        this.size = other.size;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    public boolean containsKey(K key) {\n        return get(key) != null;\n    }\n\n    @Nullable\n    public V get(K key) {\n        return isValidKey(key) ? (V) this.values[key.ordinal()] : null;\n    }\n\n    public V getOrDefault(K key, V def) {\n        V value = get(key);\n        return value == null ? def : value;\n    }\n\n    @Nullable\n    public V put(K key, @NotNull V value) {\n        Preconditions.checkNotNull(value, \"Cannot set values as nulls.\");\n\n        this.ensureCapacity(key.ordinal() + 1);\n\n        V oldValue = (V) this.values[key.ordinal()];\n        this.values[key.ordinal()] = value;\n\n        if (oldValue == null)\n            ++this.size;\n\n        return oldValue;\n    }\n\n    public void putAll(EnumerateMap<K, V> other) {\n        for (int i = 0; i < other.values.length; ++i) {\n            Object val = other.values[i];\n            if (val != null)\n                values[i] = val;\n        }\n    }\n\n    @Nullable\n    public V remove(K key) {\n        if (!isValidKey(key))\n            return null;\n\n        V oldValue = (V) this.values[key.ordinal()];\n        this.values[key.ordinal()] = null;\n\n        --this.size;\n\n        return oldValue;\n    }\n\n    public void clear() {\n        this.values = new Object[this.values.length];\n        this.size = 0;\n    }\n\n    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {\n        V value = get(key);\n        if (value == null) {\n            value = mappingFunction.apply(key);\n            put(key, value);\n        }\n        return value;\n    }\n\n    public <T> Map<K, T> collect(Collection<K> enumerables, Function<V, T> valuesMapper) {\n        Map<K, T> map = new IdentityHashMap<>();\n\n        for (K key : enumerables) {\n            V value = get(key);\n            if (value != null)\n                map.put(key, valuesMapper.apply(value));\n        }\n\n        return map;\n    }\n\n    public <T> Map<K, T> collect(Collection<K> enumerables, BiFunction<K, V, T> valuesMapper) {\n        Map<K, T> map = new IdentityHashMap<>();\n\n        for (K key : enumerables) {\n            V value = get(key);\n            if (value != null)\n                map.put(key, valuesMapper.apply(key, value));\n        }\n\n        return map;\n    }\n\n    public Map<K, V> collect(Collection<K> enumerables) {\n        Map<K, V> map = new IdentityHashMap<>();\n\n        for (K key : enumerables) {\n            V value = get(key);\n            if (value != null)\n                map.put(key, value);\n        }\n\n        return map;\n    }\n\n    public Collection<V> values() {\n        if (valuesView == null)\n            valuesView = new Values();\n\n        return valuesView;\n    }\n\n    private boolean isValidKey(K key) {\n        return key.ordinal() >= 0 && key.ordinal() < this.values.length;\n    }\n\n    private void ensureCapacity(int capacity) {\n        if (capacity <= this.values.length)\n            return;\n\n        this.values = Arrays.copyOf(this.values, capacity);\n    }\n\n    private class Values extends AbstractCollection<V> {\n        public Iterator<V> iterator() {\n            return new ValueIterator();\n        }\n\n        public int size() {\n            return size;\n        }\n\n        public boolean contains(Object o) {\n            for (Object val : values) {\n                if (Objects.equals(o, val))\n                    return true;\n            }\n            return false;\n        }\n\n        public boolean remove(Object o) {\n            for (int i = 0; i < values.length; i++) {\n                if (Objects.equals(o, values[i])) {\n                    values[i] = null;\n                    size--;\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public void clear() {\n            EnumerateMap.this.clear();\n        }\n    }\n\n    private class ValueIterator implements Iterator<V> {\n\n        private int index = 0;\n\n        private int lastReturnedIndex = -1;\n\n        @Override\n        public boolean hasNext() {\n            while (index < values.length && values[index] == null)\n                index++;\n            return index != values.length;\n        }\n\n        @Override\n        public V next() {\n            if (!hasNext())\n                throw new NoSuchElementException();\n            lastReturnedIndex = index++;\n            return (V) values[lastReturnedIndex];\n        }\n\n        @Override\n        public void remove() {\n            checkLastReturnedIndex();\n\n            if (values[lastReturnedIndex] != null) {\n                values[lastReturnedIndex] = null;\n                size--;\n            }\n            lastReturnedIndex = -1;\n        }\n\n        private void checkLastReturnedIndex() {\n            if (lastReturnedIndex < 0)\n                throw new IllegalStateException();\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateSet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class EnumerateSet<K extends Enumerable> {\n\n    private boolean[] values;\n    private int size = 0;\n\n    public EnumerateSet(Collection<K> enumerables) {\n        this.values = new boolean[enumerables.size()];\n    }\n\n    public EnumerateSet(EnumerateSet<K> other) {\n        this.values = other.values.clone();\n        this.size = other.size;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    public boolean contains(K key) {\n        return isValidKey(key) && this.values[key.ordinal()];\n    }\n\n    public boolean add(K key) {\n        this.ensureCapacity(key.ordinal() + 1);\n\n        boolean containedBefore = this.values[key.ordinal()];\n        this.values[key.ordinal()] = true;\n\n        if (!containedBefore)\n            ++this.size;\n\n        return !containedBefore;\n    }\n\n    public boolean addAll(EnumerateSet<Dimension> other) {\n        boolean added = false;\n\n        for (int i = 0; i < other.values.length; ++i) {\n            boolean value = other.values[i];\n            if (value) {\n                this.ensureCapacity(i + 1);\n                if (!values[i]) {\n                    values[i] = added = true;\n                    ++size;\n                }\n            }\n        }\n\n        return added;\n    }\n\n    public boolean remove(K key) {\n        if (!isValidKey(key))\n            return false;\n\n        boolean containedBefore = this.values[key.ordinal()];\n        this.values[key.ordinal()] = false;\n\n        --this.size;\n\n        return containedBefore;\n    }\n\n    public void clear() {\n        this.values = new boolean[this.values.length];\n        this.size = 0;\n    }\n\n    public Set<K> collect(Collection<K> enumerables) {\n        Set<K> set = new LinkedHashSet<>();\n\n        for (K key : enumerables) {\n            if (contains(key))\n                set.add(key);\n        }\n\n        return set;\n    }\n\n    @Override\n    public String toString() {\n        return \"EnumerateSet{\" + Arrays.toString(values) + '}';\n    }\n\n    private boolean isValidKey(K key) {\n        return key.ordinal() >= 0 && key.ordinal() < this.values.length;\n    }\n\n    private void ensureCapacity(int capacity) {\n        if (capacity > this.values.length)\n            this.values = Arrays.copyOf(this.values, capacity);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\n\nimport java.util.AbstractCollection;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.function.Supplier;\n\npublic class IslandPosition2ObjectMap<V> {\n\n    @Nullable\n    private Values values;\n\n    private final Map<String, Long2ObjectMapView<V>> backendMap = new LinkedHashMap<>();\n    private int size = 0;\n\n    public int size() {\n        return this.size;\n    }\n\n    public boolean isEmpty() {\n        return this.size == 0;\n    }\n\n    @Nullable\n    public V get(String worldName, long packedPos) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.get(worldName);\n        if (worldBackendData == null)\n            return null;\n\n        return worldBackendData.get(packedPos);\n    }\n\n    public V computeIfAbsent(String worldName, long packedPos, Supplier<V> newValue) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.computeIfAbsent(worldName, n ->\n                CollectionsFactory.createLong2ObjectLinkedHashMap());\n\n        return worldBackendData.computeIfAbsent(packedPos, p -> {\n            ++IslandPosition2ObjectMap.this.size;\n            return newValue.get();\n        });\n    }\n\n    @Nullable\n    public V put(String worldName, long packedPos, V value) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.computeIfAbsent(worldName, n ->\n                CollectionsFactory.createLong2ObjectLinkedHashMap());\n\n        V oldValue = worldBackendData.put(packedPos, value);\n\n        if (oldValue == null)\n            ++this.size;\n\n        return oldValue;\n    }\n\n    @Nullable\n    public V remove(String worldName, long packedPos) {\n        Long2ObjectMapView<V> worldBackendData = this.backendMap.get(worldName);\n        if (worldBackendData == null)\n            return null;\n\n        V oldValue = onRemove(worldBackendData.remove(packedPos));\n        if (oldValue == null)\n            return null;\n\n        if (worldBackendData.isEmpty())\n            IslandPosition2ObjectMap.this.backendMap.remove(worldName);\n\n        return oldValue;\n    }\n\n    @Nullable\n    private V onRemove(@Nullable V removedValue) {\n        if (removedValue != null)\n            --this.size;\n        return removedValue;\n    }\n\n    public void clear() {\n        this.backendMap.clear();\n        this.size = 0;\n    }\n\n    @NotNull\n    public Collection<V> values() {\n        return this.values == null ? (this.values = new Values()) : this.values;\n    }\n\n    private class Values extends AbstractCollection<V> {\n\n        @Override\n        public int size() {\n            return IslandPosition2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return IslandPosition2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            throw new UnsupportedOperationException();\n        }\n\n        @NotNull\n        @Override\n        public Iterator<V> iterator() {\n            return new ValuesItr();\n        }\n\n        @Override\n        public void clear() {\n            IslandPosition2ObjectMap.this.clear();\n        }\n\n        private class ValuesItr extends Itr<V> {\n\n            @Override\n            protected V getNext() {\n                return this.currentValue;\n            }\n\n        }\n\n    }\n\n    private abstract class Itr<T> implements Iterator<T> {\n\n        protected final Iterator<Map.Entry<String, Long2ObjectMapView<V>>> worldsIterator;\n        protected Iterator<Long2ObjectMapView.Entry<V>> currentWorldIterator = Collections.emptyIterator();\n        protected String currentWorld;\n        protected long currentPosition;\n        protected V currentValue;\n\n        protected Itr() {\n            this.worldsIterator = IslandPosition2ObjectMap.this.backendMap.entrySet().iterator();\n        }\n\n        @Override\n        public final boolean hasNext() {\n            return this.currentWorldIterator.hasNext() || this.worldsIterator.hasNext();\n        }\n\n        @Override\n        public final T next() {\n            if (!this.currentWorldIterator.hasNext()) {\n                if (!this.worldsIterator.hasNext()) {\n                    throw new NoSuchElementException();\n                }\n\n                Map.Entry<String, Long2ObjectMapView<V>> nextWorld = this.worldsIterator.next();\n                this.currentWorldIterator = nextWorld.getValue().entryIterator();\n                this.currentWorld = nextWorld.getKey();\n            }\n\n            Long2ObjectMapView.Entry<V> nextPosition = this.currentWorldIterator.next();\n            this.currentPosition = nextPosition.getKey();\n            this.currentValue = nextPosition.getValue();\n\n            return getNext();\n        }\n\n        protected abstract T getNext();\n\n        @Override\n        public final void remove() {\n            Long2ObjectMapView<V> worldBackendData = IslandPosition2ObjectMap.this.backendMap.get(this.currentWorld);\n\n            this.currentWorldIterator.remove();\n            IslandPosition2ObjectMap.this.onRemove(this.currentValue);\n\n            if (worldBackendData.isEmpty())\n                this.worldsIterator.remove();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/Location2ObjectMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\n\nimport java.util.AbstractCollection;\nimport java.util.AbstractMap;\nimport java.util.AbstractSet;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\npublic class Location2ObjectMap<V> extends AbstractMap<Location, V> {\n\n    private static final boolean IS_TALL_WORLD = ServerVersion.isAtLeast(ServerVersion.v1_18);\n\n    @Nullable\n    private KeySet keySet;\n    @Nullable\n    private Values values;\n    @Nullable\n    private EntrySet entrySet;\n\n    private final Chunk2ObjectMap<ChunkMap<V>> backendMap = new Chunk2ObjectMap<>();\n    private int size = 0;\n\n\n    @Override\n    public int size() {\n        return this.size;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return this.size == 0;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return get(key) != null;\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        return value != null && super.containsValue(value);\n    }\n\n    @Override\n    public V get(Object key) {\n        return key instanceof Location ? get((Location) key) : null;\n    }\n\n    @Nullable\n    private V get(Location location) {\n        String worldName = LazyWorldLocation.getWorldName(location);\n        if (worldName == null)\n            return null;\n\n        int blockX = location.getBlockX();\n        int blockZ = location.getBlockZ();\n\n        long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4);\n\n        ChunkMap<V> chunkMap = this.backendMap.get(worldName, chunkPair);\n        if (chunkMap == null)\n            return null;\n\n        return chunkMap.get(blockX & 0xF, location.getBlockY(), blockZ & 0xF);\n    }\n\n    @Nullable\n    @Override\n    public V put(Location location, V value) {\n        String worldName = LazyWorldLocation.getWorldName(location);\n        Preconditions.checkArgument(worldName != null, \"cannot insert location with null world\");\n\n        int blockX = location.getBlockX();\n        int blockZ = location.getBlockZ();\n\n        long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4);\n\n        ChunkMap<V> chunkMap = this.backendMap.computeIfAbsent(worldName, chunkPair, ChunkMap::new);\n\n        V oldValue = chunkMap.put(blockX & 0xF, location.getBlockY(), blockZ & 0xF, value);\n\n        if (oldValue == null)\n            ++this.size;\n\n        return oldValue;\n    }\n\n    @Override\n    public V remove(Object key) {\n        return key instanceof Location ? remove((Location) key) : null;\n    }\n\n    @Nullable\n    public V remove(Location location) {\n        String worldName = LazyWorldLocation.getWorldName(location);\n        if (worldName == null)\n            return null;\n\n        int blockX = location.getBlockX();\n        int blockZ = location.getBlockZ();\n\n        long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4);\n\n        ChunkMap<V> chunkMap = this.backendMap.get(worldName, chunkPair);\n        if (chunkMap == null)\n            return null;\n\n        V oldValue = onRemove(chunkMap.remove(blockX & 0xF, location.getBlockY(), blockZ & 0xF));\n        if (oldValue == null)\n            return null;\n\n        if (chunkMap.isEmpty()) {\n            this.backendMap.remove(worldName, chunkPair);\n        }\n\n        return oldValue;\n    }\n\n    @Nullable\n    private V onRemove(@Nullable V removedValue) {\n        if (removedValue != null)\n            --this.size;\n        return removedValue;\n    }\n\n    @Override\n    public void clear() {\n        this.backendMap.clear();\n        this.size = 0;\n    }\n\n    @NotNull\n    @Override\n    public Set<Location> keySet() {\n        return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet;\n    }\n\n    @NotNull\n    @Override\n    public Collection<V> values() {\n        return this.values == null ? (this.values = new Values()) : this.values;\n    }\n\n    public void forEach(ChunkPosition chunkPosition, Consumer<V> consumer) {\n        ChunkMap<V> chunkMap = this.backendMap.get(chunkPosition.getWorldName(), chunkPosition.asPair());\n        if (chunkMap == null)\n            return;\n\n        Iterator<V> iterator = chunkMap.backendData.valueIterator();\n        while (iterator.hasNext())\n            consumer.accept(iterator.next());\n    }\n\n    public void removeAll(ChunkPosition chunkPosition, Consumer<V> predicate) {\n        ChunkMap<V> chunkMap = this.backendMap.remove(chunkPosition.getWorldName(), chunkPosition.asPair());\n        if (chunkMap == null)\n            return;\n\n        Iterator<V> iterator = chunkMap.backendData.valueIterator();\n        while (iterator.hasNext())\n            predicate.accept(iterator.next());\n\n        chunkMap.backendData.clear();\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<Location, V>> entrySet() {\n        return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet;\n    }\n\n    private static long computeChunkPair(int chunkX, int chunkZ) {\n        return ((chunkZ & 0xFFFFFFFFL) << 32) | (chunkX & 0xFFFFFFFFL);\n    }\n\n    private static int computeBlockIndex(int relativeX, int blockY, int relativeZ) {\n        Preconditions.checkArgument(relativeX >= 0 && relativeX <= 0xF, \"invalid relativeX: \" + relativeX);\n        Preconditions.checkArgument(relativeZ >= 0 && relativeZ <= 0xF, \"invalid blockZ: \" + relativeZ);\n\n        int worldMinHeight = IS_TALL_WORLD ? 0 : -64;\n\n        short relativeY = (short) (blockY - worldMinHeight);\n        return (relativeY << 8) | (relativeX << 4) | relativeZ;\n    }\n\n    private static Location computeLocationFromBlockAndChunk(String worldName, long chunkPair, int blockIdx) {\n        int chunkX = Chunk2ObjectMap.getChunkXFromPair(chunkPair);\n        int chunkZ = Chunk2ObjectMap.getChunkZFromPair(chunkPair);\n\n        int blockX = (chunkX << 4) + getRelativeBlockXFromIndex(blockIdx);\n        int blockY = (IS_TALL_WORLD ? 0 : -64) + getRelativeBlockYFromIndex(blockIdx);\n        int blockZ = (chunkZ << 4) + getRelativeBlockZFromIndex(blockIdx);\n\n        return new LazyWorldLocation(worldName, blockX, blockY, blockZ, 0, 0);\n    }\n\n    private static int getRelativeBlockXFromIndex(int blockIdx) {\n        return (blockIdx >> 4) & 0xF;\n    }\n\n    private static int getRelativeBlockYFromIndex(int blockIdx) {\n        return blockIdx >> 8;\n    }\n\n    private static int getRelativeBlockZFromIndex(int blockIdx) {\n        return blockIdx & 0xF;\n    }\n\n    private static class ChunkMap<V> {\n\n        private final Int2ObjectMapView<V> backendData = CollectionsFactory.createInt2ObjectLinkedHashMap();\n\n        @Nullable\n        public V get(int relativeX, int blockY, int relativeZ) {\n            int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ);\n            return get(blockIdx);\n        }\n\n        @Nullable\n        public V get(int blockIdx) {\n            return this.backendData.get(blockIdx);\n        }\n\n        @Nullable\n        public V put(int relativeX, int blockY, int relativeZ, V value) {\n            int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ);\n            return put(blockIdx, value);\n        }\n\n        @Nullable\n        public V put(int blockIdx, V value) {\n            return this.backendData.put(blockIdx, value);\n        }\n\n        @Nullable\n        public V remove(int relativeX, int blockY, int relativeZ) {\n            int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ);\n            return this.remove(blockIdx);\n        }\n\n        @Nullable\n        public V remove(int blockIdx) {\n            return this.backendData.remove(blockIdx);\n        }\n\n        public boolean isEmpty() {\n            return this.backendData.isEmpty();\n        }\n\n    }\n\n    private class KeySet extends AbstractSet<Location> {\n\n        @Override\n        public int size() {\n            return Location2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Location2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return Location2ObjectMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Location> iterator() {\n            return new KeySetItr();\n        }\n\n        @Override\n        public void clear() {\n            Location2ObjectMap.this.clear();\n        }\n\n        private class KeySetItr extends Itr<Location> {\n\n            @Override\n            protected Location getNext() {\n                return computeLocationFromBlockAndChunk(this.currWorld, this.currChunk, this.currBlockIdx);\n            }\n\n        }\n\n    }\n\n    private class Values extends AbstractCollection<V> {\n\n        @Override\n        public int size() {\n            return Location2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Location2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return Location2ObjectMap.this.containsValue(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<V> iterator() {\n            return new ValuesItr();\n        }\n\n        @Override\n        public void clear() {\n            Location2ObjectMap.this.clear();\n        }\n\n        private class ValuesItr extends Itr<V> {\n\n            @Override\n            protected V getNext() {\n                return this.currValue;\n            }\n\n        }\n\n    }\n\n    private class EntrySet extends AbstractSet<Entry<Location, V>> {\n\n        @Override\n        public int size() {\n            return Location2ObjectMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return Location2ObjectMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            Location key = null;\n\n            if (o instanceof Entry) {\n                o = ((Entry<?, ?>) o).getKey();\n            }\n\n            if (o instanceof Location)\n                key = (Location) o;\n\n            return key != null && Location2ObjectMap.this.containsKey(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Entry<Location, V>> iterator() {\n            return new EntrySetItr();\n        }\n\n        @Override\n        public void clear() {\n            Location2ObjectMap.this.clear();\n        }\n\n        private class EntrySetItr extends Itr<Entry<Location, V>> {\n\n            @Override\n            protected Entry<Location, V> getNext() {\n                return new EntryImpl(this.currWorld, this.currChunk, this.currBlockIdx, this.currValue);\n            }\n\n            private class EntryImpl implements Entry<Location, V> {\n\n                private final String worldName;\n                private final long chunkPair;\n                private final int blockIdx;\n\n                private Location cachedLocation;\n                private V cachedValue;\n\n\n                EntryImpl(String worldName, long chunkPair, int blockIdx, V value) {\n                    this.worldName = worldName;\n                    this.chunkPair = chunkPair;\n                    this.blockIdx = blockIdx;\n                    this.cachedValue = value;\n                }\n\n                @Override\n                public Location getKey() {\n                    return this.cachedLocation == null ?\n                            (this.cachedLocation = computeLocationFromBlockAndChunk(this.worldName, this.chunkPair, this.blockIdx)) :\n                            this.cachedLocation;\n                }\n\n                @Override\n                public V getValue() {\n                    if (this.cachedValue == null) {\n                        this.cachedValue = Location2ObjectMap.this.backendMap\n                                .get(this.worldName, this.chunkPair)\n                                .get(this.blockIdx);\n                    }\n\n                    return this.cachedValue;\n                }\n\n                @Override\n                public V setValue(V v) {\n                    V oldValue = this.cachedValue;\n                    this.cachedValue = v;\n\n                    Location2ObjectMap.this.backendMap\n                            .get(this.worldName, this.chunkPair)\n                            .put(this.blockIdx, this.cachedValue);\n\n                    return oldValue;\n                }\n            }\n\n        }\n\n    }\n\n    private abstract class Itr<T> implements Iterator<T> {\n\n        protected final Iterator<Entry<ChunkPosition, ChunkMap<V>>> worldsIterator;\n        protected Iterator<Int2ObjectMapView.Entry<V>> currChunkIterator = Collections.emptyIterator();\n        protected String currWorld;\n        protected long currChunk;\n        protected ChunkMap<V> currChunkMap;\n        protected int currBlockIdx;\n        protected V currValue;\n\n        protected Itr() {\n            this.worldsIterator = Location2ObjectMap.this.backendMap.entrySet().iterator();\n        }\n\n        @Override\n        public final boolean hasNext() {\n            return this.currChunkIterator.hasNext() || this.worldsIterator.hasNext();\n        }\n\n        @Override\n        public final T next() {\n            if (!this.currChunkIterator.hasNext()) {\n                Entry<ChunkPosition, ChunkMap<V>> nextChunk = this.worldsIterator.next();\n                this.currWorld = nextChunk.getKey().getWorldName();\n                this.currChunk = nextChunk.getKey().asPair();\n                this.currChunkMap = nextChunk.getValue();\n                this.currChunkIterator = this.currChunkMap.backendData.entryIterator();\n            }\n\n            Int2ObjectMapView.Entry<V> nextBlock = this.currChunkIterator.next();\n            this.currBlockIdx = nextBlock.getKey();\n            this.currValue = nextBlock.getValue();\n\n            return getNext();\n        }\n\n        protected abstract T getNext();\n\n        @Override\n        public final void remove() {\n            this.currChunkIterator.remove();\n            Location2ObjectMap.this.onRemove(this.currValue);\n\n            if (this.currChunkMap.isEmpty())\n                this.worldsIterator.remove();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/CollectionsCreator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.creator;\n\nimport com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\n\npublic interface CollectionsCreator {\n\n    <V> Int2ObjectMapView<V> createInt2ObjectLinkedHashMap();\n\n    <V> Int2ObjectMapView<V> createInt2ObjectArrayMap();\n\n    Int2IntMapView createInt2IntHashMap();\n\n    Int2IntMapView createInt2IntArrayMap();\n\n    <V> Long2ObjectMapView<V> createLong2ObjectHashMap();\n\n    <V> Long2ObjectMapView<V> createLong2ObjectLinkedHashMap();\n\n    <V> Long2ObjectMapView<V> createLong2ObjectArrayMap();\n\n    <V> Char2ObjectMapView<V> createChar2ObjectArrayMap();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/FastUtilCollectionsCreator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.creator;\n\nimport com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.CharIterator;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.IntIterator;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\nimport it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap;\nimport it.unimi.dsi.fastutil.chars.Char2ObjectMap;\nimport it.unimi.dsi.fastutil.ints.Int2IntArrayMap;\nimport it.unimi.dsi.fastutil.ints.Int2IntMap;\nimport it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;\nimport it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;\nimport it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;\nimport it.unimi.dsi.fastutil.ints.Int2ObjectMap;\nimport it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap;\nimport it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;\nimport it.unimi.dsi.fastutil.longs.Long2ObjectMap;\nimport it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;\n\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.OptionalInt;\n\npublic class FastUtilCollectionsCreator implements CollectionsCreator {\n\n    public static final FastUtilCollectionsCreator INSTANCE = new FastUtilCollectionsCreator();\n\n    private FastUtilCollectionsCreator() {\n\n    }\n\n    @Override\n    public <V> Int2ObjectMapView<V> createInt2ObjectLinkedHashMap() {\n        return new Int2ObjectFastUtilMapView<>(new Int2ObjectLinkedOpenHashMap<>());\n    }\n\n    @Override\n    public <V> Int2ObjectMapView<V> createInt2ObjectArrayMap() {\n        return new Int2ObjectFastUtilMapView<>(new Int2ObjectArrayMap<>());\n    }\n\n    @Override\n    public Int2IntMapView createInt2IntHashMap() {\n        return new Int2IntFastUtilMapView(new Int2IntOpenHashMap());\n    }\n\n    @Override\n    public Int2IntMapView createInt2IntArrayMap() {\n        return new Int2IntFastUtilMapView(new Int2IntArrayMap());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectHashMap() {\n        return new Long2ObjectFastUtilMapView<>(new Long2ObjectOpenHashMap<>());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectLinkedHashMap() {\n        return new Long2ObjectFastUtilMapView<>(new Long2ObjectLinkedOpenHashMap<>());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectArrayMap() {\n        return new Long2ObjectFastUtilMapView<>(new Long2ObjectArrayMap<>());\n    }\n\n    @Override\n    public <V> Char2ObjectMapView<V> createChar2ObjectArrayMap() {\n        return new Char2ObjectFastUtilMapView<>(new Char2ObjectArrayMap<>());\n    }\n\n    private static class Int2ObjectFastUtilMapView<V> implements Int2ObjectMapView<V> {\n\n        private final Int2ObjectMap<V> delegate;\n\n        Int2ObjectFastUtilMapView(Int2ObjectMap<V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(int key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(int key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(int key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.int2ObjectEntrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public IntIterator keyIterator() {\n            return new IntIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Int2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Int2ObjectMap.Entry<V>> handle;\n\n            EntryIteratorWrapper(Iterator<Int2ObjectMap.Entry<V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Int2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Int2ObjectMapView.Entry<V> {\n\n                private final Int2ObjectMap.Entry<V> handle;\n\n                EntryWrapper(Int2ObjectMap.Entry<V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public int getKey() {\n                    return this.handle.getIntKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n    }\n\n    private static class Int2IntFastUtilMapView implements Int2IntMapView {\n\n        private final Int2IntMap delegate;\n\n        Int2IntFastUtilMapView(Int2IntMap delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public OptionalInt put(int key, int value) {\n            int old = this.delegate.put(key, value);\n            return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public OptionalInt get(int key) {\n            int old = this.delegate.get(key);\n            return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public OptionalInt remove(int key) {\n            int old = this.delegate.remove(key);\n            return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry> entryIterator() {\n            return new EntryIteratorWrapper(this.delegate.int2IntEntrySet().iterator());\n        }\n\n        @Override\n        public IntIterator valueIterator() {\n            return new IntIteratorWrapper(this.delegate.values().iterator());\n        }\n\n        @Override\n        public IntIterator keyIterator() {\n            return new IntIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        @Override\n        public Map<Integer, Integer> asMap() {\n            return this.delegate;\n        }\n\n        private static class EntryIteratorWrapper implements Iterator<Int2IntMapView.Entry> {\n\n            private final Iterator<Int2IntMap.Entry> handle;\n\n            EntryIteratorWrapper(Iterator<Int2IntMap.Entry> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Int2IntMapView.Entry next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private static class EntryWrapper implements Int2IntMapView.Entry {\n\n                private final Int2IntMap.Entry handle;\n\n                EntryWrapper(Int2IntMap.Entry handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public int getKey() {\n                    return this.handle.getIntKey();\n                }\n\n                @Override\n                public int getValue() {\n                    return this.handle.getIntValue();\n                }\n\n                @Override\n                public int setValue(int newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n    }\n\n    private static class Long2ObjectFastUtilMapView<V> implements Long2ObjectMapView<V> {\n\n        private final Long2ObjectMap<V> delegate;\n\n        Long2ObjectFastUtilMapView(Long2ObjectMap<V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(long key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(long key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(long key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.long2ObjectEntrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public LongIterator keyIterator() {\n            return new LongIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Long2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Long2ObjectMap.Entry<V>> handle;\n\n            EntryIteratorWrapper(Iterator<Long2ObjectMap.Entry<V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Long2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Long2ObjectMapView.Entry<V> {\n\n                private final Long2ObjectMap.Entry<V> handle;\n\n                EntryWrapper(Long2ObjectMap.Entry<V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public long getKey() {\n                    return this.handle.getLongKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n    }\n\n    private static class Char2ObjectFastUtilMapView<V> implements Char2ObjectMapView<V> {\n\n        private final Char2ObjectMap<V> delegate;\n\n        Char2ObjectFastUtilMapView(Char2ObjectMap<V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(char key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(char key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(char key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.char2ObjectEntrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public CharIterator keyIterator() {\n            return new CharIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Char2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Char2ObjectMap.Entry<V>> handle;\n\n            EntryIteratorWrapper(Iterator<Char2ObjectMap.Entry<V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Char2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Char2ObjectMapView.Entry<V> {\n\n                private final Char2ObjectMap.Entry<V> handle;\n\n                EntryWrapper(Char2ObjectMap.Entry<V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public char getKey() {\n                    return this.handle.getCharKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n    }\n\n    private static class IntIteratorWrapper implements IntIterator {\n\n        private final it.unimi.dsi.fastutil.ints.IntIterator handle;\n\n        IntIteratorWrapper(it.unimi.dsi.fastutil.ints.IntIterator handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public int next() {\n            return this.handle.nextInt();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n    private static class LongIteratorWrapper implements LongIterator {\n\n        private final it.unimi.dsi.fastutil.longs.LongIterator handle;\n\n        LongIteratorWrapper(it.unimi.dsi.fastutil.longs.LongIterator handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public long next() {\n            return this.handle.nextLong();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n    private static class CharIteratorWrapper implements CharIterator {\n\n        private final it.unimi.dsi.fastutil.chars.CharIterator handle;\n\n        CharIteratorWrapper(it.unimi.dsi.fastutil.chars.CharIterator handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public char next() {\n            return this.handle.nextChar();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/JavaCollectionsCreator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.creator;\n\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.CharIterator;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.IntIterator;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.LongIterator;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.OptionalInt;\n\npublic class JavaCollectionsCreator implements CollectionsCreator {\n\n    public static final JavaCollectionsCreator INSTANCE = new JavaCollectionsCreator();\n\n    private JavaCollectionsCreator() {\n\n    }\n\n    @Override\n    public <V> Int2ObjectMapView<V> createInt2ObjectLinkedHashMap() {\n        return new Int2ObjectJavaMapView<>(new LinkedHashMap<>());\n    }\n\n    @Override\n    public <V> Int2ObjectMapView<V> createInt2ObjectArrayMap() {\n        return new Int2ObjectJavaMapView<>(new ArrayMap<>());\n    }\n\n    @Override\n    public Int2IntMapView createInt2IntHashMap() {\n        return new Int2IntJavaMapView(new HashMap<>());\n    }\n\n    @Override\n    public Int2IntMapView createInt2IntArrayMap() {\n        return new Int2IntJavaMapView(new ArrayMap<>());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectHashMap() {\n        return new Long2ObjectJavaMapView<>(new HashMap<>());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectLinkedHashMap() {\n        return new Long2ObjectJavaMapView<>(new LinkedHashMap<>());\n    }\n\n    @Override\n    public <V> Long2ObjectMapView<V> createLong2ObjectArrayMap() {\n        return new Long2ObjectJavaMapView<>(new ArrayMap<>());\n    }\n\n    @Override\n    public <V> Char2ObjectMapView<V> createChar2ObjectArrayMap() {\n        return new Char2ObjectJavaMapView<>(new ArrayMap<>());\n    }\n\n    private static class Int2ObjectJavaMapView<V> implements Int2ObjectMapView<V> {\n\n        private final Map<Integer, V> delegate;\n\n        Int2ObjectJavaMapView(Map<Integer, V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(int key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(int key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(int key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public IntIterator keyIterator() {\n            return new IntIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Int2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Map.Entry<Integer, V>> handle;\n\n            EntryIteratorWrapper(Iterator<Map.Entry<Integer, V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Int2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Int2ObjectMapView.Entry<V> {\n\n                private final Map.Entry<Integer, V> handle;\n\n                EntryWrapper(Map.Entry<Integer, V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public int getKey() {\n                    return this.handle.getKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n    }\n\n    private static class Int2IntJavaMapView implements Int2IntMapView {\n\n        private final Map<Integer, Integer> delegate;\n\n        Int2IntJavaMapView(Map<Integer, Integer> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public OptionalInt put(int key, int value) {\n            Integer old = this.delegate.put(key, value);\n            return old == null ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public OptionalInt get(int key) {\n            Integer old = this.delegate.get(key);\n            return old == null ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public OptionalInt remove(int key) {\n            Integer old = this.delegate.remove(key);\n            return old == null ? OptionalInt.empty() : OptionalInt.of(old);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry> entryIterator() {\n            return new EntryIteratorWrapper(this.delegate.entrySet().iterator());\n        }\n\n        @Override\n        public IntIterator valueIterator() {\n            return new IntIteratorWrapper(this.delegate.values().iterator());\n        }\n\n        @Override\n        public IntIterator keyIterator() {\n            return new IntIteratorWrapper(this.delegate.values().iterator());\n        }\n\n        @Override\n        public Map<Integer, Integer> asMap() {\n            return this.delegate;\n        }\n\n        private static class EntryIteratorWrapper implements Iterator<Int2IntMapView.Entry> {\n\n            private final Iterator<Map.Entry<Integer, Integer>> handle;\n\n            EntryIteratorWrapper(Iterator<Map.Entry<Integer, Integer>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Int2IntMapView.Entry next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private static class EntryWrapper implements Int2IntMapView.Entry {\n\n                private final Map.Entry<Integer, Integer> handle;\n\n                EntryWrapper(Map.Entry<Integer, Integer> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public int getKey() {\n                    return this.handle.getKey();\n                }\n\n                @Override\n                public int getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public int setValue(int newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n\n    }\n\n    private static class Long2ObjectJavaMapView<V> implements Long2ObjectMapView<V> {\n\n        private final Map<Long, V> delegate;\n\n        Long2ObjectJavaMapView(Map<Long, V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(long key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(long key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(long key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public LongIterator keyIterator() {\n            return new LongIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Long2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Map.Entry<Long, V>> handle;\n\n            EntryIteratorWrapper(Iterator<Map.Entry<Long, V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Long2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Long2ObjectMapView.Entry<V> {\n\n                private final Map.Entry<Long, V> handle;\n\n                EntryWrapper(Map.Entry<Long, V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public long getKey() {\n                    return this.handle.getKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n\n    }\n\n    private static class Char2ObjectJavaMapView<V> implements Char2ObjectMapView<V> {\n\n        private final Map<Character, V> delegate;\n\n        Char2ObjectJavaMapView(Map<Character, V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Override\n        public V put(char key, V value) {\n            return this.delegate.put(key, value);\n        }\n\n        @Override\n        public V get(char key) {\n            return this.delegate.get(key);\n        }\n\n        @Override\n        public V remove(char key) {\n            return this.delegate.remove(key);\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public void clear() {\n            this.delegate.clear();\n        }\n\n        @Override\n        public Iterator<Entry<V>> entryIterator() {\n            return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator());\n        }\n\n        @Override\n        public Iterator<V> valueIterator() {\n            return this.delegate.values().iterator();\n        }\n\n        @Override\n        public CharIterator keyIterator() {\n            return new CharIteratorWrapper(this.delegate.keySet().iterator());\n        }\n\n        private static class EntryIteratorWrapper<V> implements Iterator<Char2ObjectMapView.Entry<V>> {\n\n            private final Iterator<Map.Entry<Character, V>> handle;\n\n            EntryIteratorWrapper(Iterator<Map.Entry<Character, V>> handle) {\n                this.handle = handle;\n            }\n\n            @Override\n            public boolean hasNext() {\n                return this.handle.hasNext();\n            }\n\n            @Override\n            public Char2ObjectMapView.Entry<V> next() {\n                return new EntryWrapper(this.handle.next());\n            }\n\n            @Override\n            public void remove() {\n                this.handle.remove();\n            }\n\n            private class EntryWrapper implements Char2ObjectMapView.Entry<V> {\n\n                private final Map.Entry<Character, V> handle;\n\n                EntryWrapper(Map.Entry<Character, V> handle) {\n                    this.handle = handle;\n                }\n\n                @Override\n                public char getKey() {\n                    return this.handle.getKey();\n                }\n\n                @Override\n                public V getValue() {\n                    return this.handle.getValue();\n                }\n\n                @Override\n                public V setValue(V newValue) {\n                    return this.handle.setValue(newValue);\n                }\n            }\n\n        }\n\n\n    }\n\n    private static class IntIteratorWrapper implements IntIterator {\n\n        private final Iterator<Integer> handle;\n\n        IntIteratorWrapper(Iterator<Integer> handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public int next() {\n            return this.handle.next();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n    private static class LongIteratorWrapper implements LongIterator {\n\n        private final Iterator<Long> handle;\n\n        LongIteratorWrapper(Iterator<Long> handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public long next() {\n            return this.handle.next();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n    private static class CharIteratorWrapper implements CharIterator {\n\n        private final Iterator<Character> handle;\n\n        CharIteratorWrapper(Iterator<Character> handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.handle.hasNext();\n        }\n\n        @Override\n        public char next() {\n            return this.handle.next();\n        }\n\n        @Override\n        public void remove() {\n            this.handle.remove();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Char2ObjectMapView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Iterator;\n\npublic interface Char2ObjectMapView<V> {\n\n    @Nullable\n    V put(char key, V value);\n\n    @Nullable\n    V get(char key);\n\n    default V getOrDefault(char key, V def) {\n        V value = get(key);\n        return value == null ? def : value;\n    }\n\n    @Nullable\n    V remove(char key);\n\n    int size();\n\n    default boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    void clear();\n\n    Iterator<Entry<V>> entryIterator();\n\n    Iterator<V> valueIterator();\n\n    CharIterator keyIterator();\n\n    default V computeIfAbsent(char key, AbsentConsumer<V> consumer) {\n        V value = get(key);\n        if (value == null) {\n            value = consumer.accept(key);\n            put(key, value);\n        }\n\n        return value;\n    }\n\n    interface AbsentConsumer<V> {\n\n        V accept(char key);\n\n    }\n\n    interface Entry<V> {\n\n        char getKey();\n\n        V getValue();\n\n        V setValue(V newValue);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/CharIterator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\npublic interface CharIterator {\n\n    boolean hasNext();\n\n    char next();\n\n    void remove();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/EmptyInt2IntMapView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.OptionalInt;\n\npublic class EmptyInt2IntMapView implements Int2IntMapView {\n\n    public static final EmptyInt2IntMapView INSTANCE = new EmptyInt2IntMapView();\n\n    private EmptyInt2IntMapView() {\n\n    }\n\n    @Override\n    public OptionalInt put(int key, int value) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public OptionalInt get(int key) {\n        return OptionalInt.empty();\n    }\n\n    @Override\n    public OptionalInt remove(int key) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int size() {\n        return 0;\n    }\n\n    @Override\n    public void clear() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Iterator<Entry> entryIterator() {\n        return Collections.emptyIterator();\n    }\n\n    @Override\n    public IntIterator valueIterator() {\n        return EmptyIntIterator.INSTANCE;\n    }\n\n    @Override\n    public IntIterator keyIterator() {\n        return EmptyIntIterator.INSTANCE;\n    }\n\n    @Override\n    public Map<Integer, Integer> asMap() {\n        return Collections.emptyMap();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/EmptyIntIterator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport java.util.NoSuchElementException;\n\npublic class EmptyIntIterator implements IntIterator {\n\n    public static final EmptyIntIterator INSTANCE = new EmptyIntIterator();\n\n    private EmptyIntIterator() {\n\n    }\n\n    @Override\n    public boolean hasNext() {\n        return false;\n    }\n\n    @Override\n    public int next() {\n        throw new NoSuchElementException();\n    }\n\n    @Override\n    public void remove() {\n        throw new NoSuchElementException();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2IntMapView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.OptionalInt;\n\npublic interface Int2IntMapView {\n\n    OptionalInt put(int key, int value);\n\n    OptionalInt get(int key);\n\n    default int getOrDefault(int key, int def) {\n        OptionalInt value = get(key);\n        return value.isPresent() ? value.getAsInt() : def;\n    }\n\n    OptionalInt remove(int key);\n\n    int size();\n\n    default boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    void clear();\n\n    Iterator<Entry> entryIterator();\n\n    IntIterator valueIterator();\n\n    IntIterator keyIterator();\n\n    Map<Integer, Integer> asMap();\n\n    default int computeIfAbsent(int key, AbsentConsumer consumer) {\n        OptionalInt valueOptional = get(key);\n\n        int value;\n        if (valueOptional.isPresent()) {\n            value = valueOptional.getAsInt();\n        } else {\n            value = consumer.accept(key);\n            put(key, value);\n        }\n\n        return value;\n    }\n\n    interface AbsentConsumer {\n\n        int accept(int key);\n\n    }\n\n    interface Entry {\n\n        int getKey();\n\n        int getValue();\n\n        int setValue(int newValue);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Iterator;\n\npublic interface Int2ObjectMapView<V> {\n\n    @Nullable\n    V put(int key, V value);\n\n    @Nullable\n    V get(int key);\n\n    default V getOrDefault(int key, V def) {\n        V value = get(key);\n        return value == null ? def : value;\n    }\n\n    @Nullable\n    V remove(int key);\n\n    int size();\n\n    default boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    void clear();\n\n    Iterator<Entry<V>> entryIterator();\n\n    Iterator<V> valueIterator();\n\n    IntIterator keyIterator();\n\n    default V computeIfAbsent(int key, AbsentConsumer<V> consumer) {\n        V value = get(key);\n        if (value == null) {\n            value = consumer.accept(key);\n            put(key, value);\n        }\n\n        return value;\n    }\n\n    default void putAll(Int2ObjectMapView<V> other) {\n        if (!other.isEmpty()) {\n            Iterator<Entry<V>> iterator = other.entryIterator();\n            while (iterator.hasNext()) {\n                Entry<V> entry = iterator.next();\n                put(entry.getKey(), entry.getValue());\n            }\n        }\n    }\n\n    interface AbsentConsumer<V> {\n\n        V accept(int key);\n\n    }\n\n    interface Entry<V> {\n\n        int getKey();\n\n        V getValue();\n\n        V setValue(V newValue);\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/IntIterator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\npublic interface IntIterator {\n\n    boolean hasNext();\n\n    int next();\n\n    void remove();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Iterator;\n\npublic interface Long2ObjectMapView<V> {\n\n    @Nullable\n    V put(long key, V value);\n\n    @Nullable\n    V get(long key);\n\n    default V getOrDefault(long key, V def) {\n        V value = get(key);\n        return value == null ? def : value;\n    }\n\n    default void putAll(Long2ObjectMapView<V> other) {\n        Iterator<Entry<V>> iterator = other.entryIterator();\n        while (iterator.hasNext()) {\n            Entry<V> entry = iterator.next();\n            put(entry.getKey(), entry.getValue());\n        }\n    }\n\n    @Nullable\n    V remove(long key);\n\n    int size();\n\n    default boolean isEmpty() {\n        return size() <= 0;\n    }\n\n    void clear();\n\n    Iterator<Entry<V>> entryIterator();\n\n    Iterator<V> valueIterator();\n\n    LongIterator keyIterator();\n\n    default V computeIfAbsent(long key, AbsentConsumer<V> consumer) {\n        V value = get(key);\n        if (value == null) {\n            value = consumer.accept(key);\n            put(key, value);\n        }\n\n        return value;\n    }\n\n    interface AbsentConsumer<V> {\n\n        V accept(long key);\n\n    }\n\n    interface Entry<V> {\n\n        long getKey();\n\n        V getValue();\n\n        V setValue(V newValue);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/LongIterator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.collections.view;\n\npublic interface LongIterator {\n\n    boolean hasNext();\n\n    long next();\n\n    void remove();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java",
    "content": "package com.bgsoftware.superiorskyblock.core.config;\n\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\npublic class PvPWorldsCache {\n\n    private final Set<String> pvpWorldNames = new HashSet<>();\n    private final List<Pattern> pvpWorldPatterns = new LinkedList<>();\n\n    public PvPWorldsCache(List<String> pvpWorlds) {\n        for (String worldName : pvpWorlds) {\n            Pattern worldNamePattern = getPatternRegex(worldName);\n            if (worldNamePattern == null) {\n                this.pvpWorldNames.add(worldName);\n            } else {\n                this.pvpWorldPatterns.add(worldNamePattern);\n            }\n        }\n    }\n\n    public boolean isPvPWorld(String worldName) {\n        return isPvPWorldByName(worldName) || isPvPWorldByPattern(worldName);\n    }\n\n    private boolean isPvPWorldByName(String worldName) {\n        return !this.pvpWorldNames.isEmpty() && this.pvpWorldNames.contains(worldName);\n    }\n\n    private boolean isPvPWorldByPattern(String worldName) {\n        for (Pattern pattern : this.pvpWorldPatterns) {\n            if (pattern.matcher(worldName).matches())\n                return true;\n        }\n\n        return false;\n    }\n\n    private static Pattern getPatternRegex(String value) {\n        try {\n            Pattern pattern = Pattern.compile(value);\n            if (value.matches(\".*[.*+?^${}()|\\\\[\\\\]\\\\\\\\].*\"))\n                return pattern;\n        } catch (PatternSyntaxException ignored) {\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\n\npublic class DBColumn extends Pair<String, Object> {\n\n    public DBColumn(String columnName, Object value) {\n        super(columnName, value);\n    }\n\n    public DBColumn withNameAndValue(String columnName, Object value) {\n        setKey(columnName);\n        setValue(value);\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache;\nimport com.bgsoftware.superiorskyblock.core.database.loader.DatabaseLoader;\nimport com.bgsoftware.superiorskyblock.core.database.loader.backup.BackupDatabase;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.SQLDatabaseLoader;\nimport com.bgsoftware.superiorskyblock.core.database.serialization.IslandsDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.serialization.PlayersDeserializer;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\n\nimport java.io.File;\nimport java.math.BigDecimal;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@SuppressWarnings(\"WeakerAccess\")\npublic class DataManager extends Manager {\n\n    private static final UUID CONSOLE_UUID = new UUID(0, 0);\n    private final List<DatabaseLoader> databaseLoaders = new LinkedList<>();\n\n    public DataManager(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadData() throws ManagerLoadException {\n        loadDatabaseLoaders();\n\n        runState(DatabaseLoader.State.INITIALIZE);\n\n        runState(DatabaseLoader.State.POST_INITIALIZE);\n\n        runState(DatabaseLoader.State.PRE_LOAD_DATA);\n\n        if (PluginEventsFactory.callPluginLoadDataEvent()) {\n            loadPlayers();\n            loadIslands();\n            loadGrid();\n        }\n\n        runState(DatabaseLoader.State.POST_LOAD_DATA);\n\n        /*\n         *  Because of a bug caused leaders to be guests, I am looping through all the players and trying to fix it here.\n         */\n\n        for (SuperiorPlayer superiorPlayer : plugin.getPlayers().getAllPlayers()) {\n            if (superiorPlayer.getIslandLeader().getUniqueId().equals(superiorPlayer.getUniqueId()) && superiorPlayer.getIsland() != null && !superiorPlayer.getPlayerRole().isLastRole()) {\n                Log.warn(\"Seems like \", superiorPlayer.getName(), \" is an island leader, but have a guest role - fixing it...\");\n                superiorPlayer.setPlayerRole(SPlayerRole.lastRole());\n            }\n        }\n    }\n\n    public void addDatabaseLoader(DatabaseLoader databaseLoader) {\n        this.databaseLoaders.add(databaseLoader);\n    }\n\n    public void saveDatabase(boolean async) {\n        if (async && Bukkit.isPrimaryThread()) {\n            BukkitExecutor.async(() -> saveDatabase(false));\n            return;\n        }\n\n        try {\n            //Saving grid\n            GridDatabaseBridge.deleteGrid(plugin.getGrid());\n            GridDatabaseBridge.insertGrid(plugin.getGrid());\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while saving database:\");\n        }\n    }\n\n    public void closeConnection() {\n        for (DatabaseLoader databaseLoader : databaseLoaders) {\n            try {\n                databaseLoader.setState(DatabaseLoader.State.SHUTDOWN);\n            } catch (Throwable ignored) {\n            }\n        }\n    }\n\n    private void loadDatabaseLoaders() {\n        addDatabaseLoader(new CopyOldDatabase());\n        addDatabaseLoader(new BackupDatabase(plugin));\n        addDatabaseLoader(new SQLDatabaseLoader(plugin));\n    }\n\n    private void loadPlayers() {\n        Log.info(\"Starting to load players...\");\n\n        DatabaseBridge playersLoader = PlayersDatabaseBridge.getGlobalPlayersBridge();\n\n        DatabaseCache<SuperiorPlayer.Builder> databaseCache = new DatabaseCache<>();\n        AtomicInteger playersCount = new AtomicInteger();\n        long startTime = System.currentTimeMillis();\n\n        PlayersDeserializer.deserializeMissions(playersLoader, databaseCache);\n        PlayersDeserializer.deserializePlayerSettings(playersLoader, databaseCache);\n        PlayersDeserializer.deserializePersistentDataContainer(playersLoader, databaseCache);\n\n        playersLoader.loadAllObjects(\"players\", resultSetRaw -> {\n            DatabaseResult databaseResult = new DatabaseResult(resultSetRaw);\n\n            Optional<UUID> uuid = databaseResult.getUUID(\"uuid\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load player with null uuid, skipping...\");\n                return;\n            }\n\n            if (uuid.get().equals(CONSOLE_UUID)) {\n                Log.warn(\"Cannot load player with uuid 0 (it is reserved to CONSOLE), skipping...\");\n                return;\n            }\n\n            DatabaseCache.Record<SuperiorPlayer.Builder> playerRecord =\n                    databaseCache.computeIfAbsentInfo(uuid.get(), SuperiorPlayer::newBuilder);\n\n            playerRecord.get()\n                    .setUniqueId(uuid.get())\n                    .setName(databaseResult.getString(\"last_used_name\").orElse(\"null\"))\n                    .setDisbands(databaseResult.getInt(\"disbands\").orElse(0))\n                    .setTextureValue(databaseResult.getString(\"last_used_skin\").orElse(\"\"))\n                    .setLastTimeUpdated(databaseResult.getLong(\"last_time_updated\").orElse(System.currentTimeMillis() / 1000));\n\n            checkCorruptedPlayerRecord(playerRecord);\n\n            plugin.getPlayers().getPlayersContainer().addPlayer(playerRecord.get().build());\n\n            playersCount.incrementAndGet();\n        });\n\n        long endTime = System.currentTimeMillis();\n\n        Log.info(\"Finished loading \" + playersCount.get() + \" players (Took \" + (endTime - startTime) + \"ms)\");\n    }\n\n    private void checkCorruptedPlayerRecord(DatabaseCache.Record<SuperiorPlayer.Builder> playerRecord) {\n        if (playerRecord.getRecordedTables().contains(\"players_settings\"))\n            return;\n\n        // We create a temporary SuperiorPlayer for inserting the corrupted record\n        SuperiorPlayer superiorPlayer = playerRecord.get().build();\n\n        Log.warn(\"The player \" + superiorPlayer.getUniqueId() + \" does not have a players_settings record - fixing it...\");\n\n        PlayersDatabaseBridge.insertPlayerSettings(superiorPlayer);\n    }\n\n    private void loadIslands() {\n        Log.info(\"Starting to load islands...\");\n\n        DatabaseBridge islandsLoader = plugin.getFactory().createDatabaseBridge((Island) null);\n\n        DatabaseCache<Island.Builder> databaseCache = new DatabaseCache<>();\n        AtomicInteger islandsCount = new AtomicInteger();\n        long startTime = System.currentTimeMillis();\n\n        IslandsDeserializer.deserializeIslandHomes(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeMembers(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeBanned(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializePlayerPermissions(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeRolePermissions(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeUpgrades(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeWarps(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeBlockLimits(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeRatings(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeMissions(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeIslandFlags(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeGenerators(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeVisitors(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeEntityLimits(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeEffects(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeIslandChest(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeRoleLimits(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeWarpCategories(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeIslandBank(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeVisitorHomes(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeIslandSettings(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializeBankTransactions(islandsLoader, databaseCache);\n        IslandsDeserializer.deserializePersistentDataContainer(islandsLoader, databaseCache);\n\n        islandsLoader.loadAllObjects(\"islands\", resultSetRaw -> {\n            DatabaseResult databaseResult = new DatabaseResult(resultSetRaw);\n\n            Optional<UUID> uuid = databaseResult.getUUID(\"uuid\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island with invalid uuid, skipping...\");\n                return;\n            }\n\n            Optional<UUID> ownerUUID = databaseResult.getUUID(\"owner\");\n            if (!ownerUUID.isPresent()) {\n                Log.warn(\"Cannot load island with invalid owner uuid, skipping...\");\n                return;\n            }\n\n            SuperiorPlayer owner = plugin.getPlayers().getSuperiorPlayer(ownerUUID.get(), false);\n            if (owner == null) {\n                Log.warn(\"Cannot load island with unrecognized owner uuid: \" + ownerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            Optional<Location> center = databaseResult.getString(\"center\").map(Serializers.LOCATION_SERIALIZER::deserialize);\n            if (!center.isPresent()) {\n                Log.warn(\"Cannot load island with invalid center, skipping...\");\n                return;\n            }\n\n            DatabaseCache.Record<Island.Builder> islandRecord =\n                    databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new);\n\n            Island.Builder builder = islandRecord.get()\n                    .setOwner(owner)\n                    .setUniqueId(uuid.get())\n                    .setCenter(center.get())\n                    .setName(databaseResult.getString(\"name\").orElse(\"\"))\n                    .setSchematicName(databaseResult.getString(\"island_type\").orElse(null))\n                    .setCreationTime(databaseResult.getLong(\"creation_time\").orElse(System.currentTimeMillis() / 1000L))\n                    .setDiscord(databaseResult.getString(\"discord\").orElse(\"None\"))\n                    .setPaypal(databaseResult.getString(\"paypal\").orElse(\"None\"))\n                    .setBonusWorth(databaseResult.getBigDecimal(\"worth_bonus\").orElse(BigDecimal.ZERO))\n                    .setBonusLevel(databaseResult.getBigDecimal(\"levels_bonus\").orElse(BigDecimal.ZERO))\n                    .setLocked(databaseResult.getBoolean(\"locked\").orElse(false))\n                    .setIgnored(databaseResult.getBoolean(\"ignored\").orElse(false))\n                    .setDescription(databaseResult.getString(\"description\").orElse(\"\"))\n                    .setLastTimeUpdated(databaseResult.getLong(\"last_time_updated\").orElse(System.currentTimeMillis() / 1000L));\n\n            databaseResult.getString(\"generated_schematics\").ifPresent(generatedSchematics -> {\n                IslandsDeserializer.deserializeDimensionsList(generatedSchematics, builder::setGeneratedSchematic);\n            });\n\n            databaseResult.getString(\"unlocked_worlds\").ifPresent(unlockedWorlds -> {\n                IslandsDeserializer.deserializeDimensionsList(unlockedWorlds, builder::setUnlockedWorld);\n            });\n\n            databaseResult.getString(\"dirty_chunks\").ifPresent(dirtyChunks -> {\n                IslandsDeserializer.deserializeDirtyChunks(builder, dirtyChunks);\n            });\n\n            databaseResult.getString(\"block_counts\").ifPresent(blockCounts -> {\n                IslandsDeserializer.deserializeBlockCounts(builder, blockCounts);\n            });\n\n            databaseResult.getString(\"entity_counts\").ifPresent(entityCounts -> {\n                IslandsDeserializer.deserializeEntityCounts(builder, entityCounts);\n            });\n\n            checkCorruptedIslandRecord(islandRecord);\n\n            plugin.getGrid().getIslandsContainer().addIsland(builder.build());\n\n            islandsCount.incrementAndGet();\n        });\n\n        long endTime = System.currentTimeMillis();\n\n        Log.info(\"Finished loading \" + islandsCount.get() + \" islands (Took \" + (endTime - startTime) + \"ms)\");\n    }\n\n    private void checkCorruptedIslandRecord(DatabaseCache.Record<Island.Builder> islandRecord) {\n        boolean hasIslandsBanks = islandRecord.getRecordedTables().contains(\"islands_banks\");\n        boolean hasIslandsSettings = islandRecord.getRecordedTables().contains(\"islands_settings\");\n\n        if (hasIslandsBanks && hasIslandsSettings)\n            return;\n\n        // We create a temporary Island for inserting the corrupted record\n        Island island = islandRecord.get().build();\n\n        if (!hasIslandsBanks) {\n            Log.warn(\"The island \" + island.getUniqueId() + \" does not have a islands_banks record - fixing it...\");\n            IslandsDatabaseBridge.insertIslandBanks(island);\n        }\n\n        if (!hasIslandsSettings) {\n            Log.warn(\"The island \" + island.getUniqueId() + \" does not have a islands_settings record - fixing it...\");\n            IslandsDatabaseBridge.insertIslandSettings(island);\n        }\n    }\n\n\n    private void loadGrid() {\n        Log.info(\"Starting to load grid...\");\n\n        DatabaseBridge gridLoader = plugin.getFactory().createDatabaseBridge((GridManager) null);\n\n        gridLoader.loadAllObjects(\"grid\",\n                resultSet -> plugin.getGrid().loadGrid(new DatabaseResult(resultSet)));\n\n        Log.info(\"Finished grid!\");\n    }\n\n    private void runState(DatabaseLoader.State state) throws ManagerLoadException {\n        for (DatabaseLoader databaseLoader : databaseLoaders) {\n            databaseLoader.setState(state);\n        }\n    }\n\n    private class CopyOldDatabase implements DatabaseLoader {\n\n        @Override\n        public void setState(State state) throws ManagerLoadException {\n            if (state == State.INITIALIZE) {\n                File oldDataFile = new File(plugin.getDataFolder(), \"database.db\");\n                if (oldDataFile.exists()) {\n                    File newDataFile = new File(plugin.getDataFolder(), \"datastore/database.db\");\n                    newDataFile.getParentFile().mkdirs();\n                    if (!oldDataFile.renameTo(newDataFile))\n                        throw new ManagerLoadException(\"Failed to move old database file\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n                }\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/DatabaseResult.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\n\nimport java.math.BigDecimal;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic class DatabaseResult {\n\n    private final Map<String, Object> resultSet;\n\n    public DatabaseResult(Map<String, Object> resultSet) {\n        this.resultSet = resultSet;\n    }\n\n    public Optional<String> getString(String key) {\n        return getObject(key, String.class);\n    }\n\n    public Optional<Integer> getInt(String key) {\n        return getObject(key, Integer.class);\n    }\n\n    public Optional<Long> getLong(String key) {\n        Object value = getObject(key);\n\n        if (value != null) {\n            if (value instanceof Long) {\n                return Optional.of((long) value);\n            } else if (value instanceof Integer) {\n                return Optional.of((long) (int) value);\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    public Optional<Double> getDouble(String key) {\n        Object value = getObject(key);\n\n        if (value != null) {\n            if (value instanceof Double) {\n                return Optional.of((double) value);\n            } else if (value instanceof Long) {\n                return Optional.of((double) (long) value);\n            } else if (value instanceof Integer) {\n                return Optional.of((double) (int) value);\n            } else if (value instanceof BigDecimal) {\n                return Optional.of(((BigDecimal) value).doubleValue());\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    public Optional<Boolean> getBoolean(String key) {\n        Object value = getObject(key);\n\n        if (value != null) {\n            if (value instanceof Integer) {\n                return Optional.of((int) value == 1);\n            } else if (value instanceof Boolean) {\n                return Optional.of((boolean) value);\n            } else if (value instanceof Byte) {\n                return Optional.of((byte) value == 1);\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    public Optional<Byte> getByte(String key) {\n        Object value = getObject(key);\n\n        if (value != null) {\n            if (value instanceof Byte) {\n                return Optional.of((byte) value);\n            } else if (value instanceof Boolean) {\n                return Optional.of((Boolean) value ? (byte) 1 : 0);\n            } else if (value instanceof Integer) {\n                return Optional.of((byte) (int) value);\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    public Optional<BigDecimal> getBigDecimal(String key) {\n        Optional<String> value = getString(key);\n        try {\n            return value.map(BigDecimal::new);\n        } catch (NumberFormatException | NullPointerException ex) {\n            return Optional.empty();\n        }\n    }\n\n    public Optional<UUID> getUUID(String key) {\n        Optional<String> value = getString(key);\n\n        if (!value.isPresent())\n            return Optional.empty();\n\n        try {\n            return Optional.of(UUID.fromString(value.get()));\n        } catch (IllegalArgumentException error) {\n            return Optional.empty();\n        }\n    }\n\n    public <T extends Enum<T>> Optional<T> getEnum(String key, Class<T> enumType) {\n        return getString(key).map(s -> EnumHelper.getEnum(enumType, s));\n\n    }\n\n    public Optional<byte[]> getBlob(String key) {\n        Object obj = getObject(key);\n\n        if (obj instanceof String) {\n            return Optional.of(((String) obj).getBytes());\n        } else if (obj instanceof byte[]) {\n            return Optional.of((byte[]) obj);\n        }\n\n        return Optional.empty();\n    }\n\n    private <T> Optional<T> getObject(String key, Class<T> clazz) {\n        Object value = getObject(key);\n        return Optional.ofNullable(value == null || !value.getClass().isAssignableFrom(clazz) ? null : clazz.cast(value));\n    }\n\n    @Nullable\n    private Object getObject(String key) {\n        return resultSet.get(key);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/EmptyDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.bridge;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic class EmptyDatabaseBridge implements DatabaseBridge {\n\n    private static final EmptyDatabaseBridge instance = new EmptyDatabaseBridge();\n\n    private EmptyDatabaseBridge() {\n\n    }\n\n    public static EmptyDatabaseBridge getInstance() {\n        return instance;\n    }\n\n    @Override\n    public void loadAllObjects(String table, Consumer<Map<String, Object>> resultConsumer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void batchOperations(boolean batchOperations) {\n        // Do nothing.\n    }\n\n    @Override\n    public void updateObject(String table, @Nullable DatabaseFilter filter, Pair<String, Object>... columns) {\n        // Do nothing.\n    }\n\n    @Override\n    public void insertObject(String table, Pair<String, Object>... columns) {\n        // Do nothing.\n    }\n\n    @Override\n    public void deleteObject(String table, @Nullable DatabaseFilter filter) {\n        // Do nothing.\n    }\n\n    @Override\n    public void loadObject(String table, @Nullable DatabaseFilter filter, Consumer<Map<String, Object>> resultConsumer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode) {\n        // Do nothing.\n    }\n\n    @Override\n    public DatabaseBridgeMode getDatabaseBridgeMode() {\n        return DatabaseBridgeMode.IDLE;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.bridge;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.DBColumn;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\n\nimport java.util.function.Consumer;\n\npublic class GridDatabaseBridge {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private GridDatabaseBridge() {\n    }\n\n    public static void saveLastIsland(GridManager gridManager, BlockPosition lastIsland) {\n        runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(\"last_island\", Serializers.BLOCK_POSITION_SERIALIZER.serialize(lastIsland));\n                databaseBridge.updateObject(\"grid\", null, column);\n            }\n        });\n    }\n\n    public static void updateVersion(GridManager gridManager, int version) {\n        runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> {\n            databaseBridge.deleteObject(\"ssb_metadata\", null);\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(\"version\", version);\n                databaseBridge.insertObject(\"ssb_metadata\", column);\n            }\n        });\n    }\n\n    public static void insertGrid(GridManager gridManager) {\n        runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"grid\",\n                        pool.obtain().withNameAndValue(\"last_island\", Serializers.BLOCK_POSITION_SERIALIZER.serialize(gridManager.getLastIslandPosition())),\n                        pool.obtain().withNameAndValue(\"max_island_size\", plugin.getSettings().getMaxIslandSize()),\n                        pool.obtain().withNameAndValue(\"world\", plugin.getSettings().getWorlds().getDefaultWorldName())\n                );\n            }\n        });\n    }\n\n    public static void deleteGrid(GridManager gridManager) {\n        runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"grid\", null));\n    }\n\n    private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer<DatabaseBridge> databaseBridgeConsumer) {\n        if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA)\n            databaseBridgeConsumer.accept(databaseBridge);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.bridge;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.DBColumn;\nimport com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.island.IslandNames;\nimport com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\n\npublic class IslandsDatabaseBridge {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Map<UUID, Map<FutureSave, Set<Object>>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>();\n\n    private IslandsDatabaseBridge() {\n    }\n\n    public static void addMember(Island island, SuperiorPlayer superiorPlayer, long addTime) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_members\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"role\", superiorPlayer.getPlayerRole().getId()),\n                        pool.obtain().withNameAndValue(\"join_time\", addTime)\n                );\n            }\n        });\n    }\n\n    public static void removeMember(Island island, SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.deleteObject(\"islands_members\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString())));\n            }\n        });\n    }\n\n    public static void saveMemberRole(Island island, SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_members\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString())),\n                        pool.obtain().withNameAndValue(\"role\", superiorPlayer.getPlayerRole().getId())\n                );\n            }\n        });\n    }\n\n    public static void addBannedPlayer(Island island, SuperiorPlayer superiorPlayer, UUID banner, long banTime) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_bans\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"banned_by\", banner.toString()),\n                        pool.obtain().withNameAndValue(\"banned_time\", banTime)\n                );\n            }\n        });\n    }\n\n    public static void removeBannedPlayer(Island island, SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString());\n                databaseBridge.deleteObject(\"islands_bans\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveCoopLimit(Island island) {\n        updateIslandSettingsValue(island, \"coops_limit\", island.getCoopLimit());\n    }\n\n    public static void saveIslandHome(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) {\n        if (worldPosition == null) {\n            runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n                try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                    DBColumn column = pool.obtain().withNameAndValue(\"environment\", dimension.getName());\n                    databaseBridge.deleteObject(\"islands_homes\", createFilter(pool, \"island\", island, column));\n                }\n            });\n        } else {\n            runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n                try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                    databaseBridge.insertObject(\"islands_homes\",\n                            pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                            pool.obtain().withNameAndValue(\"environment\", dimension.getName()),\n                            pool.obtain().withNameAndValue(\"location\", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition))\n                    );\n                }\n            });\n        }\n    }\n\n    public static void saveVisitorLocation(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) {\n        if (worldPosition == null) {\n            runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n                try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                    DBColumn column = pool.obtain().withNameAndValue(\"environment\", dimension.getName());\n                    databaseBridge.deleteObject(\"islands_visitor_homes\", createFilter(pool, \"island\", island, column));\n                }\n            });\n        } else {\n            runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n                try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                    databaseBridge.insertObject(\"islands_visitor_homes\",\n                            pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                            pool.obtain().withNameAndValue(\"environment\", dimension.getName()),\n                            pool.obtain().withNameAndValue(\"location\", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition))\n                    );\n                }\n            });\n        }\n    }\n\n    public static void saveUnlockedWorlds(Island island) {\n        updateIslandValue(island, \"unlocked_worlds\",\n                IslandsSerializer.serializeDimensions(island.getUnlockedWorlds()));\n    }\n\n    public static void savePlayerPermission(Island island, SuperiorPlayer superiorPlayer, IslandPrivilege privilege,\n                                            boolean status) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_player_permissions\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"permission\", privilege.getName()),\n                        pool.obtain().withNameAndValue(\"status\", status)\n                );\n            }\n        });\n    }\n\n    public static void clearPlayerPermission(Island island, SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString());\n                databaseBridge.deleteObject(\"islands_player_permissions\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveRolePermission(Island island, PlayerRole playerRole, IslandPrivilege privilege) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_role_permissions\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"role\", playerRole.getId()),\n                        pool.obtain().withNameAndValue(\"permission\", privilege.getName())\n                );\n            }\n        });\n    }\n\n    public static void clearRolePermissions(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_role_permissions\", createFilter(\"island\", island)));\n    }\n\n    public static void saveName(Island island) {\n        updateIslandValue(island, \"name\", IslandNames.getNameForDatabase(island));\n    }\n\n    public static void saveDescription(Island island) {\n        updateIslandValue(island, \"description\", island.getDescription());\n    }\n\n    public static void saveSize(Island island) {\n        updateIslandSettingsValue(island, \"size\", island.getIslandSize());\n    }\n\n    public static void saveDiscord(Island island) {\n        updateIslandValue(island, \"discord\", island.getDiscord());\n    }\n\n    public static void savePaypal(Island island) {\n        updateIslandValue(island, \"paypal\", island.getPaypal());\n    }\n\n    public static void saveLockedStatus(Island island) {\n        updateIslandValue(island, \"locked\", island.isLocked());\n    }\n\n    public static void saveIgnoredStatus(Island island) {\n        updateIslandValue(island, \"ignored\", island.isIgnored());\n    }\n\n    public static void saveLastTimeUpdate(Island island) {\n        updateIslandValue(island, \"last_time_updated\", island.getLastTimeUpdate());\n    }\n\n    public static void saveBankLimit(Island island) {\n        updateIslandSettingsValue(island, \"bank_limit\", island.getBankLimit() + \"\");\n    }\n\n    public static void saveBonusWorth(Island island) {\n        updateIslandValue(island, \"worth_bonus\", island.getBonusWorth() + \"\");\n    }\n\n    public static void saveBonusLevel(Island island) {\n        updateIslandValue(island, \"levels_bonus\", island.getBonusLevel() + \"\");\n    }\n\n    public static void saveUpgrade(Island island, Upgrade upgrade, int level) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_upgrades\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"upgrade\", upgrade.getName()),\n                        pool.obtain().withNameAndValue(\"level\", level)\n                );\n            }\n        });\n    }\n\n    public static void saveCropGrowth(Island island) {\n        updateIslandSettingsValue(island, \"crop_growth_multiplier\", island.getCropGrowthMultiplier());\n    }\n\n    public static void saveSpawnerRates(Island island) {\n        updateIslandSettingsValue(island, \"spawner_rates_multiplier\", island.getSpawnerRatesMultiplier());\n    }\n\n    public static void saveMobDrops(Island island) {\n        updateIslandSettingsValue(island, \"mob_drops_multiplier\", island.getMobDropsMultiplier());\n    }\n\n    public static void saveBlockLimit(Island island, Key block, int limit) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_block_limits\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"block\", block.toString()),\n                        pool.obtain().withNameAndValue(\"limit\", limit)\n                );\n            }\n        });\n    }\n\n    public static void clearBlockLimits(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_block_limits\", createFilter(\"island\", island)));\n    }\n\n    public static void removeBlockLimit(Island island, Key block) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"block\", block.toString());\n                databaseBridge.deleteObject(\"islands_block_limits\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveEntityLimit(Island island, Key entityType, int limit) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_entity_limits\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"entity\", entityType.toString()),\n                        pool.obtain().withNameAndValue(\"limit\", limit)\n                );\n            }\n        });\n    }\n\n    public static void clearEntityLimits(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_entity_limits\", createFilter(\"island\", island)));\n    }\n\n    public static void removeEntityLimit(Island island, Key entity) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"entity\", entity.toString());\n                databaseBridge.deleteObject(\"islands_entity_limits\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveTeamLimit(Island island) {\n        updateIslandSettingsValue(island, \"members_limit\", island.getTeamLimit());\n    }\n\n    public static void saveWarpsLimit(Island island) {\n        updateIslandSettingsValue(island, \"warps_limit\", island.getWarpsLimit());\n    }\n\n    public static void saveIslandEffect(Island island, PotionEffectType potionEffectType, int level) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_effects\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"effect_type\", potionEffectType.getName()),\n                        pool.obtain().withNameAndValue(\"level\", level)\n                );\n            }\n        });\n    }\n\n    public static void removeIslandEffect(Island island, PotionEffectType potionEffectType) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"effect_type\", potionEffectType.getName());\n                databaseBridge.deleteObject(\"islands_effects\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void clearIslandEffects(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_effects\", createFilter(\"island\", island)));\n    }\n\n    public static void saveRoleLimit(Island island, PlayerRole playerRole, int limit) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_role_limits\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"role\", playerRole.getId()),\n                        pool.obtain().withNameAndValue(\"limit\", limit)\n                );\n            }\n        });\n    }\n\n    public static void removeRoleLimit(Island island, PlayerRole playerRole) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"role\", playerRole.getId());\n                databaseBridge.deleteObject(\"islands_role_limits\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveWarp(Island island, IslandWarp islandWarp) {\n        WarpCategory category = islandWarp.getCategory();\n        ItemStack icon = islandWarp.getRawIcon();\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain();\n                 ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n                databaseBridge.insertObject(\"islands_warps\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"name\", islandWarp.getName()),\n                        pool.obtain().withNameAndValue(\"category\", category == null ? \"\" : category.getName()),\n                        pool.obtain().withNameAndValue(\"location\", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))),\n                        pool.obtain().withNameAndValue(\"private\", islandWarp.hasPrivateFlag()),\n                        pool.obtain().withNameAndValue(\"icon\", Serializers.ITEM_STACK_SERIALIZER.serialize(icon))\n                );\n            }\n        });\n    }\n\n    public static void updateWarpName(Island island, IslandWarp islandWarp, String oldName) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warps\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", oldName)),\n                        pool.obtain().withNameAndValue(\"name\", islandWarp.getName())\n                );\n            }\n        });\n    }\n\n    public static void updateWarpLocation(Island island, IslandWarp islandWarp) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain();\n                 ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n                String islandWarpLocation = Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()));\n                databaseBridge.updateObject(\"islands_warps\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", islandWarp.getName())),\n                        pool.obtain().withNameAndValue(\"location\", islandWarpLocation)\n                );\n            }\n        });\n    }\n\n    public static void updateWarpPrivateStatus(Island island, IslandWarp islandWarp) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warps\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", islandWarp.getName())),\n                        pool.obtain().withNameAndValue(\"private\", islandWarp.hasPrivateFlag())\n                );\n            }\n        });\n    }\n\n    public static void updateWarpIcon(Island island, IslandWarp islandWarp) {\n\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            ItemStack icon = islandWarp.getRawIcon();\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warps\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", islandWarp.getName())),\n                        pool.obtain().withNameAndValue(\"icon\", Serializers.ITEM_STACK_SERIALIZER.serialize(icon))\n                );\n            }\n        });\n    }\n\n    public static void removeWarp(Island island, IslandWarp islandWarp) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"name\", islandWarp.getName());\n                databaseBridge.deleteObject(\"islands_warps\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveRating(Island island, SuperiorPlayer superiorPlayer, Rating rating, long rateTime) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_ratings\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"rating\", rating.getValue()),\n                        pool.obtain().withNameAndValue(\"rating_time\", rateTime)\n                );\n            }\n        });\n    }\n\n    public static void removeRating(Island island, SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString());\n                databaseBridge.deleteObject(\"islands_ratings\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void clearRatings(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_ratings\", createFilter(\"island\", island)));\n    }\n\n    public static void saveMission(Island island, Mission<?> mission, int finishCount) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_missions\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"name\", mission.getName().toLowerCase(Locale.ENGLISH)),\n                        pool.obtain().withNameAndValue(\"finish_count\", finishCount)\n                );\n            }\n        });\n    }\n\n    public static void removeMission(Island island, Mission<?> mission) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"name\", mission.getName());\n                databaseBridge.deleteObject(\"islands_missions\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveIslandFlag(Island island, IslandFlag islandFlag, int status) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_flags\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"name\", islandFlag.getName()),\n                        pool.obtain().withNameAndValue(\"status\", status)\n                );\n            }\n        });\n    }\n\n    public static void removeIslandFlag(Island island, IslandFlag islandFlag) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"name\", islandFlag.getName());\n                databaseBridge.deleteObject(\"islands_flags\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void clearIslandFlags(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_flags\", createFilter(\"island\", island)));\n    }\n\n    public static void saveGeneratorRate(Island island, Dimension dimension, Key blockKey, int rate) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_generators\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"environment\", dimension.getName()),\n                        pool.obtain().withNameAndValue(\"block\", blockKey.toString()),\n                        pool.obtain().withNameAndValue(\"rate\", rate)\n                );\n            }\n        });\n    }\n\n    public static void removeGeneratorRate(Island island, Dimension dimension, Key blockKey) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.deleteObject(\"islands_generators\", createFilter(pool, \"island\", island,\n                        pool.obtain().withNameAndValue(\"environment\", dimension.getName()),\n                        pool.obtain().withNameAndValue(\"block\", blockKey.toString()))\n                );\n            }\n        });\n    }\n\n    public static void clearGeneratorRates(Island island, Dimension dimension) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"environment\", dimension.getName());\n                databaseBridge.deleteObject(\"islands_generators\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveGeneratedSchematics(Island island) {\n        updateIslandValue(island, \"generated_schematics\",\n                IslandsSerializer.serializeDimensions(island.getGeneratedSchematics()));\n    }\n\n    public static void saveDirtyChunks(DirtyChunksContainer dirtyChunksContainer) {\n        updateIslandValue(dirtyChunksContainer.getIsland(), \"dirty_chunks\",\n                IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer));\n    }\n\n    public static void saveBlockCounts(Island island) {\n        updateIslandValue(island, \"block_counts\",\n                IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger()));\n    }\n\n    public static void saveEntityCounts(Island island) {\n        updateIslandValue(island, \"entity_counts\",\n                IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts()));\n    }\n\n    public static void saveIslandChest(Island island, IslandChest islandChest) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_chests\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"index\", islandChest.getIndex()),\n                        pool.obtain().withNameAndValue(\"contents\", Serializers.INVENTORY_SERIALIZER.serialize(islandChest.getContents()))\n                );\n            }\n        });\n    }\n\n    public static void saveLastInterestTime(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(\"last_interest_time\", island.getLastInterestTime() * 1000);\n                databaseBridge.updateObject(\"islands_banks\", createFilter(\"island\", island), column);\n            }\n        });\n    }\n\n    public static void saveVisitor(Island island, SuperiorPlayer visitor, long visitTime) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_visitors\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", visitor.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"visit_time\", visitTime)\n                );\n            }\n        });\n    }\n\n    public static void saveWarpCategory(Island island, WarpCategory warpCategory) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_warp_categories\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"name\", warpCategory.getName()),\n                        pool.obtain().withNameAndValue(\"slot\", warpCategory.getSlot()),\n                        pool.obtain().withNameAndValue(\"icon\", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon()))\n                );\n            }\n        });\n    }\n\n    public static void updateWarpCategory(Island island, IslandWarp islandWarp, String oldCategoryName) {\n        WarpCategory category = islandWarp.getCategory();\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warps\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"category\", oldCategoryName)),\n                        pool.obtain().withNameAndValue(\"category\", category == null ? \"\" : category.getName())\n                );\n            }\n        });\n    }\n\n    public static void updateWarpCategoryName(Island island, WarpCategory warpCategory, String oldName) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warp_categories\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", oldName)),\n                        pool.obtain().withNameAndValue(\"name\", warpCategory.getName())\n                );\n            }\n        });\n    }\n\n    public static void updateWarpCategorySlot(Island island, WarpCategory warpCategory) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warp_categories\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", warpCategory.getName())),\n                        pool.obtain().withNameAndValue(\"slot\", warpCategory.getSlot())\n                );\n            }\n        });\n    }\n\n    public static void updateWarpCategoryIcon(Island island, WarpCategory warpCategory) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_warp_categories\",\n                        createFilter(pool, \"island\", island, pool.obtain().withNameAndValue(\"name\", warpCategory.getName())),\n                        pool.obtain().withNameAndValue(\"icon\", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon()))\n                );\n            }\n        });\n    }\n\n    public static void removeWarpCategory(Island island, WarpCategory warpCategory) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"name\", warpCategory.getName());\n                databaseBridge.deleteObject(\"islands_warp_categories\", createFilter(pool, \"island\", island, column));\n            }\n        });\n    }\n\n    public static void saveIslandLeader(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(\"owner\", island.getOwner().getUniqueId().toString());\n                databaseBridge.updateObject(\"islands\", createFilter(\"uuid\", island), column);\n            }\n        });\n    }\n\n    public static void saveBankBalance(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(\"balance\", island.getIslandBank().getBalance() + \"\");\n                databaseBridge.updateObject(\"islands_banks\", createFilter(\"island\", island), column);\n            }\n        });\n    }\n\n    public static void saveBankTransaction(Island island, BankTransaction bankTransaction) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"bank_transactions\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"player\", bankTransaction.getPlayer() == null ? \"\" : bankTransaction.getPlayer().toString()),\n                        pool.obtain().withNameAndValue(\"bank_action\", bankTransaction.getAction().name()),\n                        pool.obtain().withNameAndValue(\"position\", bankTransaction.getPosition()),\n                        pool.obtain().withNameAndValue(\"time\", bankTransaction.getTime()),\n                        pool.obtain().withNameAndValue(\"failure_reason\", bankTransaction.getFailureReason()),\n                        pool.obtain().withNameAndValue(\"amount\", bankTransaction.getAmount() + \"\")\n                );\n            }\n        });\n    }\n\n    public static void savePersistentDataContainer(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_custom_data\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"data\", island.getPersistentDataContainer().serialize())\n                );\n            }\n        });\n    }\n\n    public static void removePersistentDataContainer(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"islands_custom_data\", createFilter(\"island\", island)));\n    }\n\n    public static void clearIslandSettings(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.updateObject(\"islands_settings\",\n                        createFilter(\"island\", island),\n                        pool.obtain().withNameAndValue(\"size\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"bank_limit\", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString()),\n                        pool.obtain().withNameAndValue(\"coops_limit\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"members_limit\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"warps_limit\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"crop_growth_multiplier\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"spawner_rates_multiplier\", IslandUpgradeConstants.SYNCED_VALUE),\n                        pool.obtain().withNameAndValue(\"mob_drops_multiplier\", IslandUpgradeConstants.SYNCED_VALUE)\n                );\n            }\n        });\n    }\n\n    public static void insertIsland(Island island, @Nullable List<ChunkPosition> dirtyChunks) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            BlockPosition centerPosition = island.getCenterPosition();\n            WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension());\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands\",\n                        pool.obtain().withNameAndValue(\"uuid\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"owner\", island.getOwner().getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"center\", Serializers.LOCATION_SERIALIZER.serialize(LazyWorldLocation.of(worldInfo, centerPosition))),\n                        pool.obtain().withNameAndValue(\"creation_time\", island.getCreationTime()),\n                        pool.obtain().withNameAndValue(\"island_type\", island.getSchematicName()),\n                        pool.obtain().withNameAndValue(\"discord\", island.getDiscord()),\n                        pool.obtain().withNameAndValue(\"paypal\", island.getPaypal()),\n                        pool.obtain().withNameAndValue(\"worth_bonus\", island.getBonusWorth() + \"\"),\n                        pool.obtain().withNameAndValue(\"levels_bonus\", island.getBonusLevel() + \"\"),\n                        pool.obtain().withNameAndValue(\"locked\", island.isLocked()),\n                        pool.obtain().withNameAndValue(\"ignored\", island.isIgnored()),\n                        pool.obtain().withNameAndValue(\"name\", IslandNames.getNameForDatabase(island)),\n                        pool.obtain().withNameAndValue(\"description\", island.getDescription()),\n                        pool.obtain().withNameAndValue(\"generated_schematics\", IslandsSerializer.serializeDimensions(island.getGeneratedSchematics())),\n                        pool.obtain().withNameAndValue(\"unlocked_worlds\", IslandsSerializer.serializeDimensions(island.getUnlockedWorlds())),\n                        pool.obtain().withNameAndValue(\"last_time_updated\", System.currentTimeMillis() / 1000L),\n                        pool.obtain().withNameAndValue(\"dirty_chunks\", dirtyChunks == null ? \"\" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)),\n                        pool.obtain().withNameAndValue(\"block_counts\", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())),\n                        pool.obtain().withNameAndValue(\"entity_counts\", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts()))\n                );\n            }\n        });\n\n        insertIslandBanks(island);\n        insertIslandSettings(island);\n    }\n\n    public static void insertIslandBanks(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_banks\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"balance\", island.getIslandBank().getBalance() + \"\"),\n                        pool.obtain().withNameAndValue(\"last_interest_time\", island.getLastInterestTime())\n                );\n            }\n        });\n    }\n\n    public static void insertIslandSettings(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"islands_settings\",\n                        pool.obtain().withNameAndValue(\"island\", island.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"size\", island.getIslandSizeRaw()),\n                        pool.obtain().withNameAndValue(\"bank_limit\", island.getBankLimitRaw() + \"\"),\n                        pool.obtain().withNameAndValue(\"coops_limit\", island.getCoopLimitRaw()),\n                        pool.obtain().withNameAndValue(\"members_limit\", island.getTeamLimitRaw()),\n                        pool.obtain().withNameAndValue(\"warps_limit\", island.getWarpsLimitRaw()),\n                        pool.obtain().withNameAndValue(\"crop_growth_multiplier\", island.getCropGrowthRaw()),\n                        pool.obtain().withNameAndValue(\"spawner_rates_multiplier\", island.getSpawnerRatesRaw()),\n                        pool.obtain().withNameAndValue(\"mob_drops_multiplier\", island.getMobDropsRaw())\n                );\n            }\n        });\n    }\n\n    public static void deleteIsland(Island island) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            DatabaseFilter islandFilter = createFilter(\"island\", island);\n\n            databaseBridge.deleteObject(\"islands\", createFilter(\"uuid\", island));\n            databaseBridge.deleteObject(\"islands_banks\", islandFilter);\n            databaseBridge.deleteObject(\"islands_settings\", islandFilter);\n            databaseBridge.deleteObject(\"bank_transactions\", islandFilter);\n\n\n            if (!island.getBannedPlayers().isEmpty())\n                databaseBridge.deleteObject(\"islands_bans\", islandFilter);\n            if (!island.getBlocksLimits().isEmpty())\n                databaseBridge.deleteObject(\"islands_block_limits\", islandFilter);\n            if (!island.isPersistentDataContainerEmpty())\n                databaseBridge.deleteObject(\"islands_custom_data\", islandFilter);\n            if (island.getChest().length > 0)\n                databaseBridge.deleteObject(\"islands_chests\", islandFilter);\n            if (!island.getPotionEffects().isEmpty())\n                databaseBridge.deleteObject(\"islands_effects\", islandFilter);\n            if (!island.getEntitiesLimitsAsKeys().isEmpty())\n                databaseBridge.deleteObject(\"islands_entity_limits\", islandFilter);\n            if (!island.getAllSettings().isEmpty())\n                databaseBridge.deleteObject(\"islands_flags\", islandFilter);\n            for (Dimension dimension : Dimension.values()) {\n                if (!island.getCustomGeneratorAmounts(dimension).isEmpty()) {\n                    databaseBridge.deleteObject(\"islands_generators\", islandFilter);\n                    break;\n                }\n            }\n            if (!island.getIslandHomes().isEmpty())\n                databaseBridge.deleteObject(\"islands_homes\", islandFilter);\n            if (!island.getIslandMembers(false).isEmpty())\n                databaseBridge.deleteObject(\"islands_members\", islandFilter);\n            if (!island.getCompletedMissions().isEmpty())\n                databaseBridge.deleteObject(\"islands_missions\", islandFilter);\n            if (!island.getPlayerPermissions().isEmpty())\n                databaseBridge.deleteObject(\"islands_player_permissions\", islandFilter);\n            if (!island.getRatings().isEmpty())\n                databaseBridge.deleteObject(\"islands_ratings\", islandFilter);\n            if (!island.getCustomRoleLimits().isEmpty())\n                databaseBridge.deleteObject(\"islands_role_limits\", islandFilter);\n            if (!island.getRolePermissions().isEmpty())\n                databaseBridge.deleteObject(\"islands_role_permissions\", islandFilter);\n            if (!island.getUpgrades().isEmpty())\n                databaseBridge.deleteObject(\"islands_upgrades\", islandFilter);\n            for (Dimension dimension : Dimension.values()) {\n                if (island.getVisitorsPosition(dimension) != null) {\n                    databaseBridge.deleteObject(\"islands_visitor_homes\", islandFilter);\n                    break;\n                }\n            }\n            if (!island.getUniqueVisitors().isEmpty())\n                databaseBridge.deleteObject(\"islands_visitors\", islandFilter);\n            if (!island.getWarpCategories().isEmpty()) {\n                databaseBridge.deleteObject(\"islands_warp_categories\", islandFilter);\n                databaseBridge.deleteObject(\"islands_warps\", islandFilter);\n            }\n        });\n    }\n\n    public static void markIslandChestsToBeSaved(Island island, IslandChest islandChest) {\n        SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class))\n                .computeIfAbsent(FutureSave.ISLAND_CHESTS, e -> new HashSet<>())\n                .add(islandChest);\n    }\n\n    public static void markBlockCountsToBeSaved(Island island) {\n        Set<Object> varsForBlockCounts = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class))\n                .computeIfAbsent(FutureSave.BLOCK_COUNTS, e -> new HashSet<>());\n        if (varsForBlockCounts.isEmpty())\n            varsForBlockCounts.add(new Object());\n    }\n\n    public static void markPersistentDataContainerToBeSaved(Island island) {\n        Set<Object> varsForPersistentData = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class))\n                .computeIfAbsent(FutureSave.PERSISTENT_DATA, e -> new HashSet<>());\n        if (varsForPersistentData.isEmpty())\n            varsForPersistentData.add(new Object());\n    }\n\n    public static boolean isModified(Island island) {\n        return SAVE_METHODS_TO_BE_EXECUTED.containsKey(island.getUniqueId());\n    }\n\n    public static void executeFutureSaves(Island island) {\n        Map<FutureSave, Set<Object>> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.remove(island.getUniqueId());\n        if (futureSaves != null) {\n            for (Map.Entry<FutureSave, Set<Object>> futureSaveEntry : futureSaves.entrySet()) {\n                switch (futureSaveEntry.getKey()) {\n                    case BLOCK_COUNTS:\n                        saveBlockCounts(island);\n                        break;\n                    case ISLAND_CHESTS:\n                        for (Object islandChest : futureSaveEntry.getValue())\n                            saveIslandChest(island, (IslandChest) islandChest);\n                        break;\n                    case PERSISTENT_DATA:\n                        savePersistentDataContainer(island);\n                        break;\n                }\n            }\n        }\n    }\n\n    public static void executeFutureSaves(Island island, FutureSave futureSave) {\n        Map<FutureSave, Set<Object>> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.get(island.getUniqueId());\n\n        if (futureSaves == null)\n            return;\n\n        Set<Object> values = futureSaves.remove(futureSave);\n\n        if (values == null)\n            return;\n\n        if (futureSaves.isEmpty())\n            SAVE_METHODS_TO_BE_EXECUTED.remove(island.getUniqueId());\n\n        switch (futureSave) {\n            case BLOCK_COUNTS:\n                saveBlockCounts(island);\n                break;\n            case ISLAND_CHESTS:\n                for (Object islandChest : values)\n                    saveIslandChest(island, (IslandChest) islandChest);\n                break;\n            case PERSISTENT_DATA: {\n                if (island.isPersistentDataContainerEmpty())\n                    removePersistentDataContainer(island);\n                else\n                    savePersistentDataContainer(island);\n                break;\n            }\n        }\n    }\n\n    private static void updateIslandValue(Island island, String columnName, Object value) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value);\n                databaseBridge.updateObject(\"islands\", createFilter(\"uuid\", island), column);\n            }\n        });\n    }\n\n    private static void updateIslandSettingsValue(Island island, String columnName, Object value) {\n        runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value);\n                databaseBridge.updateObject(\"islands_settings\", createFilter(\"island\", island), column);\n            }\n        });\n    }\n\n    private static DatabaseFilter createFilter(String id, Island island) {\n        return DatabaseFilter.fromFilter(id, island.getUniqueId().toString());\n    }\n\n    private static DatabaseFilter createFilter(ObjectsPools.Batch<DBColumn> pool, String id, Island island, DBColumn column) {\n        List<Pair<String, Object>> filters = new LinkedList<>();\n        filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString()));\n        filters.add(column);\n        return DatabaseFilter.fromFilters(filters);\n    }\n\n    private static DatabaseFilter createFilter(ObjectsPools.Batch<DBColumn> pool, String id, Island island, DBColumn... others) {\n        List<Pair<String, Object>> filters = new LinkedList<>();\n        filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString()));\n        if (others != null && others.length > 0)\n            Collections.addAll(filters, others);\n        return DatabaseFilter.fromFilters(filters);\n    }\n\n    private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer<DatabaseBridge> databaseBridgeConsumer) {\n        if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA)\n            databaseBridgeConsumer.accept(databaseBridge);\n    }\n\n    public enum FutureSave {\n\n        BLOCK_COUNTS,\n        ISLAND_CHESTS,\n        PERSISTENT_DATA\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.bridge;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.DBColumn;\n\nimport java.util.EnumMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\n\npublic class PlayersDatabaseBridge {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final Map<UUID, Map<FutureSave, Set<Object>>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>();\n    private static final LazyReference<DatabaseBridge> GLOBAL_PLAYERS_BRIDGE = new LazyReference<DatabaseBridge>() {\n        @Override\n        protected DatabaseBridge create() {\n            DatabaseBridge databaseBridge = plugin.getFactory().createDatabaseBridge((SuperiorPlayer) null);\n            databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n            return databaseBridge;\n        }\n    };\n\n    private PlayersDatabaseBridge() {\n    }\n\n    public static DatabaseBridge getGlobalPlayersBridge() {\n        return GLOBAL_PLAYERS_BRIDGE.get();\n    }\n\n    public static void saveTextureValue(SuperiorPlayer superiorPlayer) {\n        updatePlayerValue(superiorPlayer, \"last_used_skin\", superiorPlayer.getTextureValue());\n    }\n\n    public static void savePlayerName(SuperiorPlayer superiorPlayer) {\n        updatePlayerValue(superiorPlayer, \"last_used_name\", superiorPlayer.getName());\n    }\n\n    public static void saveUserLocale(SuperiorPlayer superiorPlayer) {\n        Locale userLocale = superiorPlayer.getUserLocale();\n        updatePlayerSettingsValue(superiorPlayer, \"language\", userLocale.getLanguage() + \"-\" + userLocale.getCountry());\n    }\n\n    public static void saveToggledBorder(SuperiorPlayer superiorPlayer) {\n        updatePlayerSettingsValue(superiorPlayer, \"toggled_border\", superiorPlayer.hasWorldBorderEnabled());\n    }\n\n    public static void saveDisbands(SuperiorPlayer superiorPlayer) {\n        updatePlayerValue(superiorPlayer, \"disbands\", superiorPlayer.getDisbands());\n    }\n\n    public static void saveToggledPanel(SuperiorPlayer superiorPlayer) {\n        updatePlayerSettingsValue(superiorPlayer, \"toggled_panel\", superiorPlayer.hasToggledPanel());\n    }\n\n    public static void saveIslandFly(SuperiorPlayer superiorPlayer) {\n        updatePlayerSettingsValue(superiorPlayer, \"island_fly\", superiorPlayer.hasIslandFlyEnabled());\n    }\n\n    public static void saveBorderColor(SuperiorPlayer superiorPlayer) {\n        updatePlayerSettingsValue(superiorPlayer, \"border_color\", superiorPlayer.getBorderColor().name());\n    }\n\n    public static void saveLastTimeStatus(SuperiorPlayer superiorPlayer) {\n        updatePlayerValue(superiorPlayer, \"last_time_updated\", superiorPlayer.getLastTimeStatus());\n    }\n\n    public static void saveMission(SuperiorPlayer superiorPlayer, Mission<?> mission, int finishCount) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"players_missions\",\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"name\", mission.getName().toLowerCase(Locale.ENGLISH)),\n                        pool.obtain().withNameAndValue(\"finish_count\", finishCount)\n                );\n            }\n        });\n    }\n\n    public static void removeMission(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                DBColumn column = pool.obtain().withNameAndValue(\"name\", mission.getName().toLowerCase(Locale.ENGLISH));\n                databaseBridge.deleteObject(\"players_missions\", createFilter(pool, \"player\", superiorPlayer, column));\n            }\n        });\n    }\n\n    public static void savePersistentDataContainer(SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"players_custom_data\",\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"data\", superiorPlayer.getPersistentDataContainer().serialize())\n                );\n            }\n        });\n    }\n\n    public static void removePersistentDataContainer(SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge ->\n                databaseBridge.deleteObject(\"players_custom_data\", createFilter(\"player\", superiorPlayer)));\n    }\n\n    public static void insertPlayer(SuperiorPlayer superiorPlayer) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"players\",\n                        pool.obtain().withNameAndValue(\"uuid\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"last_used_name\", superiorPlayer.getName()),\n                        pool.obtain().withNameAndValue(\"last_used_skin\", superiorPlayer.getTextureValue()),\n                        pool.obtain().withNameAndValue(\"disbands\", superiorPlayer.getDisbands()),\n                        pool.obtain().withNameAndValue(\"last_time_updated\", superiorPlayer.getLastTimeStatus())\n                );\n            }\n        });\n        insertPlayerSettings(superiorPlayer);\n    }\n\n    public static void insertPlayerSettings(SuperiorPlayer superiorPlayer) {\n        Locale userLocale = superiorPlayer.getUserLocale();\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"players_settings\",\n                        pool.obtain().withNameAndValue(\"player\", superiorPlayer.getUniqueId().toString()),\n                        pool.obtain().withNameAndValue(\"language\", userLocale.getLanguage() + \"-\" + userLocale.getCountry()),\n                        pool.obtain().withNameAndValue(\"toggled_panel\", superiorPlayer.hasToggledPanel()),\n                        pool.obtain().withNameAndValue(\"border_color\", superiorPlayer.getBorderColor().name()),\n                        pool.obtain().withNameAndValue(\"toggled_border\", superiorPlayer.hasWorldBorderEnabled()),\n                        pool.obtain().withNameAndValue(\"island_fly\", superiorPlayer.hasIslandFlyEnabled())\n                );\n            }\n        });\n    }\n\n    public static void replacePlayer(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) {\n        DatabaseBridge playersReplacer = getGlobalPlayersBridge();\n\n        try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n            DBColumn uuidColumn = pool.obtain().withNameAndValue(\"uuid\", newPlayer.getUniqueId().toString());\n            DatabaseFilter uuidFilter = createFilter(\"uuid\", originalPlayer);\n\n            DBColumn playerColumn = pool.obtain().withNameAndValue(\"player\", newPlayer.getUniqueId().toString());\n            DatabaseFilter playerFilter = createFilter(\"player\", originalPlayer);\n\n            // We go through all possible tables (both island and players) and replace the player uuids.\n            playersReplacer.updateObject(\"players\", uuidFilter, uuidColumn);\n            playersReplacer.updateObject(\"players_settings\", playerFilter, playerColumn);\n\n\n            playersReplacer.updateObject(\"bank_transactions\", playerFilter, playerColumn);\n            playersReplacer.updateObject(\"islands_bans\", playerFilter, playerColumn);\n            playersReplacer.updateObject(\"islands_bans\", createFilter(\"banned_by\", originalPlayer),\n                    pool.obtain().withNameAndValue(\"banned_by\", newPlayer.getUniqueId().toString()));\n            playersReplacer.updateObject(\"islands_player_permissions\", playerFilter, playerColumn);\n            playersReplacer.updateObject(\"islands_ratings\", playerFilter, playerColumn);\n            playersReplacer.updateObject(\"islands_visitors\", playerFilter, playerColumn);\n\n            if (newPlayer.hasIsland()) {\n                playersReplacer.updateObject(\"islands\", createFilter(\"owner\", originalPlayer),\n                        pool.obtain().withNameAndValue(\"owner\", newPlayer.getUniqueId().toString()));\n                playersReplacer.updateObject(\"islands_members\", playerFilter, playerColumn);\n            }\n\n            if (!newPlayer.isPersistentDataContainerEmpty())\n                playersReplacer.updateObject(\"players_custom_data\", playerFilter, playerColumn);\n            if (!newPlayer.getCompletedMissions().isEmpty())\n                playersReplacer.updateObject(\"players_missions\", playerFilter, playerColumn);\n        }\n    }\n\n    public static void deletePlayer(SuperiorPlayer superiorPlayer) {\n        DatabaseBridge playersReplacer = getGlobalPlayersBridge();\n\n        DatabaseFilter uuidFilter = createFilter(\"uuid\", superiorPlayer);\n        DatabaseFilter playerFilter = createFilter(\"player\", superiorPlayer);\n\n        // We go through all possible tables (both island and players) and delete the player record.\n        playersReplacer.deleteObject(\"players\", uuidFilter);\n        playersReplacer.deleteObject(\"players_settings\", playerFilter);\n\n        playersReplacer.deleteObject(\"bank_transactions\", playerFilter);\n        playersReplacer.deleteObject(\"islands_bans\", playerFilter);\n        playersReplacer.deleteObject(\"islands_bans\", createFilter(\"banned_by\", superiorPlayer));\n        playersReplacer.deleteObject(\"islands_player_permissions\", playerFilter);\n        playersReplacer.deleteObject(\"islands_ratings\", playerFilter);\n        playersReplacer.deleteObject(\"islands_visitors\", playerFilter);\n\n        if (superiorPlayer.hasIsland()) {\n            playersReplacer.deleteObject(\"islands\", createFilter(\"owner\", superiorPlayer));\n            playersReplacer.deleteObject(\"islands_members\", playerFilter);\n        }\n        if (!superiorPlayer.isPersistentDataContainerEmpty())\n            playersReplacer.deleteObject(\"players_custom_data\", playerFilter);\n        if (!superiorPlayer.getCompletedMissions().isEmpty())\n            playersReplacer.deleteObject(\"players_missions\", playerFilter);\n    }\n\n    public static void markPersistentDataContainerToBeSaved(SuperiorPlayer superiorPlayer) {\n        Set<Object> varsForPersistentData = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(superiorPlayer.getUniqueId(), u -> new EnumMap<>(FutureSave.class))\n                .computeIfAbsent(FutureSave.PERSISTENT_DATA, e -> new HashSet<>());\n        if (varsForPersistentData.isEmpty())\n            varsForPersistentData.add(new Object());\n    }\n\n    public static boolean isModified(SuperiorPlayer superiorPlayer) {\n        return SAVE_METHODS_TO_BE_EXECUTED.containsKey(superiorPlayer.getUniqueId());\n    }\n\n    public static void executeFutureSaves(SuperiorPlayer superiorPlayer) {\n        Map<FutureSave, Set<Object>> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.remove(superiorPlayer.getUniqueId());\n        if (futureSaves != null) {\n            for (Map.Entry<FutureSave, Set<Object>> futureSaveEntry : futureSaves.entrySet()) {\n                switch (futureSaveEntry.getKey()) {\n                    case PERSISTENT_DATA: {\n                        if (superiorPlayer.isPersistentDataContainerEmpty())\n                            removePersistentDataContainer(superiorPlayer);\n                        else\n                            savePersistentDataContainer(superiorPlayer);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    public static void executeFutureSaves(SuperiorPlayer superiorPlayer, FutureSave futureSave) {\n        Map<FutureSave, Set<Object>> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.get(superiorPlayer.getUniqueId());\n\n        if (futureSaves == null)\n            return;\n\n        Set<Object> values = futureSaves.remove(futureSave);\n\n        if (values == null)\n            return;\n\n        if (futureSaves.isEmpty())\n            SAVE_METHODS_TO_BE_EXECUTED.remove(superiorPlayer.getUniqueId());\n\n        switch (futureSave) {\n            case PERSISTENT_DATA: {\n                if (superiorPlayer.isPersistentDataContainerEmpty())\n                    removePersistentDataContainer(superiorPlayer);\n                else\n                    savePersistentDataContainer(superiorPlayer);\n                break;\n            }\n        }\n    }\n\n    private static void updatePlayerValue(SuperiorPlayer superiorPlayer, String columnName, Object value) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value);\n                databaseBridge.updateObject(\"players\", createFilter(\"uuid\", superiorPlayer), column);\n            }\n        });\n    }\n\n    private static void updatePlayerSettingsValue(SuperiorPlayer superiorPlayer, String columnName, Object value) {\n        runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Wrapper<DBColumn> wrapper = ObjectsPools.DB_COLUMN.obtain()) {\n                DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value);\n                databaseBridge.updateObject(\"players_settings\", createFilter(\"player\", superiorPlayer), column);\n            }\n        });\n    }\n\n    private static DatabaseFilter createFilter(String id, SuperiorPlayer superiorPlayer) {\n        return DatabaseFilter.fromFilter(id, superiorPlayer.getUniqueId().toString());\n    }\n\n    private static DatabaseFilter createFilter(ObjectsPools.Batch<DBColumn> pool, String id, SuperiorPlayer superiorPlayer, DBColumn column) {\n        List<Pair<String, Object>> filters = new LinkedList<>();\n        filters.add(pool.obtain().withNameAndValue(id, superiorPlayer.getUniqueId().toString()));\n        filters.add(column);\n        return DatabaseFilter.fromFilters(filters);\n    }\n\n    private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer<DatabaseBridge> databaseBridgeConsumer) {\n        if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA)\n            databaseBridgeConsumer.accept(databaseBridge);\n    }\n\n    public enum FutureSave {\n\n        PERSISTENT_DATA\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.bridge;\n\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.DBColumn;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock;\n\nimport java.util.function.Consumer;\n\npublic class StackedBlocksDatabaseBridge {\n\n    private StackedBlocksDatabaseBridge() {\n    }\n\n    public static void saveStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) {\n        runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> {\n            try (ObjectsPools.Batch<DBColumn> pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) {\n                databaseBridge.insertObject(\"stacked_blocks\",\n                        pool.obtain().withNameAndValue(\"location\", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())),\n                        pool.obtain().withNameAndValue(\"amount\", stackedBlock.getAmount()),\n                        pool.obtain().withNameAndValue(\"block_type\", stackedBlock.getBlockKey().toString())\n                );\n            }\n        });\n    }\n\n    public static void deleteStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) {\n        runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject(\"stacked_blocks\",\n                DatabaseFilter.fromFilter(\"location\", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation()))));\n    }\n\n    private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer<DatabaseBridge> databaseBridgeConsumer) {\n        if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA)\n            databaseBridgeConsumer.accept(databaseBridge);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.cache;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class DatabaseCache<V> {\n\n    private final Map<UUID, Record<V>> cache = new HashMap<>();\n\n    public DatabaseCache() {\n\n    }\n\n    public Record<V> computeIfAbsentInfo(UUID uuid, Supplier<V> value) {\n        return cache.computeIfAbsent(uuid, u -> new Record<>(value.get()));\n    }\n\n    public static class Record<T> {\n\n        private final Set<String> recordedTables = new HashSet<>();\n\n        private final T handle;\n\n        private Record(T handle) {\n            this.handle = handle;\n        }\n\n        public T get() {\n            return this.handle;\n        }\n\n        public void recordTable(String tableName) {\n            this.recordedTables.add(tableName);\n        }\n\n        public Set<String> getRecordedTables() {\n            return this.recordedTables;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/DatabaseLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader;\n\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\n\npublic interface DatabaseLoader {\n\n    void setState(State state) throws ManagerLoadException;\n\n    enum State {\n\n        INITIALIZE,\n        POST_INITIALIZE,\n        PRE_LOAD_DATA,\n        POST_LOAD_DATA,\n        SHUTDOWN\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/MachineStateDatabaseLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader;\n\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\npublic abstract class MachineStateDatabaseLoader implements DatabaseLoader {\n\n    private final Map<State, StateAction> STATE_MACHINE_HANDLES = Collections.unmodifiableMap(new EnumMap<State, StateAction>(State.class) {{\n        put(State.INITIALIZE, MachineStateDatabaseLoader.this::handleInitialize);\n        put(State.POST_INITIALIZE, MachineStateDatabaseLoader.this::handlePostInitialize);\n        put(State.PRE_LOAD_DATA, MachineStateDatabaseLoader.this::handlePreLoadData);\n        put(State.POST_LOAD_DATA, MachineStateDatabaseLoader.this::handlePostLoadData);\n        put(State.SHUTDOWN, MachineStateDatabaseLoader.this::handleShutdown);\n    }});\n\n    @Override\n    public void setState(State state) throws ManagerLoadException {\n        StateAction action = STATE_MACHINE_HANDLES.get(state);\n        if (action != null) {\n            try {\n                action.run();\n            } catch (Throwable error) {\n                if (error instanceof ManagerLoadException)\n                    throw error;\n\n                throw new ManagerLoadException(error, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n            }\n        }\n    }\n\n    protected abstract void handleInitialize() throws ManagerLoadException;\n\n    protected abstract void handlePostInitialize() throws ManagerLoadException;\n\n    protected abstract void handlePreLoadData() throws ManagerLoadException;\n\n    protected abstract void handlePostLoadData() throws ManagerLoadException;\n\n    protected abstract void handleShutdown() throws ManagerLoadException;\n\n    private interface StateAction {\n\n        void run() throws ManagerLoadException;\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/backup/BackupDatabase.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.backup;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.database.loader.DatabaseLoader;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.io.ZipFiles;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class BackupDatabase implements DatabaseLoader {\n\n    private static final SimpleDateFormat BACKUP_FILE_NAME_DATE_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd\");\n    private static final int MAX_BACKUP_FILES_PER_DAY = 1000;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public BackupDatabase(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void setState(State state) throws ManagerLoadException {\n        if (state != State.PRE_LOAD_DATA || !plugin.getSettings().getDatabase().isBackup())\n            return;\n\n        File datastoreFolder = new File(plugin.getDataFolder(), \"datastore\");\n\n        if (!datastoreFolder.exists())\n            return;\n\n        String currentTime = BACKUP_FILE_NAME_DATE_FORMAT.format(new Date());\n\n        File backupFile = getBackupFile(currentTime, 1);\n\n        if (backupFile == null)\n            throw new ManagerLoadException(\"Could not create a backup file as file already exists\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        Log.info(\"Creating a backup file...\");\n\n        backupFile.getParentFile().mkdirs();\n\n        try {\n            ZipFiles.zipFolder(datastoreFolder, backupFile);\n        } catch (IOException error) {\n            backupFile.delete();\n            throw new ManagerLoadException(error, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        Log.info(\"Backup done!\");\n    }\n\n    @Nullable\n    private File getBackupFile(String time, int attempt) {\n        File file = new File(plugin.getDataFolder(), String.format(\"backup/%s%s.zip\", time,\n                attempt > 1 ? \"-\" + attempt : \"\"));\n\n        if (file.exists())\n            return attempt >= MAX_BACKUP_FILES_PER_DAY ? null : getBackupFile(time, attempt + 1);\n\n        return file;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql;\n\nimport com.bgsoftware.common.databasebridge.sql.query.Column;\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseUpgrade_V0;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1.DatabaseUpgrade_V1;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2.DatabaseUpgrade_V2;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3.DatabaseUpgrade_V3;\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableInt;\n\nimport java.sql.ResultSet;\n\npublic class SQLDatabase {\n\n    private static final Runnable[] DATABASE_UPGRADES = new Runnable[]{\n            DatabaseUpgrade_V0.INSTANCE,\n            DatabaseUpgrade_V1.INSTANCE,\n            DatabaseUpgrade_V2.INSTANCE,\n            DatabaseUpgrade_V3.INSTANCE\n    };\n\n    private SQLDatabase() {\n\n    }\n\n    public static void initializeDatabase() {\n        createMetadataTable();\n        createIslandsTable();\n        createPlayersTable();\n        createGridTable();\n        createBankTransactionsTable();\n        createStackedBlocksTable();\n    }\n\n    public static UpgradeResult upgradeDatabase() {\n        MutableInt databaseVersionMutable = new MutableInt(0);\n\n        DBSession.select(\"ssb_metadata\", \"\", new QueryResult<ResultSet>()\n                .onSuccess(result -> databaseVersionMutable.set(result.getInt(\"version\")))\n                .onFail(error -> {\n                }));\n\n        int databaseVersion = databaseVersionMutable.get();\n        while (databaseVersion < DATABASE_UPGRADES.length) {\n            DATABASE_UPGRADES[databaseVersion++].run();\n        }\n\n        return new UpgradeResult(databaseVersion > databaseVersionMutable.get(), databaseVersion);\n    }\n\n    public static int getCurrentDatabaseVersion() {\n        return DATABASE_UPGRADES.length;\n    }\n\n    private static void createMetadataTable() {\n        MutableInt databaseVersion = new MutableInt(0);\n\n        // We check if \"islands\" table exists. If not, it's a new database,\n        // therefore the DB version should be latest. Otherwise, 0.\n        DBSession.select(\"islands\", \"\", new QueryResult<ResultSet>()\n                .onFail(error -> databaseVersion.set(getCurrentDatabaseVersion())));\n\n        DBSession.createTable(\"ssb_metadata\",\n                new Column(\"version\", \"INTEGER DEFAULT \" + databaseVersion.get())\n        );\n    }\n\n    private static void createIslandsTable() {\n        DBSession.createTable(\"islands\",\n                new Column(\"uuid\", \"UUID PRIMARY KEY\"),\n                new Column(\"owner\", \"UUID\"),\n                new Column(\"center\", \"TEXT\"),\n                new Column(\"creation_time\", \"BIGINT\"),\n                new Column(\"island_type\", \"TEXT\"),\n                new Column(\"discord\", \"TEXT\"),\n                new Column(\"paypal\", \"TEXT\"),\n                new Column(\"worth_bonus\", \"BIG_DECIMAL\"),\n                new Column(\"levels_bonus\", \"BIG_DECIMAL\"),\n                new Column(\"locked\", \"BOOLEAN\"),\n                new Column(\"ignored\", \"BOOLEAN\"),\n                new Column(\"name\", \"TEXT\"),\n                new Column(\"description\", \"TEXT\"),\n                new Column(\"generated_schematics\", \"INTEGER\"),\n                new Column(\"unlocked_worlds\", \"INTEGER\"),\n                new Column(\"last_time_updated\", \"BIGINT\"),\n                new Column(\"dirty_chunks\", \"LONGTEXT\"),\n                new Column(\"block_counts\", \"LONGTEXT\"),\n                new Column(\"entity_counts\", \"LONGTEXT\")\n        );\n\n        DBSession.createTable(\"islands_banks\",\n                new Column(\"island\", \"UUID PRIMARY KEY\"),\n                new Column(\"balance\", \"BIG_DECIMAL\"),\n                new Column(\"last_interest_time\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"islands_bans\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"banned_by\", \"UUID\"),\n                new Column(\"banned_time\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"islands_block_limits\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"block\", \"UNIQUE_TEXT\"),\n                new Column(\"`limit`\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_chests\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"`index`\", \"INTEGER\"),\n                new Column(\"contents\", \"LONGBLOB\")\n        );\n\n        DBSession.createTable(\"islands_custom_data\",\n                new Column(\"island\", \"UUID PRIMARY KEY\"),\n                new Column(\"data\", \"BLOB\")\n        );\n\n        DBSession.createTable(\"islands_effects\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"effect_type\", \"UNIQUE_TEXT\"),\n                new Column(\"level\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_entity_limits\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"entity\", \"UNIQUE_TEXT\"),\n                new Column(\"`limit`\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_flags\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"name\", \"UNIQUE_TEXT\"),\n                new Column(\"status\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_generators\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"environment\", \"VARCHAR(7)\"),\n                new Column(\"block\", \"UNIQUE_TEXT\"),\n                new Column(\"rate\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_homes\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"environment\", \"VARCHAR(7)\"),\n                new Column(\"location\", \"TEXT\")\n        );\n\n        DBSession.createTable(\"islands_members\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"role\", \"INTEGER\"),\n                new Column(\"join_time\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"islands_missions\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"name\", \"LONG_UNIQUE_TEXT\"),\n                new Column(\"finish_count\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_player_permissions\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"permission\", \"UNIQUE_TEXT\"),\n                new Column(\"status\", \"BOOLEAN\")\n        );\n\n        DBSession.createTable(\"islands_ratings\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"rating\", \"INTEGER\"),\n                new Column(\"rating_time\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"islands_role_limits\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"role\", \"INTEGER\"),\n                new Column(\"`limit`\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_role_permissions\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"role\", \"INTEGER\"),\n                new Column(\"permission\", \"UNIQUE_TEXT\")\n        );\n\n        DBSession.createTable(\"islands_settings\",\n                new Column(\"island\", \"UUID PRIMARY KEY\"),\n                new Column(\"size\", \"INTEGER\"),\n                new Column(\"bank_limit\", \"BIG_DECIMAL\"),\n                new Column(\"coops_limit\", \"INTEGER\"),\n                new Column(\"members_limit\", \"INTEGER\"),\n                new Column(\"warps_limit\", \"INTEGER\"),\n                new Column(\"crop_growth_multiplier\", \"DECIMAL\"),\n                new Column(\"spawner_rates_multiplier\", \"DECIMAL\"),\n                new Column(\"mob_drops_multiplier\", \"DECIMAL\")\n        );\n\n        DBSession.createTable(\"islands_upgrades\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"upgrade\", \"LONG_UNIQUE_TEXT\"),\n                new Column(\"level\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"islands_visitor_homes\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"environment\", \"VARCHAR(7)\"),\n                new Column(\"location\", \"TEXT\")\n        );\n\n        DBSession.createTable(\"islands_visitors\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"visit_time\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"islands_warp_categories\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"name\", \"LONG_UNIQUE_TEXT\"),\n                new Column(\"slot\", \"INTEGER\"),\n                new Column(\"icon\", \"TEXT\")\n        );\n\n        DBSession.createTable(\"islands_warps\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"name\", \"LONG_UNIQUE_TEXT\"),\n                new Column(\"category\", \"TEXT\"),\n                new Column(\"location\", \"TEXT\"),\n                new Column(\"private\", \"BOOLEAN\"),\n                new Column(\"icon\", \"TEXT\")\n        );\n    }\n\n    private static void createPlayersTable() {\n        DBSession.createTable(\"players\",\n                new Column(\"uuid\", \"UUID PRIMARY KEY\"),\n                new Column(\"last_used_name\", \"TEXT\"),\n                new Column(\"last_used_skin\", \"TEXT\"),\n                new Column(\"disbands\", \"INTEGER\"),\n                new Column(\"last_time_updated\", \"BIGINT\")\n        );\n\n        DBSession.createTable(\"players_custom_data\",\n                new Column(\"player\", \"UUID PRIMARY KEY\"),\n                new Column(\"data\", \"BLOB\")\n        );\n\n        DBSession.createTable(\"players_missions\",\n                new Column(\"player\", \"UUID\"),\n                new Column(\"name\", \"LONG_UNIQUE_TEXT\"),\n                new Column(\"finish_count\", \"INTEGER\")\n        );\n\n        DBSession.createTable(\"players_settings\",\n                new Column(\"player\", \"UUID PRIMARY KEY\"),\n                new Column(\"language\", \"TEXT\"),\n                new Column(\"toggled_panel\", \"BOOLEAN\"),\n                new Column(\"border_color\", \"TEXT\"),\n                new Column(\"toggled_border\", \"BOOLEAN\"),\n                new Column(\"island_fly\", \"BOOLEAN\")\n        );\n    }\n\n    private static void createGridTable() {\n        DBSession.createTable(\"grid\",\n                new Column(\"last_island\", \"TEXT\"),\n                new Column(\"max_island_size\", \"INTEGER\"),\n                new Column(\"world\", \"TEXT\")\n        );\n    }\n\n    private static void createBankTransactionsTable() {\n        DBSession.createTable(\"bank_transactions\",\n                new Column(\"island\", \"UUID\"),\n                new Column(\"player\", \"UUID\"),\n                new Column(\"bank_action\", \"TEXT\"),\n                new Column(\"position\", \"INTEGER\"),\n                new Column(\"time\", \"BIGINT\"),\n                new Column(\"failure_reason\", \"TEXT\"),\n                new Column(\"amount\", \"TEXT\")\n        );\n    }\n\n    private static void createStackedBlocksTable() {\n        DBSession.createTable(\"stacked_blocks\",\n                new Column(\"location\", \"LONG_UNIQUE_TEXT PRIMARY KEY\"),\n                new Column(\"block_type\", \"TEXT\"),\n                new Column(\"amount\", \"INTEGER\")\n        );\n    }\n\n    public static class UpgradeResult {\n\n        private final boolean upgraded;\n        private final int databaseVersion;\n\n        UpgradeResult(boolean upgraded, int databaseVersion) {\n            this.upgraded = upgraded;\n            this.databaseVersion = databaseVersion;\n        }\n\n        public boolean isUpgraded() {\n            return upgraded;\n        }\n\n        public int getDatabaseVersion() {\n            return databaseVersion;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql;\n\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.loader.MachineStateDatabaseLoader;\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\n\nimport java.sql.ResultSet;\n\npublic class SQLDatabaseLoader extends MachineStateDatabaseLoader {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public SQLDatabaseLoader(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void setState(State state) throws ManagerLoadException {\n        if (!plugin.getFactory().hasCustomDatabaseBridge())\n            super.setState(state);\n    }\n\n    @Override\n    protected void handleInitialize() throws ManagerLoadException {\n        if (!DBSession.createConnection(plugin)) {\n            throw new ManagerLoadException(\"Couldn't connect to the database.\\nMake sure all information is correct.\",\n                    ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        try {\n            DBSession.select(\"ssb_metadata\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n                int databaseVersion = resultSet.getInt(\"version\");\n\n                if (databaseVersion > SQLDatabase.getCurrentDatabaseVersion())\n                    throw new IllegalStateException(\"Database is in newer version: \" + databaseVersion + \" > \" + SQLDatabase.getCurrentDatabaseVersion());\n            }).onFail(error -> {\n            }));\n        } catch (IllegalStateException error) {\n            throw new ManagerLoadException(error.getMessage(), ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        SQLDatabase.UpgradeResult databaseUpgradeResult = SQLDatabase.upgradeDatabase();\n\n        SQLDatabase.initializeDatabase();\n\n        if (databaseUpgradeResult.isUpgraded())\n            GridDatabaseBridge.updateVersion(plugin.getGrid(), databaseUpgradeResult.getDatabaseVersion());\n\n        DBSession.select(\"grid\", \"\", new QueryResult<ResultSet>()\n                .onFail(error -> GridDatabaseBridge.insertGrid(plugin.getGrid())));\n    }\n\n    @Override\n    protected void handlePostInitialize() {\n        DBSession.createIndex(\"islands_bans_index\", \"islands_bans\",\n                \"island\", \"player\");\n\n        DBSession.createIndex(\"block_limits_index\", \"islands_block_limits\",\n                \"island\", \"block\");\n\n        DBSession.createIndex(\"islands_chests_index\", \"islands_chests\",\n                \"island\", \"`index`\");\n\n        DBSession.createIndex(\"islands_effects_index\", \"islands_effects\",\n                \"island\", \"effect_type\");\n\n        DBSession.createIndex(\"entity_limits_index\", \"islands_entity_limits\",\n                \"island\", \"entity\");\n\n        DBSession.createIndex(\"islands_flags_index\", \"islands_flags\",\n                \"island\", \"name\");\n\n        DBSession.createIndex(\"islands_generators_index\", \"islands_generators\",\n                \"island\", \"environment\", \"block\");\n\n        DBSession.createIndex(\"islands_homes_index\", \"islands_homes\",\n                \"island\", \"environment\");\n\n        DBSession.createIndex(\"islands_members_index\", \"islands_members\",\n                \"island\", \"player\");\n\n        DBSession.createIndex(\"islands_missions_index\", \"islands_missions\",\n                \"island\", \"name\");\n\n        DBSession.createIndex(\"player_permissions_index\", \"islands_player_permissions\",\n                \"island\", \"player\", \"permission\");\n\n        DBSession.createIndex(\"islands_ratings_index\", \"islands_ratings\",\n                \"island\", \"player\");\n\n        DBSession.createIndex(\"role_limits_index\", \"islands_role_limits\",\n                \"island\", \"role\");\n\n        DBSession.createIndex(\"role_permissions_index\", \"islands_role_permissions\",\n                \"island\", \"permission\");\n\n        DBSession.createIndex(\"islands_upgrades_index\", \"islands_upgrades\",\n                \"island\", \"upgrade\");\n\n        DBSession.createIndex(\"visitor_homes_index\", \"islands_visitor_homes\",\n                \"island\", \"environment\");\n\n        DBSession.createIndex(\"islands_visitors_index\", \"islands_visitors\",\n                \"island\", \"player\");\n\n        DBSession.createIndex(\"warp_categories_index\", \"islands_warp_categories\",\n                \"island\", \"name\");\n\n        DBSession.createIndex(\"islands_warps_index\", \"islands_warps\",\n                \"island\", \"name\");\n\n        DBSession.createIndex(\"players_missions_index\", \"players_missions\",\n                \"player\", \"name\");\n    }\n\n    @Override\n    protected void handlePreLoadData() {\n        DBSession.setJournalMode(\"MEMORY\", QueryResult.EMPTY_QUERY_RESULT);\n    }\n\n    @Override\n    protected void handlePostLoadData() {\n        DBSession.setJournalMode(\"DELETE\", QueryResult.EMPTY_QUERY_RESULT);\n    }\n\n    @Override\n    protected void handleShutdown() {\n\n        DBSession.close();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0;\n\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.SQLDatabase;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.BankTransactionsAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.GridAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.StackedBlockAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.EmptyParameterGuardDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.IDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.JsonDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.MultipleDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.RawDeserializer;\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\nimport com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableObject;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport org.bukkit.World;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.io.File;\nimport java.sql.ResultSet;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.BiConsumer;\n\npublic class DatabaseConverter {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final UUID CONSOLE_UUID = new UUID(0, 0);\n\n    private static File databaseFile;\n    private static boolean isRemoteDatabase;\n\n    private static final List<PlayerAttributes> loadedPlayers = new ArrayList<>();\n    private static final List<IslandAttributes> loadedIslands = new ArrayList<>();\n    private static final List<StackedBlockAttributes> loadedBlocks = new ArrayList<>();\n    private static final List<BankTransactionsAttributes> loadedBankTransactions = new ArrayList<>();\n    private static final IDeserializer deserializer = new MultipleDeserializer(\n            EmptyParameterGuardDeserializer.getInstance(),\n            JsonDeserializer.INSTANCE,\n            RawDeserializer.INSTANCE\n    );\n    private static GridAttributes gridAttributes;\n\n    private DatabaseConverter() {\n\n    }\n\n    public static void tryConvertDatabase() {\n        boolean isOldDatabaseFormat = isDatabaseOldFormat();\n        if (isOldDatabaseFormat) {\n            convertDatabase();\n            saveConvertedData();\n        }\n    }\n\n    private static void convertDatabase() {\n        Log.info(\"[Database-Converter] Detected old database - starting to convert data...\");\n\n        DBSession.select(\"players\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                loadedPlayers.add(loadPlayer(new ResultSetMapBridge(resultSet)));\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n\n        Log.info(\"[Database-Converter] Found \", loadedPlayers.size(), \" players in the database.\");\n\n        DBSession.select(\"islands\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                loadedIslands.add(loadIsland(new ResultSetMapBridge(resultSet)));\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n\n        Log.info(\"[Database-Converter] Found \", loadedIslands.size(), \" islands in the database.\");\n\n        DBSession.select(\"stackedBlocks\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                loadedBlocks.add(loadStackedBlock(new ResultSetMapBridge(resultSet)));\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n\n        Log.info(\"[Database-Converter] Found \", loadedBlocks.size(), \" stacked blocks in the database.\");\n\n        // Ignoring errors as the bankTransactions table may not exist.\n        AtomicBoolean foundBankTransaction = new AtomicBoolean(false);\n        DBSession.select(\"bankTransactions\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            foundBankTransaction.set(true);\n            while (resultSet.next()) {\n                loadedBankTransactions.add(loadBankTransaction(new ResultSetMapBridge(resultSet)));\n            }\n        }));\n\n        if (foundBankTransaction.get()) {\n            Log.info(\"[Database-Converter] Found \", loadedBankTransactions.size(), \" bank transactions in the database.\");\n        }\n\n        DBSession.select(\"grid\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            if (resultSet.next()) {\n                gridAttributes = new GridAttributes()\n                        .setValue(GridAttributes.Field.LAST_ISLAND, resultSet.getString(\"lastIsland\"))\n                        .setValue(GridAttributes.Field.MAX_ISLAND_SIZE, resultSet.getString(\"maxIslandSize\"))\n                        .setValue(GridAttributes.Field.WORLD, resultSet.getString(\"world\"));\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n\n        MutableObject<Throwable> failedBackupError = new MutableObject<>(null);\n\n        if (!isRemoteDatabase) {\n            DBSession.close();\n            if (!databaseFile.renameTo(new File(databaseFile.getParentFile(), \"database-bkp.db\"))) {\n                failedBackupError.setValue(new RuntimeException(\"Failed to rename file to database-bkp.db\"));\n            } else {\n                DBSession.createConnection(plugin);\n                SQLDatabase.initializeDatabase();\n            }\n        }\n\n        if (failedBackupError.getValue() != null) {\n            Log.error(failedBackupError.getValue(), \"[Database-Converter] Failed to create a backup for the database file:\");\n        } else {\n            Log.info(\"[Database-Converter] Successfully created a backup for the database.\");\n        }\n    }\n\n    private static void saveConvertedData() {\n        savePlayers();\n        saveIslands();\n        saveStackedBlocks();\n        saveBankTransactions();\n        saveGrid();\n    }\n\n    private static boolean isDatabaseOldFormat() {\n        isRemoteDatabase = isRemoteDatabase();\n\n        if (!isRemoteDatabase) {\n            databaseFile = new File(plugin.getDataFolder(), \"datastore/database.db\");\n\n            if (!databaseFile.exists())\n                return false;\n        }\n\n        AtomicBoolean isOldFormat = new AtomicBoolean(true);\n\n        DBSession.select(\"stackedBlocks\", \"\", new QueryResult<ResultSet>().onFail(error -> {\n            isOldFormat.set(false);\n        }));\n\n        return isOldFormat.get();\n    }\n\n    private static boolean isRemoteDatabase() {\n        switch (plugin.getSettings().getDatabase().getType()) {\n            case \"MYSQL\":\n            case \"MARIADB\":\n            case \"POSTGRESQL\":\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private static void savePlayers() {\n        Log.info(\"[Database-Converter] Converting players...\");\n\n        CustomSQLDatabaseTransaction playersTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}players VALUES(?,?,?,?,?)\");\n        CustomSQLDatabaseTransaction playersMissionsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}players_missions VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction playersSettingsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}players_settings VALUES(?,?,?,?,?,?)\");\n\n        for (PlayerAttributes playerAttributes : loadedPlayers) {\n            insertPlayer(playerAttributes, playersTransaction, playersMissionsTransaction, playersSettingsTransaction);\n        }\n\n        try {\n            DBSession.execute(playersMissionsTransaction, playersSettingsTransaction).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n    }\n\n    private static void saveIslands() {\n        long currentTime = System.currentTimeMillis();\n\n        Log.info(\"[Database-Converter] Converting islands...\");\n\n        CustomSQLDatabaseTransaction islandsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsBanksTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_banks VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsBansTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_bans VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsBlockLimitsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_block_limits VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsChestsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_chests VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsEffectsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_effects VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsEntityLimitsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_entity_limits VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsFlagsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_flags VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsGeneratorsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_generators VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsHomesTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_homes VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsMembersTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_members VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsMissionsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_missions VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsPlayerPermissionsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_player_permissions VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsRatingsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_ratings VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsRoleLimitsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_role_limits VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsRolePermissionsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_role_permissions VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsSettingsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_settings VALUES(?,?,?,?,?,?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsUpgradesTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_upgrades VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsVisitorHomesTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_visitor_homes VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsVisitorsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_visitors VALUES(?,?,?)\");\n        CustomSQLDatabaseTransaction islandsWarpCategoriesTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_warp_categories VALUES(?,?,?,?)\");\n        CustomSQLDatabaseTransaction islandsWarpsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}islands_warps VALUES(?,?,?,?,?,?)\");\n\n        for (IslandAttributes islandAttributes : loadedIslands) {\n            insertIsland(islandAttributes, currentTime, islandsTransaction, islandsBanksTransaction, islandsBansTransaction,\n                    islandsBlockLimitsTransaction, islandsChestsTransaction, islandsEffectsTransaction, islandsEntityLimitsTransaction,\n                    islandsFlagsTransaction, islandsGeneratorsTransaction, islandsHomesTransaction, islandsMembersTransaction,\n                    islandsMissionsTransaction, islandsPlayerPermissionsTransaction, islandsRatingsTransaction, islandsRoleLimitsTransaction,\n                    islandsRolePermissionsTransaction, islandsSettingsTransaction, islandsUpgradesTransaction, islandsVisitorHomesTransaction,\n                    islandsVisitorsTransaction, islandsWarpCategoriesTransaction, islandsWarpsTransaction);\n        }\n\n        try {\n            DBSession.execute(\n                    islandsTransaction,\n                    islandsBanksTransaction,\n                    islandsBansTransaction,\n                    islandsBlockLimitsTransaction,\n                    islandsChestsTransaction,\n                    islandsEffectsTransaction,\n                    islandsEntityLimitsTransaction,\n                    islandsFlagsTransaction,\n                    islandsGeneratorsTransaction,\n                    islandsHomesTransaction,\n                    islandsMembersTransaction,\n                    islandsMissionsTransaction,\n                    islandsPlayerPermissionsTransaction,\n                    islandsRatingsTransaction,\n                    islandsRoleLimitsTransaction,\n                    islandsRolePermissionsTransaction,\n                    islandsSettingsTransaction,\n                    islandsUpgradesTransaction,\n                    islandsVisitorHomesTransaction,\n                    islandsVisitorsTransaction,\n                    islandsWarpCategoriesTransaction,\n                    islandsWarpsTransaction\n            ).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n    }\n\n    private static void saveStackedBlocks() {\n        Log.info(\"[Database-Converter] Converting stacked blocks...\");\n\n        CustomSQLDatabaseTransaction stackedBlocksTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}stacked_blocks VALUES(?,?,?)\");\n\n        for (StackedBlockAttributes stackedBlockAttributes : loadedBlocks) {\n            stackedBlocksTransaction\n                    .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.LOCATION))\n                    .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.BLOCK_TYPE))\n                    .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.AMOUNT))\n                    .newBatch();\n        }\n\n        try {\n            DBSession.execute(stackedBlocksTransaction).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n    }\n\n    private static void saveBankTransactions() {\n        Log.info(\"[Database-Converter] Converting bank transactions...\");\n\n        CustomSQLDatabaseTransaction bankTransactionsTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}bank_transactions VALUES(?,?,?,?,?,?,?)\");\n\n        for (BankTransactionsAttributes bankTransactionsAttributes : loadedBankTransactions) {\n            bankTransactionsTransaction\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.ISLAND))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.PLAYER))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.BANK_ACTION))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.POSITION))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.TIME))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.FAILURE_REASON))\n                    .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.AMOUNT))\n                    .newBatch();\n        }\n\n        try {\n            DBSession.execute(bankTransactionsTransaction).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n    }\n\n    private static void saveGrid() {\n        if (gridAttributes == null)\n            return;\n\n        Log.info(\"[Database-Converter] Converting grid data...\");\n\n        CustomSQLDatabaseTransaction deleteGridTransaction = new CustomSQLDatabaseTransaction(\"DELETE FROM {prefix}grid;\");\n        try {\n            DBSession.execute(deleteGridTransaction).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n\n        CustomSQLDatabaseTransaction insertGridTransaction = new CustomSQLDatabaseTransaction(\n                \"REPLACE INTO {prefix}grid VALUES(?,?,?)\");\n        insertGridTransaction\n                .bindObject(gridAttributes.getValue(GridAttributes.Field.LAST_ISLAND))\n                .bindObject(gridAttributes.getValue(GridAttributes.Field.MAX_ISLAND_SIZE))\n                .bindObject(gridAttributes.getValue(GridAttributes.Field.WORLD));\n        try {\n            DBSession.execute(insertGridTransaction).get();\n        } catch (InterruptedException | ExecutionException error) {\n            error.printStackTrace();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static void insertPlayer(PlayerAttributes playerAttributes,\n                                     CustomSQLDatabaseTransaction playersTransaction,\n                                     CustomSQLDatabaseTransaction playersMissionsTransaction,\n                                     CustomSQLDatabaseTransaction playersSettingsTransaction) {\n        String playerUUID = playerAttributes.getValue(PlayerAttributes.Field.UUID);\n        playersTransaction.bindObject(playerUUID)\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_USED_NAME))\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_USED_SKIN))\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.DISBANDS))\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_TIME_UPDATED))\n                .newBatch();\n        ((Map<String, Integer>) playerAttributes.getValue(PlayerAttributes.Field.COMPLETED_MISSIONS)).forEach((missionName, finishCount) ->\n                playersMissionsTransaction.bindObject(playerUUID)\n                        .bindObject(missionName.toLowerCase(Locale.ENGLISH))\n                        .bindObject(finishCount)\n                        .newBatch());\n        playersSettingsTransaction.bindObject(playerUUID)\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LANGUAGE))\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.TOGGLED_PANEL))\n                .bindObject(((BorderColor) playerAttributes.getValue(PlayerAttributes.Field.BORDER_COLOR)).name())\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.TOGGLED_BORDER))\n                .bindObject(playerAttributes.getValue(PlayerAttributes.Field.ISLAND_FLY))\n                .newBatch();\n    }\n\n    @SuppressWarnings({\"unchecked\"})\n    private static void insertIsland(IslandAttributes islandAttributes, long currentTime,\n                                     CustomSQLDatabaseTransaction islandsTransaction,\n                                     CustomSQLDatabaseTransaction islandsBanksTransaction,\n                                     CustomSQLDatabaseTransaction islandsBansTransaction,\n                                     CustomSQLDatabaseTransaction islandsBlockLimitsTransaction,\n                                     CustomSQLDatabaseTransaction islandsChestsTransaction,\n                                     CustomSQLDatabaseTransaction islandsEffectsTransaction,\n                                     CustomSQLDatabaseTransaction islandsEntityLimitsTransaction,\n                                     CustomSQLDatabaseTransaction islandsFlagsTransaction,\n                                     CustomSQLDatabaseTransaction islandsGeneratorsTransaction,\n                                     CustomSQLDatabaseTransaction islandsHomesTransaction,\n                                     CustomSQLDatabaseTransaction islandsMembersTransaction,\n                                     CustomSQLDatabaseTransaction islandsMissionsTransaction,\n                                     CustomSQLDatabaseTransaction islandsPlayerPermissionsTransaction,\n                                     CustomSQLDatabaseTransaction islandsRatingsTransaction,\n                                     CustomSQLDatabaseTransaction islandsRoleLimitsTransaction,\n                                     CustomSQLDatabaseTransaction islandsRolePermissionsTransaction,\n                                     CustomSQLDatabaseTransaction islandsSettingsTransaction,\n                                     CustomSQLDatabaseTransaction islandsUpgradesTransaction,\n                                     CustomSQLDatabaseTransaction islandsVisitorHomesTransaction,\n                                     CustomSQLDatabaseTransaction islandsVisitorsTransaction,\n                                     CustomSQLDatabaseTransaction islandsWarpCategoriesTransaction,\n                                     CustomSQLDatabaseTransaction islandsWarpsTransaction) {\n        String islandUUID = islandAttributes.getValue(IslandAttributes.Field.UUID);\n        islandsTransaction.bindObject(islandUUID)\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.OWNER))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.CENTER))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.CREATION_TIME))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.ISLAND_TYPE))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.DISCORD))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.PAYPAL))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.WORTH_BONUS))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.LEVELS_BONUS))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.LOCKED))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.IGNORED))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.NAME))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.DESCRIPTION))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.GENERATED_SCHEMATICS))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.UNLOCKED_WORLDS))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.LAST_TIME_UPDATED))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.DIRTY_CHUNKS))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.BLOCK_COUNTS))\n                .newBatch();\n        islandsBanksTransaction.bindObject(islandUUID)\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_BALANCE))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_LAST_INTEREST))\n                .newBatch();\n        ((List<PlayerAttributes>) islandAttributes.getValue(IslandAttributes.Field.BANS)).forEach(playerAttributes ->\n                islandsBansTransaction.bindObject(islandUUID)\n                        .bindObject(playerAttributes.getValue(PlayerAttributes.Field.UUID))\n                        .bindObject(CONSOLE_UUID.toString())\n                        .bindObject(currentTime)\n                        .newBatch());\n        ((KeyMap<Integer>) islandAttributes.getValue(IslandAttributes.Field.BLOCK_LIMITS)).forEach((key, limit) ->\n                islandsBlockLimitsTransaction.bindObject(islandUUID)\n                        .bindObject(key.toString())\n                        .bindObject(limit)\n                        .newBatch());\n        ((List<IslandChestAttributes>) islandAttributes.getValue(IslandAttributes.Field.ISLAND_CHESTS)).forEach(islandChestAttributes ->\n                islandsChestsTransaction.bindObject(islandUUID)\n                        .bindObject(islandChestAttributes.getValue(IslandChestAttributes.Field.INDEX))\n                        .bindObject(islandChestAttributes.getValue(IslandChestAttributes.Field.CONTENTS))\n                        .newBatch());\n        ((Map<PotionEffectType, Integer>) islandAttributes.getValue(IslandAttributes.Field.EFFECTS)).forEach((type, level) ->\n                islandsEffectsTransaction.bindObject(islandUUID)\n                        .bindObject(type.getName())\n                        .bindObject(level)\n                        .newBatch());\n        ((KeyMap<Integer>) islandAttributes.getValue(IslandAttributes.Field.ENTITY_LIMITS)).forEach((entity, limit) ->\n                islandsEntityLimitsTransaction.bindObject(islandUUID)\n                        .bindObject(entity.toString())\n                        .bindObject(limit)\n                        .newBatch());\n        ((Map<IslandFlag, Byte>) islandAttributes.getValue(IslandAttributes.Field.ISLAND_FLAGS)).forEach((islandFlag, status) ->\n                islandsFlagsTransaction.bindObject(islandUUID)\n                        .bindObject(islandFlag.getName())\n                        .bindObject(status)\n                        .newBatch());\n        runOnEnvironments((KeyMap<Integer>[]) islandAttributes.getValue(IslandAttributes.Field.GENERATORS), (generatorRates, environment) ->\n                generatorRates.forEach((block, rate) ->\n                        islandsGeneratorsTransaction.bindObject(islandUUID)\n                                .bindObject(environment.name())\n                                .bindObject(block.toString())\n                                .bindObject(rate)\n                                .newBatch()));\n        runOnEnvironments((String[]) islandAttributes.getValue(IslandAttributes.Field.HOMES), (islandHome, environment) ->\n                islandsHomesTransaction.bindObject(islandUUID)\n                        .bindObject(environment.name())\n                        .bindObject(islandHome)\n                        .newBatch());\n        ((List<PlayerAttributes>) islandAttributes.getValue(IslandAttributes.Field.MEMBERS)).forEach(playerAttributes ->\n                islandsMembersTransaction.bindObject(islandUUID)\n                        .bindObject(playerAttributes.getValue(PlayerAttributes.Field.UUID))\n                        .bindObject(((PlayerRole) playerAttributes.getValue(PlayerAttributes.Field.ISLAND_ROLE)).getId())\n                        .bindObject(currentTime)\n                        .newBatch());\n        ((Map<String, Integer>) islandAttributes.getValue(IslandAttributes.Field.MISSIONS)).forEach((mission, finishCount) ->\n                islandsMissionsTransaction.bindObject(islandUUID)\n                        .bindObject(mission)\n                        .bindObject(finishCount)\n                        .newBatch());\n        ((Map<UUID, PlayerPrivilegeNode>) islandAttributes.getValue(IslandAttributes.Field.PLAYER_PERMISSIONS)).forEach((playerUUID, node) -> {\n            for (Map.Entry<IslandPrivilege, Boolean> playerPermission : node.getCustomPermissions().entrySet())\n                islandsPlayerPermissionsTransaction.bindObject(islandUUID)\n                        .bindObject(playerUUID.toString())\n                        .bindObject(playerPermission.getKey().getName())\n                        .bindObject(playerPermission.getValue())\n                        .newBatch();\n        });\n        ((Map<UUID, Rating>) islandAttributes.getValue(IslandAttributes.Field.RATINGS)).forEach((playerUUID, rating) ->\n                islandsRatingsTransaction.bindObject(islandUUID)\n                        .bindObject(playerUUID.toString())\n                        .bindObject(rating.getValue())\n                        .bindObject(currentTime)\n                        .newBatch());\n        ((Map<PlayerRole, Integer>) islandAttributes.getValue(IslandAttributes.Field.ROLE_LIMITS)).forEach((role, limit) ->\n                islandsRoleLimitsTransaction.bindObject(islandUUID)\n                        .bindObject(role.getId())\n                        .bindObject(limit)\n                        .newBatch());\n        ((Map<IslandPrivilege, PlayerRole>) islandAttributes.getValue(IslandAttributes.Field.ROLE_PERMISSIONS)).forEach((privilege, role) ->\n                islandsRolePermissionsTransaction.bindObject(islandUUID)\n                        .bindObject(role.getId())\n                        .bindObject(privilege.getName())\n                        .newBatch());\n        islandsSettingsTransaction.bindObject(islandUUID)\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.ISLAND_SIZE))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_LIMIT))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.COOP_LIMIT))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.TEAM_LIMIT))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.WARPS_LIMIT))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER))\n                .bindObject(islandAttributes.getValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER))\n                .newBatch();\n        ((Map<String, Integer>) islandAttributes.getValue(IslandAttributes.Field.UPGRADES)).forEach((upgradeName, level) ->\n                islandsUpgradesTransaction.bindObject(islandUUID)\n                        .bindObject(upgradeName)\n                        .bindObject(level)\n                        .newBatch());\n        String visitorHome = islandAttributes.getValue(IslandAttributes.Field.VISITOR_HOMES);\n        if (visitorHome != null && !visitorHome.isEmpty())\n            islandsVisitorHomesTransaction.bindObject(islandUUID)\n                    .bindObject(World.Environment.NORMAL.name())\n                    .bindObject(visitorHome)\n                    .newBatch();\n        ((List<Pair<UUID, Long>>) islandAttributes.getValue(IslandAttributes.Field.VISITORS)).forEach(visitor ->\n                islandsVisitorsTransaction.bindObject(islandUUID)\n                        .bindObject(visitor.getKey().toString())\n                        .bindObject(visitor.getValue())\n                        .newBatch());\n        ((List<WarpCategoryAttributes>) islandAttributes.getValue(IslandAttributes.Field.WARP_CATEGORIES)).forEach(warpCategoryAttributes ->\n                islandsWarpCategoriesTransaction.bindObject(islandUUID)\n                        .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.NAME))\n                        .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.SLOT))\n                        .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.ICON))\n                        .newBatch());\n        ((List<IslandWarpAttributes>) islandAttributes.getValue(IslandAttributes.Field.WARPS)).forEach(islandWarpAttributes ->\n                islandsWarpsTransaction.bindObject(islandUUID)\n                        .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.NAME))\n                        .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.CATEGORY))\n                        .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.LOCATION))\n                        .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.PRIVATE_STATUS))\n                        .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.ICON))\n                        .newBatch());\n    }\n\n    private static <T> void runOnEnvironments(T[] arr, BiConsumer<T, World.Environment> consumer) {\n        for (World.Environment environment : World.Environment.values()) {\n            if (arr[environment.ordinal()] != null) {\n                consumer.accept(arr[environment.ordinal()], environment);\n            }\n        }\n    }\n\n    private static PlayerAttributes loadPlayer(ResultSetMapBridge resultSet) {\n        PlayerRole playerRole;\n\n        try {\n            playerRole = SPlayerRole.fromId(Integer.parseInt(resultSet.get(\"islandRole\", \"-1\")));\n        } catch (Exception ex) {\n            playerRole = SPlayerRole.of((String) resultSet.get(\"islandRole\"));\n        }\n\n        long currentTime = System.currentTimeMillis();\n\n        return new PlayerAttributes()\n                .setValue(PlayerAttributes.Field.UUID, resultSet.get(\"player\"))\n                .setValue(PlayerAttributes.Field.ISLAND_LEADER, resultSet.get(\"teamLeader\", resultSet.get(\"player\")))\n                .setValue(PlayerAttributes.Field.LAST_USED_NAME, resultSet.get(\"name\", \"null\"))\n                .setValue(PlayerAttributes.Field.LAST_USED_SKIN, resultSet.get(\"textureValue\", \"\"))\n                .setValue(PlayerAttributes.Field.ISLAND_ROLE, playerRole)\n                .setValue(PlayerAttributes.Field.DISBANDS, resultSet.get(\"disbands\", plugin.getSettings().getDisbandCount()))\n                .setValue(PlayerAttributes.Field.LAST_TIME_UPDATED, resultSet.get(\"lastTimeStatus\", currentTime / 1000))\n                .setValue(PlayerAttributes.Field.COMPLETED_MISSIONS, deserializer.deserializeMissions(resultSet.get(\"missions\", \"\")))\n                .setValue(PlayerAttributes.Field.TOGGLED_PANEL, resultSet.get(\"toggledPanel\", plugin.getSettings().isDefaultToggledPanel()))\n                .setValue(PlayerAttributes.Field.ISLAND_FLY, resultSet.get(\"islandFly\", plugin.getSettings().isDefaultIslandFly()))\n                .setValue(PlayerAttributes.Field.BORDER_COLOR, BorderColor.valueOf(resultSet.get(\"borderColor\", plugin.getSettings().getDefaultBorderColor())))\n                .setValue(PlayerAttributes.Field.LANGUAGE, resultSet.get(\"language\", plugin.getSettings().getDefaultLanguage()))\n                .setValue(PlayerAttributes.Field.TOGGLED_BORDER, resultSet.get(\"toggledBorder\", plugin.getSettings().isDefaultWorldBorder())\n                );\n    }\n\n    private static IslandAttributes loadIsland(ResultSetMapBridge resultSet) {\n        UUID ownerUUID = UUID.fromString((String) resultSet.get(\"owner\"));\n        UUID islandUUID;\n\n        String uuidRaw = resultSet.get(\"uuid\", null);\n        if (Text.isBlank(uuidRaw)) {\n            islandUUID = ownerUUID;\n        } else {\n            islandUUID = UUID.fromString(uuidRaw);\n        }\n\n        int generatedSchematics = 0;\n        String generatedSchematicsRaw = resultSet.get(\"generatedSchematics\", \"0\");\n        try {\n            generatedSchematics = Integer.parseInt(generatedSchematicsRaw);\n        } catch (Exception ex) {\n            if (generatedSchematicsRaw.contains(\"normal\"))\n                generatedSchematics |= 8;\n            if (generatedSchematicsRaw.contains(\"nether\"))\n                generatedSchematics |= 4;\n            if (generatedSchematicsRaw.contains(\"the_end\"))\n                generatedSchematics |= 3;\n        }\n\n        int unlockedWorlds = 0;\n        String unlockedWorldsRaw = resultSet.get(\"unlockedWorlds\", \"0\");\n        try {\n            unlockedWorlds = Integer.parseInt(unlockedWorldsRaw);\n        } catch (Exception ex) {\n            if (unlockedWorldsRaw.contains(\"nether\"))\n                unlockedWorlds |= 1;\n            if (unlockedWorldsRaw.contains(\"the_end\"))\n                unlockedWorlds |= 2;\n        }\n\n        long currentTime = System.currentTimeMillis();\n\n        return new IslandAttributes()\n                .setValue(IslandAttributes.Field.UUID, islandUUID.toString())\n                .setValue(IslandAttributes.Field.OWNER, ownerUUID.toString())\n                .setValue(IslandAttributes.Field.CENTER, (String) resultSet.get(\"center\"))\n                .setValue(IslandAttributes.Field.CREATION_TIME, resultSet.get(\"creationTime\", currentTime / 1000))\n                .setValue(IslandAttributes.Field.ISLAND_TYPE, resultSet.get(\"schemName\", \"\"))\n                .setValue(IslandAttributes.Field.DISCORD, resultSet.get(\"discord\", \"None\"))\n                .setValue(IslandAttributes.Field.PAYPAL, resultSet.get(\"paypal\", \"None\"))\n                .setValue(IslandAttributes.Field.WORTH_BONUS, resultSet.get(\"bonusWorth\", \"\"))\n                .setValue(IslandAttributes.Field.LEVELS_BONUS, resultSet.get(\"bonusLevel\", \"\"))\n                .setValue(IslandAttributes.Field.LOCKED, resultSet.get(\"locked\", false))\n                .setValue(IslandAttributes.Field.IGNORED, resultSet.get(\"ignored\", false))\n                .setValue(IslandAttributes.Field.NAME, resultSet.get(\"name\", \"\"))\n                .setValue(IslandAttributes.Field.DESCRIPTION, resultSet.get(\"description\", \"\"))\n                .setValue(IslandAttributes.Field.GENERATED_SCHEMATICS, generatedSchematics)\n                .setValue(IslandAttributes.Field.UNLOCKED_WORLDS, unlockedWorlds)\n                .setValue(IslandAttributes.Field.LAST_TIME_UPDATED, resultSet.get(\"lastTimeUpdate\", currentTime / 1000))\n                .setValue(IslandAttributes.Field.DIRTY_CHUNKS, deserializer.deserializeDirtyChunks(resultSet.get(\"dirtyChunks\", \"\")))\n                .setValue(IslandAttributes.Field.BLOCK_COUNTS, deserializer.deserializeBlockCounts(resultSet.get(\"blockCounts\", \"\")))\n                .setValue(IslandAttributes.Field.HOMES, deserializer.deserializeHomes(resultSet.get(\"teleportLocation\", \"\")))\n                .setValue(IslandAttributes.Field.MEMBERS, deserializer.deserializePlayers(resultSet.get(\"members\", \"\")))\n                .setValue(IslandAttributes.Field.BANS, deserializer.deserializePlayers(resultSet.get(\"banned\", \"\")))\n                .setValue(IslandAttributes.Field.PLAYER_PERMISSIONS, deserializer.deserializePlayerPerms(resultSet.get(\"permissionNodes\", \"\")))\n                .setValue(IslandAttributes.Field.ROLE_PERMISSIONS, deserializer.deserializeRolePerms(resultSet.get(\"permissionNodes\", \"\")))\n                .setValue(IslandAttributes.Field.UPGRADES, deserializer.deserializeUpgrades(resultSet.get(\"upgrades\", \"\")))\n                .setValue(IslandAttributes.Field.WARPS, deserializer.deserializeWarps(resultSet.get(\"warps\", \"\")))\n                .setValue(IslandAttributes.Field.BLOCK_LIMITS, deserializer.deserializeBlockLimits(resultSet.get(\"blockLimits\", \"\")))\n                .setValue(IslandAttributes.Field.RATINGS, deserializer.deserializeRatings(resultSet.get(\"ratings\", \"\")))\n                .setValue(IslandAttributes.Field.MISSIONS, deserializer.deserializeMissions(resultSet.get(\"missions\", \"\")))\n                .setValue(IslandAttributes.Field.ISLAND_FLAGS, deserializer.deserializeIslandFlags(resultSet.get(\"settings\", \"\")))\n                .setValue(IslandAttributes.Field.GENERATORS, deserializer.deserializeGenerators(resultSet.get(\"generator\", \"\")))\n                .setValue(IslandAttributes.Field.VISITORS, deserializer.deserializeVisitors(resultSet.get(\"uniqueVisitors\", \"\")))\n                .setValue(IslandAttributes.Field.ENTITY_LIMITS, deserializer.deserializeEntityLimits(resultSet.get(\"entityLimits\", \"\")))\n                .setValue(IslandAttributes.Field.EFFECTS, deserializer.deserializeEffects(resultSet.get(\"islandEffects\", \"\")))\n                .setValue(IslandAttributes.Field.ISLAND_CHESTS, deserializer.deserializeIslandChests(resultSet.get(\"islandChest\", \"\")))\n                .setValue(IslandAttributes.Field.ROLE_LIMITS, deserializer.deserializeRoleLimits(resultSet.get(\"roleLimits\", \"\")))\n                .setValue(IslandAttributes.Field.WARP_CATEGORIES, deserializer.deserializeWarpCategories(resultSet.get(\"warpCategories\", \"\")))\n                .setValue(IslandAttributes.Field.BANK_BALANCE, resultSet.get(\"islandBank\", \"\"))\n                .setValue(IslandAttributes.Field.BANK_LAST_INTEREST, resultSet.get(\"lastInterest\", currentTime / 1000))\n                .setValue(IslandAttributes.Field.VISITOR_HOMES, resultSet.get(\"visitorsLocation\", \"\"))\n                .setValue(IslandAttributes.Field.ISLAND_SIZE, resultSet.get(\"islandSize\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.TEAM_LIMIT, resultSet.get(\"teamLimit\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.WARPS_LIMIT, resultSet.get(\"warpsLimit\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER, resultSet.get(\"cropGrowth\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER, resultSet.get(\"spawnerRates\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER, resultSet.get(\"mobDrops\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.COOP_LIMIT, resultSet.get(\"coopLimit\", IslandUpgradeConstants.SYNCED_VALUE))\n                .setValue(IslandAttributes.Field.BANK_LIMIT, resultSet.get(\"bankLimit\", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString()));\n    }\n\n    private static StackedBlockAttributes loadStackedBlock(ResultSetMapBridge resultSet) {\n        String world = (String) resultSet.get(\"world\");\n        int x = (int) resultSet.get(\"x\");\n        int y = (int) resultSet.get(\"y\");\n        int z = (int) resultSet.get(\"z\");\n        String amount = (String) resultSet.get(\"amount\");\n        String blockType = (String) resultSet.get(\"item\");\n\n        return new StackedBlockAttributes()\n                .setValue(StackedBlockAttributes.Field.LOCATION, world + \", \" + x + \", \" + y + \", \" + z)\n                .setValue(StackedBlockAttributes.Field.BLOCK_TYPE, blockType)\n                .setValue(StackedBlockAttributes.Field.AMOUNT, amount);\n    }\n\n    private static BankTransactionsAttributes loadBankTransaction(ResultSetMapBridge resultSet) {\n        return new BankTransactionsAttributes()\n                .setValue(BankTransactionsAttributes.Field.ISLAND, resultSet.get(\"island\"))\n                .setValue(BankTransactionsAttributes.Field.PLAYER, resultSet.get(\"player\"))\n                .setValue(BankTransactionsAttributes.Field.BANK_ACTION, resultSet.get(\"bankAction\"))\n                .setValue(BankTransactionsAttributes.Field.POSITION, resultSet.get(\"position\"))\n                .setValue(BankTransactionsAttributes.Field.TIME, resultSet.get(\"time\"))\n                .setValue(BankTransactionsAttributes.Field.FAILURE_REASON, resultSet.get(\"failureReason\"))\n                .setValue(BankTransactionsAttributes.Field.AMOUNT, resultSet.get(\"amount\"));\n    }\n\n    public static PlayerAttributes getPlayerAttributes(String uuid) {\n        return loadedPlayers.stream().filter(playerAttributes ->\n                        playerAttributes.getValue(PlayerAttributes.Field.UUID).equals(uuid))\n                .findFirst()\n                .orElse(null);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0;\n\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\n\npublic class DatabaseUpgrade_V0 implements Runnable {\n\n    public static final DatabaseUpgrade_V0 INSTANCE = new DatabaseUpgrade_V0();\n\n    private DatabaseUpgrade_V0() {\n\n    }\n\n    @Override\n    public void run() {\n        upgradeIslandsTables();\n        upgradePlayersTables();\n        upgradeStackedBlocksTables();\n        DatabaseConverter.tryConvertDatabase();\n    }\n\n    private void upgradeIslandsTables() {\n        DBSession.modifyColumnType(\"islands\", \"dirty_chunks\", \"LONGTEXT\");\n        DBSession.modifyColumnType(\"islands\", \"block_counts\", \"LONGTEXT\");\n\n        DBSession.modifyColumnType(\"islands_chests\", \"contents\", \"LONGBLOB\");\n\n        DBSession.modifyColumnType(\"islands_missions\", \"name\", \"LONG_UNIQUE_TEXT\");\n\n        // Up to 1.9.0.574, decimals would not be saved correctly in MySQL\n        // This occurred because the field type was DECIMAL(10,0) instead of DECIMAL(10,2)\n        // Updating the column types to \"DECIMAL\" again should fix the issue.\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1021\n        DBSession.modifyColumnType(\"islands_settings\", \"crop_growth_multiplier\", \"DECIMAL\");\n        DBSession.modifyColumnType(\"islands_settings\", \"spawner_rates_multiplier\", \"DECIMAL\");\n        DBSession.modifyColumnType(\"islands_settings\", \"mob_drops_multiplier\", \"DECIMAL\");\n\n        DBSession.modifyColumnType(\"islands_upgrades\", \"upgrade\", \"LONG_UNIQUE_TEXT\");\n        DBSession.removePrimaryKey(\"islands_upgrades\", \"island\");\n\n        DBSession.modifyColumnType(\"islands_warp_categories\", \"name\", \"LONG_UNIQUE_TEXT\");\n\n        DBSession.modifyColumnType(\"islands_warps\", \"name\", \"LONG_UNIQUE_TEXT\");\n    }\n\n    private void upgradePlayersTables() {\n        DBSession.modifyColumnType(\"players_missions\", \"name\", \"LONG_UNIQUE_TEXT\");\n    }\n\n    private void upgradeStackedBlocksTables() {\n        // Before v1.8.1.363, location column of stacked_blocks was limited to 30 chars.\n        // In order to make sure all tables keep the large number, we modify the column to 255-chars long\n        // each time the plugin attempts to create the table.\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/730\n        DBSession.modifyColumnType(\"stacked_blocks\", \"location\", \"LONG_UNIQUE_TEXT\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/AttributesRegistry.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\nimport java.util.EnumMap;\n\npublic abstract class AttributesRegistry<K extends Enum<K>> {\n\n    private final EnumMap<K, Object> fieldValues;\n\n    protected AttributesRegistry(Class<K> classType) {\n        fieldValues = new EnumMap<>(classType);\n    }\n\n    public AttributesRegistry<K> setValue(K field, Object value) {\n        fieldValues.put(field, value);\n        return this;\n    }\n\n    public <T> T getValue(K field) {\n        Object value = fieldValues.get(field);\n        // noinspection all\n        return (T) value;\n    }\n\n    public <T> T getValue(K field, Class<T> type) {\n        Object value = fieldValues.get(field);\n        // noinspection all\n        return type.cast(value);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/BankTransactionsAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class BankTransactionsAttributes extends AttributesRegistry<BankTransactionsAttributes.Field> {\n\n    public BankTransactionsAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public BankTransactionsAttributes setValue(Field field, Object value) {\n        return (BankTransactionsAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        ISLAND,\n        PLAYER,\n        BANK_ACTION,\n        POSITION,\n        TIME,\n        FAILURE_REASON,\n        AMOUNT\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/GridAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class GridAttributes extends AttributesRegistry<GridAttributes.Field> {\n\n    public GridAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public GridAttributes setValue(Field field, Object value) {\n        return (GridAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        LAST_ISLAND,\n        MAX_ISLAND_SIZE,\n        WORLD\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class IslandAttributes extends AttributesRegistry<IslandAttributes.Field> {\n\n    public IslandAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public IslandAttributes setValue(Field field, Object value) {\n        return (IslandAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        UUID,\n        OWNER,\n        CENTER,\n        CREATION_TIME,\n        ISLAND_TYPE,\n        DISCORD,\n        PAYPAL,\n        WORTH_BONUS,\n        LEVELS_BONUS,\n        LOCKED,\n        IGNORED,\n        NAME,\n        DESCRIPTION,\n        GENERATED_SCHEMATICS,\n        UNLOCKED_WORLDS,\n        LAST_TIME_UPDATED,\n        DIRTY_CHUNKS,\n        BLOCK_COUNTS,\n        HOMES,\n        MEMBERS,\n        BANS,\n        PLAYER_PERMISSIONS,\n        ROLE_PERMISSIONS,\n        UPGRADES,\n        WARPS,\n        BLOCK_LIMITS,\n        RATINGS,\n        MISSIONS,\n        ISLAND_FLAGS,\n        GENERATORS,\n        VISITORS,\n        ENTITY_LIMITS,\n        EFFECTS,\n        ISLAND_CHESTS,\n        ROLE_LIMITS,\n        WARP_CATEGORIES,\n        BANK_BALANCE,\n        BANK_LAST_INTEREST,\n        VISITOR_HOMES,\n        ISLAND_SIZE,\n        TEAM_LIMIT,\n        WARPS_LIMIT,\n        CROP_GROWTH_MULTIPLIER,\n        SPAWNER_RATES_MULTIPLIER,\n        MOB_DROPS_MULTIPLIER,\n        COOP_LIMIT,\n        BANK_LIMIT\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandChestAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class IslandChestAttributes extends AttributesRegistry<IslandChestAttributes.Field> {\n\n    public IslandChestAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public IslandChestAttributes setValue(Field field, Object value) {\n        return (IslandChestAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        INDEX,\n        CONTENTS\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandWarpAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class IslandWarpAttributes extends AttributesRegistry<IslandWarpAttributes.Field> {\n\n    public IslandWarpAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public IslandWarpAttributes setValue(Field field, Object value) {\n        return (IslandWarpAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        NAME,\n        CATEGORY,\n        LOCATION,\n        PRIVATE_STATUS,\n        ICON\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/PlayerAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class PlayerAttributes extends AttributesRegistry<PlayerAttributes.Field> {\n\n    public PlayerAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public PlayerAttributes setValue(Field field, Object value) {\n        return (PlayerAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        UUID,\n        ISLAND_LEADER,\n        LAST_USED_NAME,\n        LAST_USED_SKIN,\n        ISLAND_ROLE,\n        DISBANDS,\n        LAST_TIME_UPDATED,\n        COMPLETED_MISSIONS,\n        TOGGLED_PANEL,\n        ISLAND_FLY,\n        BORDER_COLOR,\n        LANGUAGE,\n        TOGGLED_BORDER\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/StackedBlockAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class StackedBlockAttributes extends AttributesRegistry<StackedBlockAttributes.Field> {\n\n    public StackedBlockAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public StackedBlockAttributes setValue(Field field, Object value) {\n        return (StackedBlockAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        LOCATION,\n        BLOCK_TYPE,\n        AMOUNT\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/WarpCategoryAttributes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes;\n\npublic class WarpCategoryAttributes extends AttributesRegistry<WarpCategoryAttributes.Field> {\n\n    public WarpCategoryAttributes() {\n        super(Field.class);\n    }\n\n    @Override\n    public WarpCategoryAttributes setValue(Field field, Object value) {\n        return (WarpCategoryAttributes) super.setValue(field, value);\n    }\n\n    public enum Field {\n\n        NAME,\n        SLOT,\n        ICON\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer;\n\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport org.bukkit.World;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class EmptyParameterGuardDeserializer implements IDeserializer {\n\n    private static final EmptyParameterGuardDeserializer INSTANCE = new EmptyParameterGuardDeserializer();\n\n    public static EmptyParameterGuardDeserializer getInstance() {\n        return INSTANCE;\n    }\n\n    private EmptyParameterGuardDeserializer() {\n\n    }\n\n    private static <T> T checkParam(String param, Supplier<T> emptyValue) {\n        if (Text.isBlank(param))\n            return emptyValue.get();\n\n        throw new RuntimeException(); // Will continue to other deserializers\n    }\n\n    @Override\n    public Map<String, Integer> deserializeMissions(String missions) {\n        return checkParam(missions, Collections::emptyMap);\n    }\n\n    @Override\n    public String[] deserializeHomes(String locationParam) {\n        return checkParam(locationParam, () -> new String[World.Environment.values().length]);\n    }\n\n    @Override\n    public List<PlayerAttributes> deserializePlayers(String players) {\n        return checkParam(players, Collections::emptyList);\n    }\n\n    @Override\n    public Map<UUID, PlayerPrivilegeNode> deserializePlayerPerms(String permissionNodes) {\n        return checkParam(permissionNodes, Collections::emptyMap);\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> deserializeRolePerms(String permissionNodes) {\n        return checkParam(permissionNodes, Collections::emptyMap);\n    }\n\n    @Override\n    public Map<String, Integer> deserializeUpgrades(String upgrades) {\n        return checkParam(upgrades, Collections::emptyMap);\n    }\n\n    @Override\n    public List<IslandWarpAttributes> deserializeWarps(String islandWarps) {\n        return checkParam(islandWarps, Collections::emptyList);\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeBlockLimits(String blocks) {\n        return checkParam(blocks, KeyMaps::createEmptyMap);\n    }\n\n    @Override\n    public Map<UUID, Rating> deserializeRatings(String ratings) {\n        return checkParam(ratings, Collections::emptyMap);\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> deserializeIslandFlags(String settings) {\n        return checkParam(settings, Collections::emptyMap);\n    }\n\n    @Override\n    public KeyMap<Integer>[] deserializeGenerators(String generator) {\n        return checkParam(generator, () -> new KeyMap[World.Environment.values().length]);\n    }\n\n    @Override\n    public List<Pair<UUID, Long>> deserializeVisitors(String visitors) {\n        return checkParam(visitors, Collections::emptyList);\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeEntityLimits(String entities) {\n        return checkParam(entities, KeyMaps::createEmptyMap);\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> deserializeEffects(String effects) {\n        return checkParam(effects, Collections::emptyMap);\n    }\n\n    @Override\n    public List<IslandChestAttributes> deserializeIslandChests(String islandChest) {\n        return checkParam(islandChest, Collections::emptyList);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> deserializeRoleLimits(String roles) {\n        return checkParam(roles, Collections::emptyMap);\n    }\n\n    @Override\n    public List<WarpCategoryAttributes> deserializeWarpCategories(String categories) {\n        return checkParam(categories, Collections::emptyList);\n    }\n\n    @Override\n    public String deserializeBlockCounts(String blockCountsParam) {\n        return checkParam(blockCountsParam, () -> \"[]\");\n    }\n\n    @Override\n    public String deserializeDirtyChunks(String dirtyChunksParam) {\n        return checkParam(dirtyChunksParam, () -> \"[]\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/IDeserializer.java",
    "content": " package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer;\n\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic interface IDeserializer {\n\n    Map<String, Integer> deserializeMissions(String missions);\n\n    String[] deserializeHomes(String locationParam);\n\n    List<PlayerAttributes> deserializePlayers(String players);\n\n    Map<UUID, PlayerPrivilegeNode> deserializePlayerPerms(String permissionNodes);\n\n    Map<IslandPrivilege, PlayerRole> deserializeRolePerms(String permissionNodes);\n\n    Map<String, Integer> deserializeUpgrades(String upgrades);\n\n    List<IslandWarpAttributes> deserializeWarps(String islandWarps);\n\n    KeyMap<Integer> deserializeBlockLimits(String blocks);\n\n    Map<UUID, Rating> deserializeRatings(String ratings);\n\n    Map<IslandFlag, Byte> deserializeIslandFlags(String settings);\n\n    KeyMap<Integer>[] deserializeGenerators(String generator);\n\n    List<Pair<UUID, Long>> deserializeVisitors(String visitors);\n\n    KeyMap<Integer> deserializeEntityLimits(String entities);\n\n    Map<PotionEffectType, Integer> deserializeEffects(String effects);\n\n    List<IslandChestAttributes> deserializeIslandChests(String islandChest);\n\n    Map<PlayerRole, Integer> deserializeRoleLimits(String roles);\n\n    List<WarpCategoryAttributes> deserializeWarpCategories(String categories);\n\n    String deserializeBlockCounts(String blockCountsParam);\n\n    String deserializeDirtyChunks(String dirtyChunksParam);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer;\n\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseConverter;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\nimport org.bukkit.World;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class JsonDeserializer implements IDeserializer {\n\n    public static final JsonDeserializer INSTANCE = new JsonDeserializer();\n\n    private static final Gson gson = new Gson();\n\n    private JsonDeserializer() {\n    }\n\n    public Map<String, Integer> deserializeMissions(String missions) {\n        Map<String, Integer> completedMissions = new HashMap<>();\n\n        JsonArray missionsArray = gson.fromJson(missions, JsonArray.class);\n        missionsArray.forEach(missionElement -> {\n            JsonObject missionObject = missionElement.getAsJsonObject();\n\n            String name = missionObject.get(\"name\").getAsString();\n            int finishCount = missionObject.get(\"finishCount\").getAsInt();\n\n            completedMissions.put(name, finishCount);\n        });\n\n        return completedMissions;\n    }\n\n    public String[] deserializeHomes(String locationParam) {\n        String[] locations = new String[World.Environment.values().length];\n\n        JsonArray locationsArray = gson.fromJson(locationParam, JsonArray.class);\n        locationsArray.forEach(locationElement -> {\n            JsonObject locationObject = locationElement.getAsJsonObject();\n            try {\n                int i = World.Environment.valueOf(locationObject.get(\"env\").getAsString()).ordinal();\n                locations[i] = locationObject.get(\"location\").getAsString();\n            } catch (Exception ignored) {\n            }\n        });\n\n        return locations;\n    }\n\n    public List<PlayerAttributes> deserializePlayers(String players) {\n        List<PlayerAttributes> playerAttributes = new LinkedList<>();\n        JsonArray playersArray = gson.fromJson(players, JsonArray.class);\n        playersArray.forEach(uuid -> {\n            PlayerAttributes _playerAttributes = DatabaseConverter.getPlayerAttributes(uuid.getAsString());\n            if (_playerAttributes != null)\n                playerAttributes.add(_playerAttributes);\n        });\n        return Collections.unmodifiableList(playerAttributes);\n    }\n\n    public Map<UUID, PlayerPrivilegeNode> deserializePlayerPerms(String permissionNodes) {\n        Map<UUID, PlayerPrivilegeNode> playerPermissions = new ArrayMap<>();\n\n        JsonObject globalObject = gson.fromJson(permissionNodes, JsonObject.class);\n        JsonArray playersArray = globalObject.getAsJsonArray(\"players\");\n\n        playersArray.forEach(playerElement -> {\n            JsonObject playerObject = playerElement.getAsJsonObject();\n            try {\n                UUID uuid = UUID.fromString(playerObject.get(\"uuid\").getAsString());\n                JsonArray permsArray = playerObject.getAsJsonArray(\"permissions\");\n                PlayerPrivilegeNode playerPermissionNode = new PlayerPrivilegeNode(null, null, \"\");\n                playerPermissions.put(uuid, playerPermissionNode);\n\n                for (JsonElement permElement : permsArray) {\n                    try {\n                        JsonObject permObject = permElement.getAsJsonObject();\n                        IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permObject.get(\"name\").getAsString());\n                        playerPermissionNode.setPermission(islandPrivilege, permObject.get(\"status\").getAsString().equals(\"1\"));\n                    } catch (Exception ignored) {\n                    }\n                }\n            } catch (Exception ignored) {\n            }\n        });\n\n        return playerPermissions;\n    }\n\n    public Map<IslandPrivilege, PlayerRole> deserializeRolePerms(String permissionNodes) {\n        Map<IslandPrivilege, PlayerRole> rolePermissions = new ArrayMap<>();\n\n        JsonObject globalObject = gson.fromJson(permissionNodes, JsonObject.class);\n        JsonArray rolesArray = globalObject.getAsJsonArray(\"roles\");\n\n        rolesArray.forEach(roleElement -> {\n            JsonObject roleObject = roleElement.getAsJsonObject();\n            PlayerRole playerRole = SPlayerRole.fromId(roleObject.get(\"id\").getAsInt());\n            roleObject.getAsJsonArray(\"permissions\").forEach(permElement -> {\n                try {\n                    IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permElement.getAsString());\n                    rolePermissions.put(islandPrivilege, playerRole);\n                } catch (Exception ignored) {\n                }\n            });\n        });\n\n        return rolePermissions;\n    }\n\n    public Map<String, Integer> deserializeUpgrades(String upgrades) {\n        Map<String, Integer> upgradesMap = new HashMap<>();\n\n        JsonArray upgradesArray = gson.fromJson(upgrades, JsonArray.class);\n        upgradesArray.forEach(upgradeElement -> {\n            JsonObject upgradeObject = upgradeElement.getAsJsonObject();\n            String name = upgradeObject.get(\"name\").getAsString();\n            int level = upgradeObject.get(\"level\").getAsInt();\n            upgradesMap.put(name, level);\n        });\n\n        return upgradesMap;\n    }\n\n    public List<IslandWarpAttributes> deserializeWarps(String islandWarps) {\n        List<IslandWarpAttributes> islandWarpList = new LinkedList<>();\n\n        JsonArray warpsArray = gson.fromJson(islandWarps, JsonArray.class);\n        warpsArray.forEach(warpElement -> {\n            JsonObject warpObject = warpElement.getAsJsonObject();\n            String name = warpObject.get(\"name\").getAsString();\n            String warpCategory = warpObject.get(\"category\").getAsString();\n            String location = warpObject.get(\"location\").getAsString();\n            boolean privateWarp = warpObject.get(\"private\").getAsInt() == 1;\n            String icon = warpObject.has(\"icon\") ? warpObject.get(\"icon\").getAsString() : \"\";\n\n            islandWarpList.add(new IslandWarpAttributes()\n                    .setValue(IslandWarpAttributes.Field.NAME, name)\n                    .setValue(IslandWarpAttributes.Field.CATEGORY, warpCategory)\n                    .setValue(IslandWarpAttributes.Field.LOCATION, location)\n                    .setValue(IslandWarpAttributes.Field.PRIVATE_STATUS, privateWarp)\n                    .setValue(IslandWarpAttributes.Field.ICON, icon));\n        });\n\n        return Collections.unmodifiableList(islandWarpList);\n    }\n\n    public KeyMap<Integer> deserializeBlockLimits(String blocks) {\n        KeyMap<Integer> blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n\n        JsonArray blockLimitsArray = gson.fromJson(blocks, JsonArray.class);\n        blockLimitsArray.forEach(blockLimitElement -> {\n            JsonObject blockLimitObject = blockLimitElement.getAsJsonObject();\n            Key blockKey = Keys.ofMaterialAndData(blockLimitObject.get(\"id\").getAsString());\n            int limit = blockLimitObject.get(\"limit\").getAsInt();\n            blockLimits.put(blockKey, limit);\n        });\n\n        return blockLimits;\n    }\n\n    public Map<UUID, Rating> deserializeRatings(String ratings) {\n        Map<UUID, Rating> ratingsMap = new ArrayMap<>();\n\n        JsonArray ratingsArray = gson.fromJson(ratings, JsonArray.class);\n        ratingsArray.forEach(ratingElement -> {\n            JsonObject ratingObject = ratingElement.getAsJsonObject();\n            try {\n                UUID uuid = UUID.fromString(ratingObject.get(\"player\").getAsString());\n                Rating rating = Rating.valueOf(ratingObject.get(\"rating\").getAsInt());\n                ratingsMap.put(uuid, rating);\n            } catch (Exception ignored) {\n            }\n        });\n\n        return ratingsMap;\n    }\n\n    public Map<IslandFlag, Byte> deserializeIslandFlags(String settings) {\n        Map<IslandFlag, Byte> islandFlags = new ArrayMap<>();\n\n        JsonArray islandFlagsArray = gson.fromJson(settings, JsonArray.class);\n        islandFlagsArray.forEach(islandFlagElement -> {\n            JsonObject islandFlagObject = islandFlagElement.getAsJsonObject();\n            try {\n                IslandFlag islandFlag = IslandFlag.getByName(islandFlagObject.get(\"name\").getAsString());\n                byte status = islandFlagObject.get(\"status\").getAsByte();\n                islandFlags.put(islandFlag, status);\n            } catch (Exception ignored) {\n            }\n        });\n\n        return islandFlags;\n    }\n\n    public KeyMap<Integer>[] deserializeGenerators(String generator) {\n        // noinspection all\n        KeyMap<Integer>[] cobbleGenerator = new KeyMap[World.Environment.values().length];\n\n        JsonArray generatorWorldsArray = gson.fromJson(generator, JsonArray.class);\n        generatorWorldsArray.forEach(generatorWorldElement -> {\n            JsonObject generatorWorldObject = generatorWorldElement.getAsJsonObject();\n            try {\n                int i = World.Environment.valueOf(generatorWorldObject.get(\"env\").getAsString()).ordinal();\n                generatorWorldObject.getAsJsonArray(\"rates\").forEach(generatorElement -> {\n                    JsonObject generatorObject = generatorElement.getAsJsonObject();\n                    Key blockKey = Keys.ofMaterialAndData(generatorObject.get(\"id\").getAsString());\n                    int rate = generatorObject.get(\"rate\").getAsInt();\n                    (cobbleGenerator[i] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL)).put(blockKey, rate);\n                });\n            } catch (Exception ignored) {\n            }\n        });\n\n        return cobbleGenerator;\n    }\n\n    public List<Pair<UUID, Long>> deserializeVisitors(String visitors) {\n        List<Pair<UUID, Long>> visitorsList = new LinkedList<>();\n\n        JsonArray playersArray = gson.fromJson(visitors, JsonArray.class);\n\n        playersArray.forEach(playerElement -> {\n            JsonObject playerObject = playerElement.getAsJsonObject();\n            try {\n                UUID uuid = UUID.fromString(playerObject.get(\"uuid\").getAsString());\n                long lastTimeRecorded = playerObject.get(\"lastTimeRecorded\").getAsLong();\n                visitorsList.add(new Pair<>(uuid, lastTimeRecorded));\n            } catch (Exception ignored) {\n            }\n        });\n\n        return Collections.unmodifiableList(visitorsList);\n    }\n\n    public KeyMap<Integer> deserializeEntityLimits(String entities) {\n        KeyMap<Integer> entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n        JsonArray entityLimitsArray = gson.fromJson(entities, JsonArray.class);\n        entityLimitsArray.forEach(entityLimitElement -> {\n            JsonObject entityLimitObject = entityLimitElement.getAsJsonObject();\n            Key entity = Keys.ofEntityType(entityLimitObject.get(\"id\").getAsString());\n            int limit = entityLimitObject.get(\"limit\").getAsInt();\n            entityLimits.put(entity, limit);\n        });\n\n        return entityLimits;\n    }\n\n    public Map<PotionEffectType, Integer> deserializeEffects(String effects) {\n        Map<PotionEffectType, Integer> islandEffects = new ArrayMap<>();\n\n        JsonArray effectsArray = gson.fromJson(effects, JsonArray.class);\n        effectsArray.forEach(effectElement -> {\n            JsonObject effectObject = effectElement.getAsJsonObject();\n            PotionEffectType potionEffectType = PotionEffectType.getByName(effectObject.get(\"type\").getAsString());\n            if (potionEffectType != null) {\n                int level = effectObject.get(\"level\").getAsInt();\n                islandEffects.put(potionEffectType, level);\n            }\n        });\n\n        return islandEffects;\n    }\n\n    public List<IslandChestAttributes> deserializeIslandChests(String islandChest) {\n        List<IslandChestAttributes> islandChestList = new LinkedList<>();\n\n        JsonArray islandChestsArray = gson.fromJson(islandChest, JsonArray.class);\n        islandChestsArray.forEach(islandChestElement -> {\n            JsonObject islandChestObject = islandChestElement.getAsJsonObject();\n            int index = islandChestObject.get(\"index\").getAsInt();\n            String contents = islandChestObject.get(\"contents\").getAsString();\n\n            islandChestList.add(new IslandChestAttributes()\n                    .setValue(IslandChestAttributes.Field.INDEX, index)\n                    .setValue(IslandChestAttributes.Field.CONTENTS, contents));\n        });\n\n        return Collections.unmodifiableList(islandChestList);\n    }\n\n    public Map<PlayerRole, Integer> deserializeRoleLimits(String roles) {\n        Map<PlayerRole, Integer> roleLimits = new ArrayMap<>();\n\n        JsonArray roleLimitsArray = gson.fromJson(roles, JsonArray.class);\n        roleLimitsArray.forEach(roleElement -> {\n            JsonObject roleObject = roleElement.getAsJsonObject();\n            PlayerRole playerRole = SPlayerRole.fromId(roleObject.get(\"id\").getAsInt());\n            if (playerRole != null) {\n                int limit = roleObject.get(\"limit\").getAsInt();\n                roleLimits.put(playerRole, limit);\n            }\n        });\n\n        return roleLimits;\n    }\n\n    public List<WarpCategoryAttributes> deserializeWarpCategories(String categories) {\n        List<WarpCategoryAttributes> warpCategories = new LinkedList<>();\n\n        JsonArray warpCategoriesArray = gson.fromJson(categories, JsonArray.class);\n        warpCategoriesArray.forEach(warpCategoryElement -> {\n            JsonObject warpCategoryObject = warpCategoryElement.getAsJsonObject();\n            String name = warpCategoryObject.get(\"name\").getAsString();\n            int slot = warpCategoryObject.get(\"slot\").getAsInt();\n            String icon = warpCategoryObject.get(\"icon\").getAsString();\n            warpCategories.add(new WarpCategoryAttributes()\n                    .setValue(WarpCategoryAttributes.Field.NAME, name)\n                    .setValue(WarpCategoryAttributes.Field.SLOT, slot)\n                    .setValue(WarpCategoryAttributes.Field.ICON, icon));\n        });\n\n        return Collections.unmodifiableList(warpCategories);\n    }\n\n    @Override\n    public String deserializeBlockCounts(String blockCountsParam) {\n        gson.fromJson(blockCountsParam, JsonArray.class);\n        return blockCountsParam;\n    }\n\n    @Override\n    public String deserializeDirtyChunks(String dirtyChunksParam) {\n        gson.fromJson(dirtyChunksParam, JsonObject.class);\n        return dirtyChunksParam;\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/MultipleDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer;\n\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Function;\n\npublic class MultipleDeserializer implements IDeserializer {\n\n    private final List<IDeserializer> deserializers;\n\n    public MultipleDeserializer(IDeserializer... deserializers) {\n        this.deserializers = Arrays.asList(deserializers);\n    }\n\n    private <T> T runDeserializers(Function<IDeserializer, T> function) {\n        for (IDeserializer deserializer : deserializers) {\n            try {\n                return function.apply(deserializer);\n            } catch (Exception ignored) {\n            }\n        }\n\n        throw new RuntimeException(\"No valid deserializer found.\");\n    }\n\n    @Override\n    public Map<String, Integer> deserializeMissions(String missions) {\n        return runDeserializers(deserializer -> deserializer.deserializeMissions(missions));\n    }\n\n    @Override\n    public String[] deserializeHomes(String locationParam) {\n        return runDeserializers(deserializer -> deserializer.deserializeHomes(locationParam));\n    }\n\n    @Override\n    public List<PlayerAttributes> deserializePlayers(String players) {\n        return runDeserializers(deserializer -> deserializer.deserializePlayers(players));\n    }\n\n    @Override\n    public Map<UUID, PlayerPrivilegeNode> deserializePlayerPerms(String permissionNodes) {\n        return runDeserializers(deserializer -> deserializer.deserializePlayerPerms(permissionNodes));\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> deserializeRolePerms(String permissionNodes) {\n        return runDeserializers(deserializer -> deserializer.deserializeRolePerms(permissionNodes));\n    }\n\n    @Override\n    public Map<String, Integer> deserializeUpgrades(String upgrades) {\n        return runDeserializers(deserializer -> deserializer.deserializeUpgrades(upgrades));\n    }\n\n    @Override\n    public List<IslandWarpAttributes> deserializeWarps(String islandWarps) {\n        return runDeserializers(deserializer -> deserializer.deserializeWarps(islandWarps));\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeBlockLimits(String blocks) {\n        return runDeserializers(deserializer -> deserializer.deserializeBlockLimits(blocks));\n    }\n\n    @Override\n    public Map<UUID, Rating> deserializeRatings(String ratings) {\n        return runDeserializers(deserializer -> deserializer.deserializeRatings(ratings));\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> deserializeIslandFlags(String settings) {\n        return runDeserializers(deserializer -> deserializer.deserializeIslandFlags(settings));\n    }\n\n    @Override\n    public KeyMap<Integer>[] deserializeGenerators(String generator) {\n        return runDeserializers(deserializer -> deserializer.deserializeGenerators(generator));\n    }\n\n    @Override\n    public List<Pair<UUID, Long>> deserializeVisitors(String visitors) {\n        return runDeserializers(deserializer -> deserializer.deserializeVisitors(visitors));\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeEntityLimits(String entities) {\n        return runDeserializers(deserializer -> deserializer.deserializeEntityLimits(entities));\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> deserializeEffects(String effects) {\n        return runDeserializers(deserializer -> deserializer.deserializeEffects(effects));\n    }\n\n    @Override\n    public List<IslandChestAttributes> deserializeIslandChests(String islandChest) {\n        return runDeserializers(deserializer -> deserializer.deserializeIslandChests(islandChest));\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> deserializeRoleLimits(String roles) {\n        return runDeserializers(deserializer -> deserializer.deserializeRoleLimits(roles));\n    }\n\n    @Override\n    public List<WarpCategoryAttributes> deserializeWarpCategories(String categories) {\n        return runDeserializers(deserializer -> deserializer.deserializeWarpCategories(categories));\n    }\n\n    @Override\n    public String deserializeBlockCounts(String blockCountsParam) {\n        return runDeserializers(deserializer -> deserializer.deserializeBlockCounts(blockCountsParam));\n    }\n\n    @Override\n    public String deserializeDirtyChunks(String dirtyChunksParam) {\n        return runDeserializers(deserializer -> deserializer.deserializeDirtyChunks(dirtyChunksParam));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.DirtyChunk;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseConverter;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes;\nimport com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.World;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class RawDeserializer implements IDeserializer {\n\n    public static final RawDeserializer INSTANCE = new RawDeserializer();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private RawDeserializer() {\n    }\n\n    @Override\n    public Map<String, Integer> deserializeMissions(String missions) {\n        Map<String, Integer> completedMissions = new HashMap<>();\n\n        if (missions != null) {\n            for (String mission : missions.split(\";\")) {\n                String[] missionSections = mission.split(\"=\");\n                int completeAmount = missionSections.length > 1 ? Integer.parseInt(missionSections[1]) : 1;\n                completedMissions.put(missionSections[0], completeAmount);\n            }\n        }\n\n        return completedMissions;\n    }\n\n    @Override\n    public String[] deserializeHomes(String locationParam) {\n        String[] islandHomes = new String[World.Environment.values().length];\n\n        if (locationParam == null)\n            return islandHomes;\n\n        String _locationParam = locationParam.contains(\"=\") ? locationParam : \"normal=\" + locationParam;\n\n        for (String worldSection : _locationParam.split(\";\")) {\n            try {\n                String[] locationSection = worldSection.split(\"=\");\n                String environment = locationSection[0].toUpperCase(Locale.ENGLISH);\n                islandHomes[World.Environment.valueOf(environment).ordinal()] = locationSection[1];\n            } catch (Exception ignored) {\n            }\n        }\n\n        return islandHomes;\n    }\n\n    @Override\n    public List<PlayerAttributes> deserializePlayers(String players) {\n        List<PlayerAttributes> playerAttributesList = new LinkedList<>();\n\n        if (players != null) {\n            for (String uuid : players.split(\",\")) {\n                try {\n                    PlayerAttributes playerAttributes = DatabaseConverter.getPlayerAttributes(uuid);\n                    if (playerAttributes != null)\n                        playerAttributesList.add(playerAttributes);\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return Collections.unmodifiableList(playerAttributesList);\n    }\n\n    @Override\n    public Map<UUID, PlayerPrivilegeNode> deserializePlayerPerms(String permissionNodes) {\n        Map<UUID, PlayerPrivilegeNode> playerPermissions = new ArrayMap<>();\n\n        if (permissionNodes == null)\n            return playerPermissions;\n\n        for (String entry : permissionNodes.split(\",\")) {\n            try {\n                String[] sections = entry.split(\"=\");\n\n                try {\n                    try {\n                        int id = Integer.parseInt(sections[0]);\n                        SPlayerRole.fromId(id);\n                    } catch (Exception ex) {\n                        SPlayerRole.of(sections[0]);\n                    }\n                } catch (Exception ex) {\n                    playerPermissions.put(UUID.fromString(sections[0]), new PlayerPrivilegeNode(null,\n                            null, sections.length == 1 ? \"\" : sections[1]));\n                }\n            } catch (Exception ignored) {\n            }\n        }\n\n        return playerPermissions;\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> deserializeRolePerms(String permissionNodes) {\n        Map<IslandPrivilege, PlayerRole> rolePermissions = new ArrayMap<>();\n\n        if (permissionNodes == null)\n            return rolePermissions;\n\n        for (String entry : permissionNodes.split(\",\")) {\n            try {\n                String[] sections = entry.split(\"=\");\n\n                PlayerRole playerRole;\n\n                try {\n                    int id = Integer.parseInt(sections[0]);\n                    playerRole = SPlayerRole.fromId(id);\n                } catch (Exception ex) {\n                    playerRole = SPlayerRole.of(sections[0]);\n                }\n\n                if (sections.length != 1) {\n                    String[] permission = sections[1].split(\";\");\n                    for (String perm : permission) {\n                        String[] permissionSections = perm.split(\":\");\n                        try {\n                            IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permissionSections[0]);\n                            if (permissionSections.length == 2 && permissionSections[1].equals(\"1\")) {\n                                rolePermissions.put(islandPrivilege, playerRole);\n                            }\n                        } catch (Exception ignored) {\n                        }\n                    }\n                }\n            } catch (Exception ignored) {\n            }\n        }\n\n        return rolePermissions;\n    }\n\n    @Override\n    public Map<String, Integer> deserializeUpgrades(String upgrades) {\n        Map<String, Integer> upgradesMap = new HashMap<>();\n\n        if (upgrades != null) {\n            for (String entry : upgrades.split(\",\")) {\n                try {\n                    String[] sections = entry.split(\"=\");\n                    upgradesMap.put(sections[0], Integer.parseInt(sections[1]));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return upgradesMap;\n    }\n\n    @Override\n    public List<IslandWarpAttributes> deserializeWarps(String islandWarps) {\n        List<IslandWarpAttributes> warpAttributes = new LinkedList<>();\n\n        if (islandWarps == null)\n            return warpAttributes;\n\n        for (String entry : islandWarps.split(\";\")) {\n            try {\n                String[] sections = entry.split(\"=\");\n                String name = Formatters.STRIP_COLOR_FORMATTER.format(sections[0].trim());\n                String category = \"\";\n                boolean privateFlag = sections.length == 3 && Boolean.parseBoolean(sections[2]);\n\n                if (name.contains(\"-\")) {\n                    String[] nameSections = name.split(\"-\");\n                    category = nameSections[0];\n                    name = nameSections[1];\n                }\n\n                if (name.isEmpty())\n                    continue;\n\n                if (!IslandUtils.isWarpNameLengthValid(name))\n                    name = name.substring(0, IslandUtils.getMaxWarpNameLength());\n\n                if (!IslandUtils.isWarpNameLengthValid(category))\n                    category = category.substring(0, IslandUtils.getMaxWarpNameLength());\n\n                warpAttributes.add(new IslandWarpAttributes()\n                        .setValue(IslandWarpAttributes.Field.NAME, name)\n                        .setValue(IslandWarpAttributes.Field.CATEGORY, category)\n                        .setValue(IslandWarpAttributes.Field.LOCATION, sections[1])\n                        .setValue(IslandWarpAttributes.Field.PRIVATE_STATUS, privateFlag)\n                        .setValue(IslandWarpAttributes.Field.ICON, sections[3]));\n            } catch (Exception ignored) {\n            }\n        }\n\n        return Collections.unmodifiableList(warpAttributes);\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeBlockLimits(String blocks) {\n        KeyMap<Integer> blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n\n        if (blocks != null) {\n            for (String limit : blocks.split(\",\")) {\n                try {\n                    String[] sections = limit.split(\"=\");\n                    blockLimits.put(Keys.ofMaterialAndData(sections[0]), Integer.parseInt(sections[1]));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return blockLimits;\n    }\n\n    @Override\n    public Map<UUID, Rating> deserializeRatings(String ratings) {\n        Map<UUID, Rating> ratingsMap = new ArrayMap<>();\n\n        if (ratings != null) {\n            for (String entry : ratings.split(\";\")) {\n                try {\n                    String[] sections = entry.split(\"=\");\n                    ratingsMap.put(UUID.fromString(sections[0]), Rating.valueOf(Integer.parseInt(sections[1])));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return ratingsMap;\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> deserializeIslandFlags(String settings) {\n        Map<IslandFlag, Byte> islandSettings = new ArrayMap<>();\n\n        if (settings != null) {\n            for (String setting : settings.split(\";\")) {\n                try {\n                    if (setting.contains(\"=\")) {\n                        String[] settingSections = setting.split(\"=\");\n                        islandSettings.put(IslandFlag.getByName(settingSections[0]), Byte.valueOf(settingSections[1]));\n                    } else {\n                        if (!plugin.getSettings().getDefaultSettings().contains(setting))\n                            islandSettings.put(IslandFlag.getByName(setting), (byte) 1);\n                    }\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return islandSettings;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public KeyMap<Integer>[] deserializeGenerators(String generator) {\n        KeyMap<Integer>[] cobbleGenerator = new KeyMap[World.Environment.values().length];\n\n        if (generator == null)\n            return cobbleGenerator;\n\n        if (generator.contains(\";\")) {\n            for (String env : generator.split(\";\")) {\n                String[] sections = env.split(\":\");\n                try {\n                    World.Environment environment = World.Environment.valueOf(sections[0]);\n                    deserializeGenerators(sections[1], cobbleGenerator[environment.ordinal()] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL));\n                } catch (Exception ignored) {\n                }\n            }\n        } else {\n            deserializeGenerators(generator, cobbleGenerator[0] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL));\n        }\n\n        return cobbleGenerator;\n    }\n\n    @Override\n    public List<Pair<UUID, Long>> deserializeVisitors(String visitorsRaw) {\n        List<Pair<UUID, Long>> visitors = new LinkedList<>();\n\n        if (visitorsRaw != null) {\n            for (String visitor : visitorsRaw.split(\",\")) {\n                try {\n                    String[] visitorSections = visitor.split(\";\");\n                    long lastTimeJoined = visitorSections.length == 2 ? Long.parseLong(visitorSections[1]) : System.currentTimeMillis();\n                    visitors.add(new Pair<>(UUID.fromString(visitorSections[0]), lastTimeJoined));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return Collections.unmodifiableList(visitors);\n    }\n\n    @Override\n    public KeyMap<Integer> deserializeEntityLimits(String entities) {\n        KeyMap<Integer> entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n\n        if (entities != null) {\n            for (String limit : entities.split(\",\")) {\n                try {\n                    String[] sections = limit.split(\"=\");\n                    entityLimits.put(Keys.ofEntityType(sections[0]), Integer.parseInt(sections[1]));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return entityLimits;\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> deserializeEffects(String effects) {\n        Map<PotionEffectType, Integer> islandEffects = new ArrayMap<>();\n\n        if (effects != null) {\n            for (String effect : effects.split(\",\")) {\n                String[] sections = effect.split(\"=\");\n                PotionEffectType potionEffectType = PotionEffectType.getByName(sections[0]);\n                if (potionEffectType != null)\n                    islandEffects.put(potionEffectType, Integer.parseInt(sections[1]));\n            }\n        }\n\n        return islandEffects;\n    }\n\n    @Override\n    public List<IslandChestAttributes> deserializeIslandChests(String islandChest) {\n        List<IslandChestAttributes> islandChestAttributes = new LinkedList<>();\n\n        if (Text.isBlank(islandChest))\n            return islandChestAttributes;\n\n        String[] islandChestsSections = islandChest.split(\"\\n\");\n\n        for (int i = 0; i < islandChestsSections.length; i++) {\n            islandChestAttributes.add(new IslandChestAttributes()\n                    .setValue(IslandChestAttributes.Field.INDEX, i)\n                    .setValue(IslandChestAttributes.Field.CONTENTS, islandChestsSections[i]));\n        }\n\n        return Collections.unmodifiableList(islandChestAttributes);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> deserializeRoleLimits(String roles) {\n        Map<PlayerRole, Integer> roleLimits = new ArrayMap<>();\n\n        if (roles != null) {\n            for (String limit : roles.split(\",\")) {\n                try {\n                    String[] sections = limit.split(\"=\");\n                    PlayerRole playerRole = SPlayerRole.fromId(Integer.parseInt(sections[0]));\n                    if (playerRole != null)\n                        roleLimits.put(playerRole, Integer.parseInt(sections[1]));\n                } catch (Exception ignored) {\n                }\n            }\n        }\n\n        return roleLimits;\n    }\n\n    @Override\n    public List<WarpCategoryAttributes> deserializeWarpCategories(String categories) {\n        List<WarpCategoryAttributes> warpCategoryAttributes = new LinkedList<>();\n\n        if (categories == null)\n            return warpCategoryAttributes;\n\n        for (String entry : categories.split(\";\")) {\n            try {\n                String[] sections = entry.split(\"=\");\n                String name = Formatters.STRIP_COLOR_FORMATTER.format(sections[0].trim());\n                int slot = Integer.parseInt(sections[1]);\n                String icon = sections[2];\n\n                warpCategoryAttributes.add(new WarpCategoryAttributes()\n                        .setValue(WarpCategoryAttributes.Field.NAME, name)\n                        .setValue(WarpCategoryAttributes.Field.SLOT, slot)\n                        .setValue(WarpCategoryAttributes.Field.ICON, icon));\n            } catch (Exception ignored) {\n            }\n        }\n\n        return Collections.unmodifiableList(warpCategoryAttributes);\n    }\n\n    @Override\n    public String deserializeBlockCounts(String blockCountsParam) {\n        KeyMap<BigInteger> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n\n        if (blockCountsParam != null) {\n            for (String blockCountSection : blockCountsParam.split(\";\")) {\n                String[] blockCountSections = blockCountSection.split(\"=\");\n                try {\n                    blockCounts.put(Keys.ofMaterialAndData(blockCountSections[0]), new BigInteger(blockCountSections[1]));\n                } catch (NumberFormatException ignored) {\n                }\n            }\n        }\n\n        return IslandsSerializer.serializeBlockCounts(blockCounts);\n    }\n\n    @Override\n    public String deserializeDirtyChunks(String dirtyChunksParam) {\n        List<DirtyChunk> dirtyChunks = new LinkedList<>();\n\n        if (dirtyChunksParam != null) {\n            if (dirtyChunksParam.contains(\"|\")) {\n                String[] serializedSections = dirtyChunksParam.split(\"\\\\|\");\n\n                for (String section : serializedSections) {\n                    String[] worldSections = section.split(\"=\");\n                    if (worldSections.length == 2) {\n                        String[] dirtyChunkSections = worldSections[1].split(\";\");\n                        for (String dirtyChunk : dirtyChunkSections) {\n                            String[] dirtyChunkSection = dirtyChunk.split(\",\");\n                            if (dirtyChunkSection.length == 2) {\n                                dirtyChunks.add(new DirtyChunk(worldSections[0], Integer.parseInt(dirtyChunkSection[0]),\n                                        Integer.parseInt(dirtyChunkSection[1])));\n                            }\n                        }\n                    }\n                }\n            } else {\n                String[] dirtyChunkSections = dirtyChunksParam.split(\";\");\n                for (String dirtyChunk : dirtyChunkSections) {\n                    String[] dirtyChunkSection = dirtyChunk.split(\",\");\n                    if (dirtyChunkSection.length == 3) {\n                        dirtyChunks.add(new DirtyChunk(dirtyChunkSection[0], Integer.parseInt(dirtyChunkSection[1]),\n                                Integer.parseInt(dirtyChunkSection[2])));\n                    }\n                }\n            }\n        }\n\n        return IslandsSerializer.serializeDirtyChunks(dirtyChunks);\n    }\n\n    private void deserializeGenerators(String generator, KeyMap<Integer> cobbleGenerator) {\n        for (String limit : generator.split(\",\")) {\n            try {\n                String[] sections = limit.split(\"=\");\n                cobbleGenerator.put(Keys.ofMaterialAndData(sections[0]), Integer.parseInt(sections[1]));\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1;\n\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\n\npublic class DatabaseUpgrade_V1 implements Runnable {\n\n    public static final DatabaseUpgrade_V1 INSTANCE = new DatabaseUpgrade_V1();\n\n    private DatabaseUpgrade_V1() {\n\n    }\n\n    @Override\n    public void run() {\n        DBSession.addColumn(\"islands\", \"entity_counts\", \"LONGTEXT\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2;\n\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge;\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.sql.ResultSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\npublic class DatabaseUpgrade_V2 implements Runnable {\n\n    public static final DatabaseUpgrade_V2 INSTANCE = new DatabaseUpgrade_V2();\n\n    private DatabaseUpgrade_V2() {\n\n    }\n\n    @Override\n    public void run() {\n        // Update all item stacks saved to DB to the new serialization\n        updateWarpsIcons();\n        updateWarpCategoriesIcons();\n        updateIslandChests();\n    }\n\n    private static void updateWarpsIcons() {\n        List<DatabaseItem> warpIcons = new LinkedList<>();\n\n        MutableBoolean isFailed = new MutableBoolean(false);\n\n        DBSession.select(\"islands_warps\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet));\n\n                String island = databaseResult.getString(\"island\").orElse(null);\n                if (island == null)\n                    continue;\n\n                String name = databaseResult.getString(\"name\").orElse(null);\n                if (name == null)\n                    continue;\n\n                String serializedIcon = databaseResult.getString(\"icon\").orElse(null);\n                if (serializedIcon == null)\n                    continue;\n\n                ItemStack icon = Serializers.ITEM_STACK_SERIALIZER.deserialize(serializedIcon);\n                warpIcons.add(new DatabaseItem(icon, island, name));\n            }\n        }).onFail(error -> isFailed.set(true)));\n\n        if (isFailed.get())\n            return;\n\n        CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction(\n                \"UPDATE {prefix}islands_warps SET icon=? WHERE island=? AND name=?\");\n        updateManyItems(warpIcons, updateTransaction);\n    }\n\n    private static void updateWarpCategoriesIcons() {\n        List<DatabaseItem> categoryIcons = new LinkedList<>();\n\n        MutableBoolean isFailed = new MutableBoolean(false);\n\n        DBSession.select(\"islands_warp_categories\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet));\n\n                String island = databaseResult.getString(\"island\").orElse(null);\n                if (island == null)\n                    continue;\n\n                String name = databaseResult.getString(\"name\").orElse(null);\n                if (name == null)\n                    continue;\n\n                String serializedIcon = databaseResult.getString(\"icon\").orElse(null);\n                if (serializedIcon == null)\n                    continue;\n\n                ItemStack icon = Serializers.ITEM_STACK_SERIALIZER.deserialize(serializedIcon);\n                categoryIcons.add(new DatabaseItem(icon, island, name));\n            }\n        }).onFail(error -> isFailed.set(true)));\n\n        if (isFailed.get())\n            return;\n\n        CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction(\n                \"UPDATE {prefix}islands_warp_categories SET icon=? WHERE island=? AND name=?\");\n        updateManyItems(categoryIcons, updateTransaction);\n    }\n\n    private static void updateIslandChests() {\n        List<DatabaseChest> islandContents = new LinkedList<>();\n\n        MutableBoolean isFailed = new MutableBoolean(false);\n\n        DBSession.select(\"islands_chests\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet));\n\n                String island = databaseResult.getString(\"island\").orElse(null);\n                if (island == null)\n                    continue;\n\n                Integer index = databaseResult.getInt(\"index\").orElse(null);\n                if (index == null)\n                    continue;\n\n                byte[] serializedContents = databaseResult.getBlob(\"contents\").orElse(null);\n                if (serializedContents == null)\n                    continue;\n\n                ItemStack[] contents = Serializers.INVENTORY_SERIALIZER.deserialize(serializedContents);\n                islandContents.add(new DatabaseChest(island, index, contents));\n            }\n        }).onFail(error -> isFailed.set(true)));\n\n        if (isFailed.get())\n            return;\n\n        CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction(\n                \"UPDATE {prefix}islands_chests SET contents=? WHERE island=? AND `index`=?\");\n\n        for (DatabaseChest chestData : islandContents) {\n            updateTransaction\n                    .bindObject(Serializers.INVENTORY_SERIALIZER.serialize(chestData.contents))\n                    .bindObject(chestData.island)\n                    .bindObject(chestData.index)\n                    .newBatch();\n        }\n\n        try {\n            DBSession.execute(updateTransaction).get();\n        } catch (InterruptedException | ExecutionException ignored) {\n        }\n    }\n\n    private static void updateManyItems(List<DatabaseItem> items,\n                                        CustomSQLDatabaseTransaction updateTransaction) {\n        for (DatabaseItem iconData : items) {\n            updateTransaction\n                    .bindObject(Serializers.ITEM_STACK_SERIALIZER.serialize(iconData.itemStack))\n                    .bindObject(iconData.island)\n                    .bindObject(iconData.identifier)\n                    .newBatch();\n        }\n\n        try {\n            DBSession.execute(updateTransaction).get();\n        } catch (InterruptedException | ExecutionException ignored) {\n        }\n    }\n\n    private static class DatabaseItem {\n\n        private final ItemStack itemStack;\n        private final String island;\n        private final String identifier;\n\n        DatabaseItem(ItemStack itemStack, String island, String identifier) {\n            this.itemStack = itemStack;\n            this.island = island;\n            this.identifier = identifier;\n        }\n\n    }\n\n    private static class DatabaseChest {\n\n        private final String island;\n        private final int index;\n        private final ItemStack[] contents;\n\n        DatabaseChest(String island, int index, ItemStack[] contents) {\n            this.island = island;\n            this.index = index;\n            this.contents = contents;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3;\n\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.sql.DBSession;\nimport com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\n\nimport java.sql.ResultSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\n\npublic class DatabaseUpgrade_V3 implements Runnable {\n\n    public static final DatabaseUpgrade_V3 INSTANCE = new DatabaseUpgrade_V3();\n\n    private DatabaseUpgrade_V3() {\n\n    }\n\n    @Override\n    public void run() {\n        List<DatabaseItem> itemsToUpdate = new LinkedList<>();\n\n        MutableBoolean isFailed = new MutableBoolean(false);\n\n        DBSession.select(\"islands\", \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet));\n\n                String uuid = databaseResult.getString(\"uuid\").orElse(null);\n                if (uuid == null)\n                    continue;\n\n                Integer generatedSchematics = databaseResult.getInt(\"generated_schematics\").orElse(null);\n                if (generatedSchematics == null)\n                    continue;\n\n                Integer unlockedWorlds = databaseResult.getInt(\"unlocked_worlds\").orElse(null);\n                if (unlockedWorlds == null)\n                    continue;\n\n                itemsToUpdate.add(new DatabaseItem(uuid, convertGeneratedSchematicsMask(generatedSchematics),\n                        convertUnlockedWorldsMask(unlockedWorlds)));\n            }\n        }).onFail(error -> isFailed.set(true)));\n\n        if (isFailed.get())\n            return;\n\n        DBSession.modifyColumnType(\"islands\", \"generated_schematics\", \"TEXT\");\n        DBSession.modifyColumnType(\"islands\", \"unlocked_worlds\", \"TEXT\");\n\n        CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction(\n                \"UPDATE {prefix}islands SET generated_schematics=?,unlocked_worlds=? WHERE uuid=?\");\n        updateManyItems(itemsToUpdate, updateTransaction);\n    }\n\n    private static String convertGeneratedSchematicsMask(int generatedSchematicsMask) {\n        StringBuilder generatedSchematics = new StringBuilder();\n\n        if ((generatedSchematicsMask & 8) == 8)\n            generatedSchematics.append(\",NORMAL\");\n\n        if ((generatedSchematicsMask & 4) == 4)\n            generatedSchematics.append(\",NETHER\");\n\n        if ((generatedSchematicsMask & 3) == 3)\n            generatedSchematics.append(\",THE_END\");\n\n        return generatedSchematics.length() == 0 ? generatedSchematics.toString() : generatedSchematics.substring(1);\n    }\n\n    private static String convertUnlockedWorldsMask(int unlockedWorldsMask) {\n        StringBuilder unlockedWorlds = new StringBuilder();\n\n        if ((unlockedWorldsMask & 4) == 4)\n            unlockedWorlds.append(\",NORMAL\");\n\n        if ((unlockedWorldsMask & 1) == 1)\n            unlockedWorlds.append(\",NETHER\");\n\n        if ((unlockedWorldsMask & 2) == 2)\n            unlockedWorlds.append(\",THE_END\");\n\n        return unlockedWorlds.length() == 0 ? unlockedWorlds.toString() : unlockedWorlds.substring(1);\n    }\n\n    private static void updateManyItems(List<DatabaseItem> items, CustomSQLDatabaseTransaction updateTransaction) {\n        for (DatabaseItem item : items) {\n            updateTransaction\n                    .bindObject(item.generatedWorlds)\n                    .bindObject(item.unlockedWorlds)\n                    .bindObject(item.uuid)\n                    .newBatch();\n        }\n\n        try {\n            DBSession.execute(updateTransaction).get();\n        } catch (InterruptedException | ExecutionException ignored) {\n        }\n    }\n\n    private static class DatabaseItem {\n\n        private final String uuid;\n        private final String generatedWorlds;\n        private final String unlockedWorlds;\n\n        DatabaseItem(String uuid, String generatedWorlds, String unlockedWorlds) {\n            this.uuid = uuid;\n            this.generatedWorlds = generatedWorlds;\n            this.unlockedWorlds = unlockedWorlds;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.serialization;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.bank.SBankTransaction;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\npublic class IslandsDeserializer {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Gson GSON = new GsonBuilder().create();\n    private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2);\n    private static final int SYNCED_VALUE = -2;\n\n    private IslandsDeserializer() {\n\n    }\n\n    public static void deserializeMembers(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_members\", membersRow -> {\n            DatabaseResult members = new DatabaseResult(membersRow);\n\n            Optional<UUID> uuid = members.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island members for null islands, skipping...\");\n                return;\n            }\n\n            Optional<UUID> playerUUID = members.getUUID(\"player\");\n            if (!playerUUID.isPresent()) {\n                Log.warn(\"Cannot load island members with invalid uuids for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false);\n            if (superiorPlayer == null) {\n                Log.warn(\"Cannot load island member with unrecognized uuid: \" + playerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_members\");\n\n            PlayerRole playerRole = members.getInt(\"role\").map(SPlayerRole::fromId)\n                    .orElse(SPlayerRole.defaultRole());\n\n            superiorPlayer.setPlayerRole(playerRole);\n            builder.addIslandMember(superiorPlayer);\n        });\n    }\n\n    public static void deserializeBanned(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_bans\", bansRow -> {\n            DatabaseResult bans = new DatabaseResult(bansRow);\n\n            Optional<UUID> uuid = bans.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load banned players for null islands, skipping...\");\n                return;\n            }\n\n            Optional<UUID> playerUUID = bans.getUUID(\"player\");\n            if (!playerUUID.isPresent()) {\n                Log.warn(\"Cannot load banned players with invalid uuids for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false);\n            if (superiorPlayer == null) {\n                Log.warn(\"Cannot load island ban with unrecognized uuid: \" + playerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_bans\");\n            builder.addBannedPlayer(superiorPlayer);\n        });\n    }\n\n    public static void deserializeVisitors(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_visitors\", visitorsRow -> {\n            DatabaseResult visitors = new DatabaseResult(visitorsRow);\n\n            Optional<UUID> uuid = visitors.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island visitors for null islands, skipping...\");\n                return;\n            }\n\n            Optional<UUID> playerUUID = visitors.getUUID(\"player\");\n            if (!playerUUID.isPresent()) {\n                Log.warn(\"Cannot load island visitors with invalid uuids for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            SuperiorPlayer visitorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false);\n            if (visitorPlayer == null) {\n                Log.warn(\"Cannot load island visitor with unrecognized uuid: \" + playerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_visitors\");\n            long visitTime = visitors.getLong(\"visit_time\").orElse(System.currentTimeMillis());\n            builder.addUniqueVisitor(visitorPlayer, visitTime);\n        });\n    }\n\n    public static void deserializePlayerPermissions(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_player_permissions\", playerPermissionRow -> {\n            DatabaseResult playerPermissions = new DatabaseResult(playerPermissionRow);\n\n            Optional<UUID> uuid = playerPermissions.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load player permissions for null islands, skipping...\");\n                return;\n            }\n\n            Optional<UUID> playerUUID = playerPermissions.getUUID(\"player\");\n            if (!playerUUID.isPresent()) {\n                Log.warn(\"Cannot load player permissions for invalid players on \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false);\n            if (superiorPlayer == null) {\n                Log.warn(\"Cannot load island player permissions with unrecognized uuid: \" + playerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            IslandPrivilege islandPrivilege = playerPermissions.getString(\"permission\").map(name -> {\n                try {\n                    return IslandPrivilege.getByName(name);\n                } catch (NullPointerException error) {\n                    IslandPrivilege.register(name);\n                    return IslandPrivilege.getByName(name);\n                }\n            }).orElseThrow(IllegalStateException::new);\n\n            Optional<Byte> status = playerPermissions.getByte(\"status\");\n            if (!status.isPresent()) {\n                Log.warn(\"Cannot load player permissions with invalid status for player \", playerUUID.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_player_permissions\");\n            builder.setPlayerPermission(superiorPlayer, islandPrivilege, status.get() == 1);\n        });\n    }\n\n    public static void deserializeRolePermissions(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_role_permissions\", rolePermissionsRow -> {\n            DatabaseResult rolePermissions = new DatabaseResult(rolePermissionsRow);\n\n            Optional<UUID> uuid = rolePermissions.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load role permissions for null islands, skipping...\");\n                return;\n            }\n\n            Optional<PlayerRole> playerRole = rolePermissions.getInt(\"role\").map(SPlayerRole::fromId);\n            if (!playerRole.isPresent()) {\n                Log.warn(\"Cannot load role permissions with invalid role for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            IslandPrivilege islandPrivilege = rolePermissions.getString(\"permission\").map(name -> {\n                try {\n                    return IslandPrivilege.getByName(name);\n                } catch (NullPointerException error) {\n                    IslandPrivilege.register(name);\n                    return IslandPrivilege.getByName(name);\n                }\n            }).orElseThrow(IllegalStateException::new);\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_role_permissions\");\n            builder.setRolePermission(islandPrivilege, playerRole.get());\n        });\n    }\n\n    public static void deserializeUpgrades(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_upgrades\", upgradesRow -> {\n            DatabaseResult upgrades = new DatabaseResult(upgradesRow);\n\n            Optional<UUID> uuid = upgrades.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load upgrades for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Upgrade> upgrade = upgrades.getString(\"upgrade\").map(plugin.getUpgrades()::getUpgrade);\n            if (!upgrade.isPresent()) {\n                Log.warn(\"Cannot load upgrades with invalid upgrade names for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> level = upgrades.getInt(\"level\");\n            if (!level.isPresent()) {\n                Log.warn(\"Cannot load upgrades with invalid levels for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_upgrades\");\n            builder.setUpgrade(upgrade.get(), level.get());\n        });\n    }\n\n    public static void deserializeWarps(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_warps\", islandWarpsRow -> {\n            DatabaseResult islandWarp = new DatabaseResult(islandWarpsRow);\n\n            Optional<UUID> uuid = islandWarp.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load warps for null islands, skipping...\");\n                return;\n            }\n\n            Optional<String> name = islandWarp.getString(\"name\").map(_name -> {\n                return IslandUtils.isWarpNameLengthValid(_name) ? _name : _name.substring(0, IslandUtils.getMaxWarpNameLength());\n            });\n            if (!name.isPresent() || name.get().isEmpty()) {\n                Log.warn(\"Cannot load warps with invalid names for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Location> location = islandWarp.getString(\"location\").map(Serializers.LOCATION_SERIALIZER::deserialize);\n            if (!location.isPresent()) {\n                Log.warn(\"Cannot load warps with invalid locations for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_warps\");\n            builder.addWarp(name.get(), islandWarp.getString(\"category\").orElse(\"\"),\n                    location.get(), islandWarp.getBoolean(\"private\").orElse(!plugin.getSettings().isPublicWarps()),\n                    islandWarp.getString(\"icon\").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null));\n        });\n    }\n\n    public static void deserializeDirtyChunks(Island.Builder builder, String dirtyChunks) {\n        if (Text.isBlank(dirtyChunks))\n            return;\n\n        JsonObject dirtyChunksObject = GSON.fromJson(dirtyChunks, JsonObject.class);\n        dirtyChunksObject.entrySet().forEach(dirtyChunkEntry -> {\n            String worldName = dirtyChunkEntry.getKey();\n            JsonArray dirtyChunksArray = dirtyChunkEntry.getValue().getAsJsonArray();\n\n            dirtyChunksArray.forEach(dirtyChunkElement -> {\n                String[] chunkPositionSections = dirtyChunkElement.getAsString().split(\",\");\n                builder.setDirtyChunk(worldName, Integer.parseInt(chunkPositionSections[0]),\n                        Integer.parseInt(chunkPositionSections[1]));\n            });\n        });\n    }\n\n    public static void deserializeBlockCounts(Island.Builder builder, String blocks) {\n        if (Text.isBlank(blocks))\n            return;\n\n        JsonArray blockCounts = GSON.fromJson(blocks, JsonArray.class);\n\n        blockCounts.forEach(blockCountElement -> {\n            JsonObject blockCountObject = blockCountElement.getAsJsonObject();\n            Key blockKey = Keys.ofMaterialAndData(blockCountObject.get(\"id\").getAsString());\n            BigInteger amount = new BigInteger(blockCountObject.get(\"amount\").getAsString());\n            builder.setBlockCount(blockKey, amount);\n        });\n    }\n\n    public static void deserializeEntityCounts(Island.Builder builder, String entities) {\n        if (Text.isBlank(entities))\n            return;\n\n        JsonArray entityCounts = GSON.fromJson(entities, JsonArray.class);\n\n        entityCounts.forEach(entityCountElement -> {\n            JsonObject entityCountObject = entityCountElement.getAsJsonObject();\n            Key entityKey = Keys.ofEntityType(entityCountObject.get(\"id\").getAsString());\n            BigInteger amount = new BigInteger(entityCountObject.get(\"amount\").getAsString());\n            builder.setEntityCount(entityKey, amount);\n        });\n    }\n\n    public static void deserializeDimensionsList(String dimensions, Consumer<Dimension> consumer) {\n        if (Text.isBlank(dimensions))\n            return;\n\n        for (String dimensionName : dimensions.split(\",\")) {\n            try {\n                Dimension dimension = Dimension.getByName(dimensionName);\n                consumer.accept(dimension);\n            } catch (NullPointerException ignored) {\n\n            }\n        }\n    }\n\n    public static void deserializeBlockLimits(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_block_limits\", blockLimitRow -> {\n            DatabaseResult blockLimits = new DatabaseResult(blockLimitRow);\n\n            Optional<UUID> uuid = blockLimits.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load block limits for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Key> block = blockLimits.getString(\"block\").map(Keys::ofMaterialAndData);\n            if (!block.isPresent()) {\n                Log.warn(\"Cannot load block limits for invalid blocks for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> limit = blockLimits.getInt(\"limit\");\n            if (!limit.isPresent()) {\n                Log.warn(\"Cannot load block limits with invalid limits for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_block_limits\");\n            builder.setBlockLimit(block.get(), limit.get());\n        });\n    }\n\n    public static void deserializeEntityLimits(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_entity_limits\", entityLimitsRow -> {\n            DatabaseResult entityLimits = new DatabaseResult(entityLimitsRow);\n\n            Optional<UUID> uuid = entityLimits.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load entity limits for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Key> entity = entityLimits.getString(\"entity\").map(Keys::ofEntityType);\n            if (!entity.isPresent()) {\n                Log.warn(\"Cannot load entity limits for invalid entities on \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> limit = entityLimits.getInt(\"limit\");\n            if (!limit.isPresent()) {\n                Log.warn(\"Cannot load entity limits with invalid limits for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_entity_limits\");\n            builder.setEntityLimit(entity.get(), limit.get());\n        });\n    }\n\n    public static void deserializeRatings(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_ratings\", ratingsRow -> {\n            DatabaseResult ratings = new DatabaseResult(ratingsRow);\n\n            Optional<UUID> uuid = ratings.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load ratings for null islands, skipping...\");\n                return;\n            }\n\n            Optional<UUID> playerUUID = ratings.getUUID(\"player\");\n            if (!playerUUID.isPresent()) {\n                Log.warn(\"Cannot load ratings with invalid players for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false);\n            if (ratingPlayer == null) {\n                Log.warn(\"Cannot load island rating with unrecognized uuid: \" + playerUUID.get() + \", skipping...\");\n                return;\n            }\n\n            Optional<Rating> rating = ratings.getInt(\"rating\").map(value -> {\n                try {\n                    return Rating.valueOf(value);\n                } catch (ArrayIndexOutOfBoundsException error) {\n                    return null;\n                }\n            });\n            if (!rating.isPresent()) {\n                Log.warn(\"Cannot load ratings with invalid rating value for \", playerUUID.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_ratings\");\n            builder.setRating(ratingPlayer, rating.get());\n        });\n    }\n\n    public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_missions\", missionsRow -> {\n            DatabaseResult missions = new DatabaseResult(missionsRow);\n\n            Optional<UUID> uuid = missions.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island missions for null islands, skipping...\");\n                return;\n            }\n\n            Optional<String> missionName = missions.getString(\"name\");\n            Optional<Mission<?>> mission = missionName.map(plugin.getMissions()::getMission);\n            if (!mission.isPresent()) {\n                if (!missionName.isPresent()) {\n                    Log.warn(\"Cannot load island missions with invalid missions for \", uuid.get(), \", skipping...\");\n                } else {\n                    Log.warn(\"Cannot load island missions with invalid mission \",\n                            missionName.get(), \" for \", uuid.get(), \", skipping...\");\n                }\n                return;\n            }\n\n            Optional<Integer> finishCount = missions.getInt(\"finish_count\");\n            if (!finishCount.isPresent()) {\n                Log.warn(\"Cannot load island missions with invalid finish count for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_missions\");\n            builder.setCompletedMission(mission.get(), finishCount.get());\n        });\n    }\n\n    public static void deserializeIslandFlags(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_flags\", islandFlagRow -> {\n            DatabaseResult islandFlagResult = new DatabaseResult(islandFlagRow);\n\n            Optional<UUID> uuid = islandFlagResult.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island flags for null islands, skipping...\");\n                return;\n            }\n\n            IslandFlag islandFlag = islandFlagResult.getString(\"name\").map(name -> {\n                try {\n                    return IslandFlag.getByName(name);\n                } catch (NullPointerException error) {\n                    IslandFlag.register(name);\n                    return IslandFlag.getByName(name);\n                }\n            }).orElseThrow(IllegalStateException::new);\n\n            Optional<Byte> status = islandFlagResult.getByte(\"status\");\n            if (!status.isPresent()) {\n                Log.warn(\"Cannot load island flags with invalid status for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_flags\");\n            builder.setIslandFlag(islandFlag, status.get() == 1);\n        });\n    }\n\n    public static void deserializeGenerators(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_generators\", generatorsRow -> {\n            DatabaseResult generators = new DatabaseResult(generatorsRow);\n\n            Optional<UUID> uuid = generators.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load generator rates for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Dimension> dimension = generators.getString(\"environment\").map(Dimension::getByName);\n            if (!dimension.isPresent()) {\n                Log.warn(\"Cannot load generator rates with invalid environment for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Key> block = generators.getString(\"block\").map(Keys::ofMaterialAndData);\n            if (!block.isPresent()) {\n                Log.warn(\"Cannot load generator rates with invalid block for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> rate = generators.getInt(\"rate\");\n            if (!rate.isPresent()) {\n                Log.warn(\"Cannot load generator rates with invalid rate for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_generators\");\n            builder.setGeneratorRate(block.get(), rate.get(), dimension.get());\n        });\n    }\n\n    public static void deserializeIslandHomes(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_homes\", islandHomesRow -> {\n            DatabaseResult islandHomes = new DatabaseResult(islandHomesRow);\n\n            Optional<UUID> uuid = islandHomes.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island homes for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Dimension> dimension = islandHomes.getString(\"environment\").map(Dimension::getByName);\n            if (!dimension.isPresent()) {\n                Log.warn(\"Cannot load island homes with invalid environment for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<WorldPosition> location = islandHomes.getString(\"location\").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize);\n            if (!location.isPresent()) {\n                Log.warn(\"Cannot load island homes with invalid location for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_homes\");\n            builder.setIslandHome(dimension.get(), location.get());\n        });\n    }\n\n    public static void deserializeVisitorHomes(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_visitor_homes\", islandVisitorHomesRow -> {\n            DatabaseResult islandVisitorHomes = new DatabaseResult(islandVisitorHomesRow);\n\n            Optional<UUID> uuid = islandVisitorHomes.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island homes for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Dimension> dimension = islandVisitorHomes.getString(\"environment\").map(Dimension::getByName);\n            if (!dimension.isPresent()) {\n                Log.warn(\"Cannot load island homes with invalid environment for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<WorldPosition> location = islandVisitorHomes.getString(\"location\").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize);\n            if (!location.isPresent()) {\n                Log.warn(\"Cannot load island homes with invalid location for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_visitor_homes\");\n            builder.setVisitorHome(dimension.get(), location.get());\n        });\n    }\n\n    public static void deserializeEffects(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_effects\", islandEffectRow -> {\n            DatabaseResult islandEffects = new DatabaseResult(islandEffectRow);\n\n            Optional<UUID> uuid = islandEffects.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island effects for null islands, skipping...\");\n                return;\n            }\n\n            Optional<PotionEffectType> effectType = islandEffects.getString(\"effect_type\")\n                    .map(PotionEffectType::getByName);\n            if (!effectType.isPresent()) {\n                Log.warn(\"Cannot load island effects with invalid effect for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> level = islandEffects.getInt(\"level\");\n            if (!level.isPresent()) {\n                Log.warn(\"Cannot load island effects with invalid level for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_effects\");\n            builder.setIslandEffect(effectType.get(), level.get());\n        });\n    }\n\n    public static void deserializeIslandChest(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_chests\", islandChestsRow -> {\n            DatabaseResult islandChests = new DatabaseResult(islandChestsRow);\n\n            Optional<UUID> uuid = islandChests.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island chests for null islands, skipping...\");\n                return;\n            }\n\n            Optional<Integer> index = islandChests.getInt(\"index\");\n            if (!index.isPresent() || index.get() < 0) {\n                Log.warn(\"Cannot load island chest with invalid index for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<ItemStack[]> contents = islandChests.getBlob(\"contents\").map(Serializers.INVENTORY_SERIALIZER::deserialize);\n            if (!contents.isPresent()) {\n                Log.warn(\"Cannot load island chest with invalid contents for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            int contentsLength = contents.get().length;\n            ItemStack[] chestContents;\n\n            if (contentsLength % 9 != 0) {\n                int amountOfRows = Math.min(1, Math.max(6, (contentsLength / 9) + 1));\n                chestContents = new ItemStack[amountOfRows * 9];\n                int amountOfContentsToCopy = Math.min(contentsLength, chestContents.length);\n                System.arraycopy(contents.get(), 0, chestContents, 0, amountOfContentsToCopy);\n            } else if (contentsLength > 54) {\n                chestContents = new ItemStack[54];\n                System.arraycopy(contents.get(), 0, chestContents, 0, 54);\n            } else if (contentsLength < 9) {\n                chestContents = new ItemStack[9];\n                System.arraycopy(contents.get(), 0, chestContents, 0, contentsLength);\n            } else {\n                chestContents = contents.get();\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_chests\");\n            builder.setIslandChest(index.get(), chestContents);\n        });\n    }\n\n    public static void deserializeRoleLimits(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_role_limits\", roleLimitRaw -> {\n            DatabaseResult roleLimits = new DatabaseResult(roleLimitRaw);\n\n            Optional<UUID> uuid = roleLimits.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load role limits for null islands, skipping...\");\n                return;\n            }\n\n            Optional<PlayerRole> playerRole = roleLimits.getInt(\"role\").map(SPlayerRole::fromId);\n            if (!playerRole.isPresent()) {\n                Log.warn(\"Cannot load role limit for invalid role on \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> limit = roleLimits.getInt(\"limit\");\n            if (!limit.isPresent()) {\n                Log.warn(\"Cannot load role limit for invalid limit on \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_role_limits\");\n            builder.setRoleLimit(playerRole.get(), limit.get());\n        });\n    }\n\n    public static void deserializeWarpCategories(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_warp_categories\", warpCategoryRow -> {\n            DatabaseResult warpCategory = new DatabaseResult(warpCategoryRow);\n\n            Optional<UUID> uuid = warpCategory.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load warp categories for null islands, skipping...\");\n                return;\n            }\n\n            Optional<String> name = warpCategory.getString(\"name\").map(Formatters.STRIP_COLOR_FORMATTER::format);\n            if (!name.isPresent() || name.get().isEmpty()) {\n                Log.warn(\"Cannot load warp categories with invalid name for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_warp_categories\");\n            builder.addWarpCategory(name.get(), warpCategory.getInt(\"slot\").orElse(-1),\n                    warpCategory.getString(\"icon\").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null));\n        });\n    }\n\n    public static void deserializeIslandBank(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_banks\", islandBankRow -> {\n            DatabaseResult islandBank = new DatabaseResult(islandBankRow);\n\n            Optional<UUID> uuid = islandBank.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island banks for null islands, skipping...\");\n                return;\n            }\n\n            Optional<BigDecimal> balance = islandBank.getBigDecimal(\"balance\");\n            if (!balance.isPresent()) {\n                Log.warn(\"Cannot load island banks with invalid balance for \", uuid.get(), \", skipping...\");\n                return;\n            }\n\n            long currentTime = System.currentTimeMillis() / 1000;\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_banks\");\n            builder.setBalance(balance.get());\n            long lastInterestTime = islandBank.getLong(\"last_interest_time\").orElse(currentTime);\n            builder.setLastInterestTime(lastInterestTime > currentTime ? lastInterestTime / 1000 : lastInterestTime);\n        });\n    }\n\n    public static void deserializeIslandSettings(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_settings\", islandSettingsRow -> {\n            DatabaseResult islandSettings = new DatabaseResult(islandSettingsRow);\n\n            Optional<UUID> uuid = islandSettings.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load island settings of null island, skipping \");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_settings\");\n\n            builder.setIslandSize(islandSettings.getInt(\"size\").orElse(SYNCED_VALUE));\n            builder.setTeamLimit(islandSettings.getInt(\"members_limit\").orElse(SYNCED_VALUE));\n            builder.setWarpsLimit(islandSettings.getInt(\"warps_limit\").orElse(SYNCED_VALUE));\n            builder.setCropGrowth(islandSettings.getDouble(\"crop_growth_multiplier\").orElse((double) SYNCED_VALUE));\n            builder.setSpawnerRates(islandSettings.getDouble(\"spawner_rates_multiplier\").orElse((double) SYNCED_VALUE));\n            builder.setMobDrops(islandSettings.getDouble(\"mob_drops_multiplier\").orElse((double) SYNCED_VALUE));\n            builder.setCoopLimit(islandSettings.getInt(\"coops_limit\").orElse(SYNCED_VALUE));\n            builder.setBankLimit(islandSettings.getBigDecimal(\"bank_limit\").orElse(SYNCED_BANK_LIMIT_VALUE));\n        });\n    }\n\n    public static void deserializeBankTransactions(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        if (!BuiltinModules.BANK.getConfiguration().isBankLogs() ||\n                !BuiltinModules.BANK.getConfiguration().isCacheAllLogs())\n            return;\n\n        databaseBridge.loadAllObjects(\"bank_transactions\", bankTransactionRow -> {\n            DatabaseResult bankTransaction = new DatabaseResult(bankTransactionRow);\n\n            Optional<UUID> uuid = bankTransaction.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load bank transaction for null islands, skipping...\");\n                return;\n            }\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"bank_transactions\");\n            SBankTransaction.fromDatabase(bankTransaction).ifPresent(builder::addBankTransaction);\n        });\n    }\n\n    public static void deserializePersistentDataContainer(DatabaseBridge databaseBridge, DatabaseCache<Island.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"islands_custom_data\", customDataRow -> {\n            DatabaseResult customData = new DatabaseResult(customDataRow);\n\n            Optional<UUID> uuid = customData.getUUID(\"island\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"Cannot load custom data for null islands, skipping...\");\n                return;\n            }\n\n            byte[] persistentData = customData.getBlob(\"data\").orElse(new byte[0]);\n\n            if (persistentData.length == 0)\n                return;\n\n            Island.Builder builder = lookupIsland(databaseCache, uuid.get(), \"islands_custom_data\");\n            builder.setPersistentData(persistentData);\n        });\n    }\n\n    private static Island.Builder lookupIsland(DatabaseCache<Island.Builder> databaseCache, UUID uuid, String tableName) {\n        DatabaseCache.Record<Island.Builder> islandRecord =\n                databaseCache.computeIfAbsentInfo(uuid, IslandBuilderImpl::new);\n        islandRecord.recordTable(tableName);\n        return islandRecord.get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.serialization;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.DirtyChunk;\nimport com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\nimport com.google.gson.JsonPrimitive;\n\nimport java.math.BigInteger;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\npublic class IslandsSerializer {\n\n    private static final Gson gson = new GsonBuilder().create();\n\n    private IslandsSerializer() {\n\n    }\n\n    public static String serializeBlockCounts(Map<Key, BigInteger> blockCounts) {\n        JsonArray blockCountsArray = new JsonArray();\n        blockCounts.forEach((key, amount) -> {\n            JsonObject blockCountObject = new JsonObject();\n            blockCountObject.addProperty(\"id\", key.toString());\n            blockCountObject.addProperty(\"amount\", amount.toString());\n            blockCountsArray.add(blockCountObject);\n        });\n        return gson.toJson(blockCountsArray);\n    }\n\n    public static String serializeEntityCounts(Map<Key, Integer> entityCounts) {\n        JsonArray entityCountsArray = new JsonArray();\n        entityCounts.forEach((key, amount) -> {\n            JsonObject blockCountObject = new JsonObject();\n            blockCountObject.addProperty(\"id\", key.toString());\n            blockCountObject.addProperty(\"amount\", amount.toString());\n            entityCountsArray.add(blockCountObject);\n        });\n        return gson.toJson(entityCountsArray);\n    }\n\n    public static String serializeDirtyChunks(List<DirtyChunk> dirtyChunks) {\n        JsonObject dirtyChunksObject = new JsonObject();\n        dirtyChunks.forEach(dirtyChunk -> {\n            JsonArray dirtyChunksArray;\n\n            if (dirtyChunksObject.has(dirtyChunk.getWorldName())) {\n                dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName());\n            } else {\n                dirtyChunksArray = new JsonArray();\n                dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray);\n            }\n\n            dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + \",\" + dirtyChunk.getZ()));\n        });\n        return gson.toJson(dirtyChunksObject);\n    }\n\n    public static String serializeDirtyChunkPositions(List<ChunkPosition> dirtyChunks) {\n        JsonObject dirtyChunksObject = new JsonObject();\n        dirtyChunks.forEach(dirtyChunk ->\n                serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk));\n        return gson.toJson(dirtyChunksObject);\n    }\n\n    public static String serializeDirtyChunkPositions(DirtyChunksContainer container) {\n        JsonObject dirtyChunksObject = new JsonObject();\n        container.getDirtyChunks(dirtyChunk ->\n                serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk));\n        return gson.toJson(dirtyChunksObject);\n    }\n\n    public static String serializeDimensions(Collection<Dimension> dimensions) {\n        StringBuilder serialized = new StringBuilder();\n        for (Dimension dimension : dimensions)\n            serialized.append(\",\").append(dimension.getName());\n        return serialized.length() == 0 ? serialized.toString() : serialized.substring(1);\n    }\n\n    private static void serializeDirtyChunkPosition(JsonObject dirtyChunksObject, ChunkPosition dirtyChunk) {\n        JsonArray dirtyChunksArray;\n\n        if (dirtyChunksObject.has(dirtyChunk.getWorldName())) {\n            dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName());\n        } else {\n            dirtyChunksArray = new JsonArray();\n            dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray);\n        }\n\n        dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + \",\" + dirtyChunk.getZ()));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.serialization;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\n\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic class PlayersDeserializer {\n\n    static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private PlayersDeserializer() {\n\n    }\n\n    public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCache<SuperiorPlayer.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"players_missions\", missionsRow -> {\n            DatabaseResult missions = new DatabaseResult(missionsRow);\n\n            Optional<String> player = missions.getString(\"player\");\n\n            if (!player.isPresent()) {\n                Log.warn(\"Cannot load player mission of null player, skipping...\");\n                return;\n            }\n\n            UUID uuid = UUID.fromString(player.get());\n            SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, \"players_missions\");\n\n            Optional<String> name = missions.getString(\"name\");\n\n            if (!name.isPresent()) {\n                Log.warn(\"Cannot load player mission of null mission for \", uuid, \", skipping...\");\n                return;\n            }\n\n            Optional<Integer> finishCount = missions.getInt(\"finish_count\");\n\n            if (!finishCount.isPresent()) {\n                Log.warn(\"Cannot load player mission of invalid finish count for \", uuid, \", skipping...\");\n                return;\n            }\n\n            Mission<?> mission = plugin.getMissions().getMission(name.get());\n\n            if (mission != null)\n                builder.setCompletedMission(mission, finishCount.get());\n        });\n    }\n\n    public static void deserializePlayerSettings(DatabaseBridge databaseBridge, DatabaseCache<SuperiorPlayer.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"players_settings\", playerSettingsRow -> {\n            DatabaseResult playerSettings = new DatabaseResult(playerSettingsRow);\n\n            Optional<String> player = playerSettings.getString(\"player\");\n\n            if (!player.isPresent()) {\n                Log.warn(\"&cCannot load player settings of null player, skipping...\");\n                return;\n            }\n\n            UUID uuid = UUID.fromString(player.get());\n            SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, \"players_settings\");\n            playerSettings.getBoolean(\"toggled_panel\").ifPresent(builder::setToggledPanel);\n            playerSettings.getBoolean(\"island_fly\").ifPresent(builder::setIslandFly);\n            playerSettings.getEnum(\"border_color\", BorderColor.class).ifPresent(builder::setBorderColor);\n            playerSettings.getString(\"language\").map(PlayerLocales::getLocale).ifPresent(builder::setLocale);\n            playerSettings.getBoolean(\"toggled_border\").ifPresent(builder::setWorldBorderEnabled);\n        });\n    }\n\n    public static void deserializePersistentDataContainer(DatabaseBridge databaseBridge, DatabaseCache<SuperiorPlayer.Builder> databaseCache) {\n        databaseBridge.loadAllObjects(\"players_custom_data\", customDataRow -> {\n            DatabaseResult customData = new DatabaseResult(customDataRow);\n\n            Optional<UUID> uuid = customData.getUUID(\"player\");\n            if (!uuid.isPresent()) {\n                Log.warn(\"&cCannot load custom data for null players, skipping...\");\n                return;\n            }\n\n            byte[] persistentData = customData.getBlob(\"data\").orElse(new byte[0]);\n\n            if (persistentData.length == 0)\n                return;\n\n            SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid.get(), \"players_custom_data\");\n            builder.setPersistentData(persistentData);\n        });\n    }\n\n    private static SuperiorPlayer.Builder lookupPlayer(DatabaseCache<SuperiorPlayer.Builder> databaseCache, UUID uuid, String tableName) {\n        DatabaseCache.Record<SuperiorPlayer.Builder> playerRecord =\n                databaseCache.computeIfAbsentInfo(uuid, SuperiorPlayer::newBuilder);\n        playerRecord.recordTable(tableName);\n        return playerRecord.get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.sql;\n\nimport com.bgsoftware.common.databasebridge.DatabaseSessionFactory;\nimport com.bgsoftware.common.databasebridge.logger.ILogger;\nimport com.bgsoftware.common.databasebridge.session.IDatabaseSession;\nimport com.bgsoftware.common.databasebridge.sql.query.Column;\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.common.databasebridge.sql.session.MariaDBDatabaseSession;\nimport com.bgsoftware.common.databasebridge.sql.session.MySQLDatabaseSession;\nimport com.bgsoftware.common.databasebridge.sql.session.SQLDatabaseSession;\nimport com.bgsoftware.common.databasebridge.sql.session.SQLiteDatabaseSession;\nimport com.bgsoftware.common.databasebridge.transaction.DatabaseTransactionsExecutor;\nimport com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.io.File;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.util.Collection;\nimport java.util.concurrent.CompletableFuture;\n\npublic class DBSession {\n\n    private static final ILogger LOGGER = new ILogger() {\n        @Override\n        public void error(String message, Throwable error) {\n            Log.error(error, message);\n        }\n\n        @Override\n        public boolean hasDebugEnabled() {\n            return Log.isDebugged(Debug.DATABASE_QUERY);\n        }\n\n        @Override\n        public void debug(String message) {\n            if (hasDebugEnabled())\n                Log.debug(Debug.DATABASE_QUERY, message);\n        }\n\n        @Override\n        public void info(String message) {\n            Log.info(message);\n        }\n    };\n\n    private static SQLDatabaseSession<?> globalSession = null;\n\n    private DBSession() {\n\n    }\n\n    public static boolean isReady() {\n        return globalSession != null;\n    }\n\n    public static void waitForConnection() {\n        if (isReady())\n            globalSession.waitForConnection();\n    }\n\n    public static boolean createConnection(SuperiorSkyblockPlugin plugin) {\n        SQLDatabaseSession<?> session = createSessionInternal(plugin, true);\n\n        if (session.connect()) {\n            globalSession = session;\n            return true;\n        }\n\n        return false;\n    }\n\n    public static CompletableFuture<Void> execute(IDatabaseTransaction transaction) {\n        return globalSession.execute(transaction);\n    }\n\n    public static CompletableFuture<Void> execute(IDatabaseTransaction... transactions) {\n        return globalSession.execute(transactions);\n    }\n\n    public static CompletableFuture<Void> execute(Collection<IDatabaseTransaction> transactions) {\n        return globalSession.execute(transactions);\n    }\n\n    public static void createTable(String tableName, Column... columns) {\n        if (isReady())\n            globalSession.createTable(tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT);\n    }\n\n    public static void createIndex(String indexName, String tableName, String... columns) {\n        if (isReady())\n            globalSession.createIndex(indexName, tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT);\n    }\n\n    public static void modifyColumnType(String tableName, String columnName, String newType) {\n        if (isReady())\n            globalSession.modifyColumnType(tableName, columnName, newType, QueryResult.EMPTY_VOID_QUERY_RESULT);\n    }\n\n    public static void addColumn(String tableName, String columnName, String type) {\n        if (isReady())\n            globalSession.addColumn(tableName, columnName, type, QueryResult.EMPTY_VOID_QUERY_RESULT);\n    }\n\n    public static void removePrimaryKey(String tableName, String columnName) {\n        if (isReady())\n            globalSession.removePrimaryKey(tableName, columnName, QueryResult.EMPTY_VOID_QUERY_RESULT);\n    }\n\n    public static void select(String tableName, String filters, QueryResult<ResultSet> queryResult) {\n        if (isReady())\n            globalSession.select(tableName, filters, queryResult);\n    }\n\n    public static void setJournalMode(String jounralMode, QueryResult<ResultSet> queryResult) {\n        if (isReady())\n            globalSession.setJournalMode(jounralMode, queryResult);\n    }\n\n    public static void customQuery(String query, QueryResult<PreparedStatement> queryResult) {\n        if (isReady())\n            globalSession.customQuery(query, queryResult);\n    }\n\n    public static void close() {\n        if (isReady()) {\n            DatabaseTransactionsExecutor.stopActiveExecutors();\n            globalSession.close();\n        }\n    }\n\n    public static String getColumnFilter(DatabaseFilter filter) {\n        StringBuilder columnIdentifier = new StringBuilder();\n        if (filter != null) {\n            filter.forEach((column, value) -> {\n                if (columnIdentifier.length() == 0) {\n                    columnIdentifier.append(String.format(\" WHERE %s=?\", column));\n                } else {\n                    columnIdentifier.append(String.format(\" AND %s=?\", column));\n                }\n            });\n        }\n        return columnIdentifier.toString();\n    }\n\n    private static SQLDatabaseSession<?> createSessionInternal(SuperiorSkyblockPlugin plugin, boolean logging) {\n        SettingsManager.Database database = plugin.getSettings().getDatabase();\n\n        IDatabaseSession.Args args;\n        switch (database.getType()) {\n            case \"MYSQL\":\n                args = new MySQLDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(),\n                        database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(),\n                        database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(),\n                        \"SuperiorSkyblock Database Thread\", LOGGER);\n                break;\n            case \"MARIADB\":\n                args = new MariaDBDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(),\n                        database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(),\n                        database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(),\n                        \"SuperiorSkyblock Database Thread\", LOGGER);\n                break;\n            default:\n                File databaseFile = new File(plugin.getDataFolder(), \"datastore/database.db\");\n                args = new SQLiteDatabaseSession.Args(databaseFile,\n                        \"SuperiorSkyblock Database Thread\", LOGGER);\n                break;\n        }\n\n        SQLDatabaseSession<?> session = (SQLDatabaseSession<?>) DatabaseSessionFactory.createSession(args);\n        if (logging)\n            session.setLogging(true);\n        return session;\n    }\n\n}\n\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/ResultSetMapBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.sql;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class ResultSetMapBridge implements Map<String, Object> {\n\n    private final ResultSet resultSet;\n\n    public ResultSetMapBridge(ResultSet resultSet) {\n        this.resultSet = resultSet;\n    }\n\n    @Override\n    public int size() {\n        return 0;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        try {\n            get(key);\n            return true;\n        } catch (Exception ex) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @Override\n    public Object get(Object key) {\n        return getSafe(key + \"\");\n    }\n\n    public <T> T get(Object key, T def) {\n        try {\n            return get(key + \"\");\n        } catch (SQLException ex) {\n            return def;\n        }\n    }\n\n    @Nullable\n    @Override\n    public Object put(String key, Object value) {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @Override\n    public Object remove(Object key) {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @Override\n    public void putAll(@NotNull Map<? extends String, ?> m) {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @Override\n    public void clear() {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @NotNull\n    @Override\n    public Set<String> keySet() {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @NotNull\n    @Override\n    public Collection<Object> values() {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<String, Object>> entrySet() {\n        throw new UnsupportedOperationException(\"This operation is not supported on this map.\");\n    }\n\n    private <T> T get(String key) throws SQLException {\n        // noinspection all\n        return (T) resultSet.getObject(key);\n    }\n\n    private <T> T getSafe(String key) {\n        try {\n            return get(key + \"\");\n        } catch (SQLException ex) {\n            throw new RuntimeException(ex);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java",
    "content": "package com.bgsoftware.superiorskyblock.core.database.sql;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.databasebridge.sql.query.QueryResult;\nimport com.bgsoftware.common.databasebridge.sql.transaction.DeleteSQLDatabaseTransaction;\nimport com.bgsoftware.common.databasebridge.sql.transaction.InsertSQLDatabaseTransaction;\nimport com.bgsoftware.common.databasebridge.sql.transaction.UpdateSQLDatabaseTransaction;\nimport com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableObject;\n\nimport java.sql.ResultSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic class SQLDatabaseBridge implements DatabaseBridge {\n\n    private DatabaseBridgeMode databaseBridgeMode = DatabaseBridgeMode.IDLE;\n    private List<IDatabaseTransaction> batchTransactions = null;\n\n    public SQLDatabaseBridge() {\n\n    }\n\n    @Override\n    public void loadAllObjects(String table, Consumer<Map<String, Object>> resultConsumer) {\n        DBSession.select(table, \"\", new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                try {\n                    resultConsumer.accept(new ResultSetMapBridge(resultSet));\n                } catch (Exception error) {\n                    Log.entering(\"ENTER\", table);\n                    Log.error(error, \"An unexpected error occurred while loading data from database:\");\n                }\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n    }\n\n    @Override\n    public void batchOperations(boolean batchOperations) {\n        if (batchOperations) {\n            batchTransactions = new LinkedList<>();\n        } else if (batchTransactions != null) {\n            DBSession.execute(batchTransactions);\n            batchTransactions = null;\n        }\n    }\n\n    @Override\n    public void updateObject(String table, @Nullable DatabaseFilter filter, Pair<String, Object>[] columns) {\n        if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA)\n            return;\n\n        List<String> filteredColumns = filter == null ? null : new LinkedList<>();\n        List<String> columnNames = new LinkedList<>();\n        List<Object> values = new LinkedList<>();\n\n        for (Pair<String, Object> column : columns) {\n            columnNames.add(column.getKey());\n            values.add(column.getValue());\n        }\n\n        if (filter != null) {\n            filter.forEach((column, value) -> {\n                filteredColumns.add(column);\n                values.add(value);\n            });\n        }\n\n        UpdateSQLDatabaseTransaction transaction = new UpdateSQLDatabaseTransaction(table, columnNames, filteredColumns);\n        transaction.bindObjects(values);\n        submitTransaction(transaction);\n    }\n\n    @Override\n    public void insertObject(String table, Pair<String, Object>... columns) {\n        if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA)\n            return;\n\n        List<String> columnNames = new LinkedList<>();\n        List<Object> values = new LinkedList<>();\n\n        for (Pair<String, Object> column : columns) {\n            columnNames.add(column.getKey());\n            values.add(column.getValue());\n        }\n\n        InsertSQLDatabaseTransaction transaction = new InsertSQLDatabaseTransaction(table, columnNames);\n        transaction.bindObjects(values);\n        submitTransaction(transaction);\n    }\n\n    @Override\n    public void deleteObject(String table, @Nullable DatabaseFilter filter) {\n        if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA)\n            return;\n\n        List<String> filteredColumns = filter == null ? null : new LinkedList<>();\n        List<Object> values = new LinkedList<>();\n\n        if (filter != null) {\n            filter.forEach((column, value) -> {\n                filteredColumns.add(column);\n                values.add(value + \"\");\n            });\n        }\n\n        DeleteSQLDatabaseTransaction transaction = new DeleteSQLDatabaseTransaction(table, filteredColumns);\n        transaction.bindObjects(values);\n\n        submitTransaction(transaction);\n    }\n\n    @Override\n    public void loadObject(String table, DatabaseFilter filter, Consumer<Map<String, Object>> resultConsumer) {\n        MutableObject<String> columnFilter = new MutableObject<>(DBSession.getColumnFilter(filter));\n\n        filter.forEach((column, value) -> {\n            columnFilter.setValue(columnFilter.getValue().replaceFirst(\"\\\\?\", value instanceof String ?\n                    String.format(\"'%s'\", value) : value.toString()));\n        });\n\n        DBSession.select(table, columnFilter.getValue(), new QueryResult<ResultSet>().onSuccess(resultSet -> {\n            while (resultSet.next()) {\n                try {\n                    resultConsumer.accept(new ResultSetMapBridge(resultSet));\n                } catch (Exception error) {\n                    Log.entering(\"ENTER\", table, columnFilter);\n                    Log.error(error, \"An unexpected error occurred while loading data from database:\");\n                }\n            }\n        }).onFail(QueryResult.PRINT_ERROR));\n    }\n\n    @Override\n    public void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode) {\n        this.databaseBridgeMode = databaseBridgeMode;\n    }\n\n    @Override\n    public DatabaseBridgeMode getDatabaseBridgeMode() {\n        return this.databaseBridgeMode;\n    }\n\n    private void submitTransaction(IDatabaseTransaction transaction) {\n        if (batchTransactions != null) {\n            batchTransactions.add(transaction);\n        } else {\n            DBSession.execute(transaction);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/engine/EnginesFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.engine;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\n\npublic class EnginesFactory {\n\n    private static IScriptEngine defaultEngine;\n\n    private EnginesFactory() {\n\n    }\n\n    public static IScriptEngine createDefaultEngine() {\n        if (defaultEngine == null) {\n            try {\n                ReflectMethod<IScriptEngine> nashornEngineGetInstance = new ReflectMethod<>(\n                        new ClassInfo(\"com.bgsoftware.superiorskyblock.core.engine.OpenJdkNashornEngine\", ClassInfo.PackageType.UNKNOWN),\n                        \"getInstance\",\n                        new Class[0]\n                );\n                Class.forName(\"org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory\");\n                defaultEngine = nashornEngineGetInstance.invoke(null);\n            } catch (Throwable error) {\n                defaultEngine = NashornEngine.getInstance();\n            }\n        }\n\n        return defaultEngine;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/engine/NashornEngine.java",
    "content": "package com.bgsoftware.superiorskyblock.core.engine;\n\nimport com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine;\n\nimport javax.script.Bindings;\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\n\npublic class NashornEngine implements IScriptEngine {\n\n    private static final NashornEngine instance = new NashornEngine();\n    private final ScriptEngine engine = new ScriptEngineManager().getEngineByName(\"JavaScript\");\n\n    private NashornEngine() {\n\n    }\n\n    public static NashornEngine getInstance() {\n        return instance;\n    }\n\n    @Override\n    public Object eval(String stringToEvaluate) throws ScriptException {\n        return engine.eval(stringToEvaluate);\n    }\n\n    @Override\n    public Object eval(String stringToEvaluate, Bindings bindings) throws ScriptException {\n        return engine.eval(stringToEvaluate, bindings);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/engine/NashornEngineDownloader.java",
    "content": "package com.bgsoftware.superiorskyblock.core.engine;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class NashornEngineDownloader {\n\n    private static final Gson GSON = new Gson();\n    private static final String JENKINS_URL = \"https://hub.bg-software.com/job/SuperiorSkyblock2%20-%20NashornEngine%20Module%20-%20Dev%20Builds/lastSuccessfulBuild/\";\n    private static final String JENKINS_API_ENDPOINT = JENKINS_URL + \"api/json\";\n    private static final String JENKINS_ARTIFACTS_ENDPOINT = JENKINS_URL + \"artifact/target/\";\n\n    public static boolean downloadEngine(SuperiorSkyblockPlugin plugin) {\n        try {\n            Log.info(\"Seems like you are missing a nashorn engine. Attempting to download one remotely...\");\n            deleteExistingModule(plugin);\n            JsonObject apiResponse = readJenkinsJsonAPI();\n            JsonObject artifact = apiResponse.getAsJsonArray(\"artifacts\").get(0).getAsJsonObject();\n            String fileName = artifact.get(\"fileName\").getAsString();\n            File engineFile = downloadEngine(plugin, fileName);\n            Log.info(\"Successfully downloaded the nashorn engine file, enabling it...\");\n            PluginModule pluginModule = plugin.getModules().registerModule(engineFile);\n            plugin.getModules().enableModule(pluginModule);\n            return true;\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while downloading nashorn engine:\");\n            return false;\n        }\n    }\n\n    private static void deleteExistingModule(SuperiorSkyblockPlugin plugin) {\n        PluginModule nashornEngineModule = plugin.getModules().getModule(\"nashorn-engine\");\n\n        if (nashornEngineModule == null)\n            return;\n\n        plugin.getModules().unregisterModule(nashornEngineModule);\n\n        try {\n            nashornEngineModule.getModuleFile().delete();\n        } catch (Exception ignored) {\n        }\n    }\n\n    private static JsonObject readJenkinsJsonAPI() throws IOException {\n        HttpsURLConnection conn = (HttpsURLConnection) new URL(JENKINS_API_ENDPOINT).openConnection();\n        conn.setRequestMethod(\"GET\");\n\n        StringBuilder jsonContents = new StringBuilder();\n\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {\n            String line;\n            while ((line = reader.readLine()) != null)\n                jsonContents.append(line);\n        }\n\n        return GSON.fromJson(jsonContents.toString(), JsonObject.class);\n    }\n\n    private static File downloadEngine(SuperiorSkyblockPlugin plugin, String engineName) throws IOException {\n        String downloadURL = JENKINS_ARTIFACTS_ENDPOINT + engineName;\n        File engineFile = new File(plugin.getDataFolder(), \"modules/\" + engineName);\n\n        try (InputStream inputStream = new URL(downloadURL).openStream()) {\n            Files.copy(inputStream, Paths.get(engineFile.toURI()));\n        }\n\n        return engineFile;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/errors/ManagerLoadException.java",
    "content": "package com.bgsoftware.superiorskyblock.core.errors;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Bukkit;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Arrays;\nimport java.util.List;\n\n@SuppressWarnings(\"all\")\npublic class ManagerLoadException extends Exception {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ErrorLevel errorLevel;\n\n    public ManagerLoadException(String message, ErrorLevel errorLevel) {\n        super(message == null ? \"\" : message);\n        this.errorLevel = errorLevel;\n    }\n\n    public ManagerLoadException(Throwable cause, ErrorLevel errorLevel) {\n        super(cause);\n        this.errorLevel = errorLevel;\n    }\n\n    public ManagerLoadException(Throwable cause, String message, ErrorLevel errorLevel) {\n        super(message, cause);\n        this.errorLevel = errorLevel;\n    }\n\n    public static boolean handle(ManagerLoadException error) {\n        error.printStackTrace();\n\n        if (error.getErrorLevel() == ErrorLevel.SERVER_SHUTDOWN) {\n            Bukkit.shutdown();\n            return false;\n        }\n\n        return true;\n    }\n\n    public ErrorLevel getErrorLevel() {\n        return errorLevel;\n    }\n\n    @Override\n    public void printStackTrace() {\n        if (getErrorLevel() == ErrorLevel.CONTINUE) {\n            super.printStackTrace();\n            return;\n        }\n\n        StringWriter stackTrace = new StringWriter();\n        super.printStackTrace(new PrintWriter(stackTrace));\n\n        List<String> messageLines = Arrays.asList(getMessage().split(\"\\n\"));\n\n        Log.error(\"################################################\");\n        Log.error(\"##                                            ##\");\n        Log.error(\"## An error occured while loading the plugin! ##\");\n        Log.error(\"##                                            ##\");\n        Log.error(\"################################################\");\n        if (!messageLines.isEmpty()) {\n            Log.error(\" \");\n            messageLines.forEach(line -> Log.error(line));\n        }\n        Log.error(\" \");\n        Log.error(\"Stack Trace:\");\n\n        int linesCounter = 0;\n\n        for (String stackTraceLine : stackTrace.toString().split(\"\\n\")) {\n            if (linesCounter > messageLines.size()) {\n                if (!messageLines.contains(stackTraceLine)) {\n                    Log.error(stackTraceLine);\n                }\n            } else {\n                linesCounter++;\n            }\n        }\n\n        Log.error(\" \");\n        Log.error(\"################################################\");\n    }\n\n    public enum ErrorLevel {\n\n        SERVER_SHUTDOWN,\n        CONTINUE\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events;\n\npublic interface EventCallback<E> {\n\n    void execute(E gameEvent);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Enumerable;\n\npublic abstract class EventType<Args, E> implements Enumerable {\n\n    private static int ordinalCounter = 0;\n\n    private final int ordinal;\n\n    protected EventType() {\n        this.ordinal = ordinalCounter++;\n    }\n\n    @Override\n    public int ordinal() {\n        return this.ordinal;\n    }\n\n    public abstract E createEvent(Args args);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class EventsDispatcher<L, T extends EventType<?, ?>, P extends Enum<P>, E extends IEvent<T>> {\n\n    protected final EnumerateMap<T, EnumMap<P, List<RegisteredListener>>> callbacks;\n\n    protected final SuperiorSkyblockPlugin plugin;\n    protected final Class<P> priorityClass;\n\n    // This must be thread-safe, as it can be accessed from multiple threads.\n    // We don't actually want it to be thread-safe, but per-thread captured events.\n    // If we don't do that, weird behaviors can occur. For reference:\n    // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2863\n    private final ThreadLocal<List<E>> capturedEvents = new ThreadLocal<>();\n\n    protected EventsDispatcher(SuperiorSkyblockPlugin plugin, Class<P> priorityClass, Collection<T> allTypes) {\n        this.plugin = plugin;\n        this.priorityClass = priorityClass;\n        this.callbacks = new EnumerateMap<>(allTypes);\n    }\n\n    public void registerCallback(L listener, T type, P priority, boolean ignoreCancelled, EventCallback callback) {\n        callbacks.computeIfAbsent(type, t -> new EnumMap<>(this.priorityClass))\n                .computeIfAbsent(priority, p -> new LinkedList<>())\n                .add(new RegisteredListener(listener, ignoreCancelled, callback));\n    }\n\n    public void clearCallbacks() {\n        this.callbacks.clear();\n    }\n\n    public void startCaptureEvents() {\n        this.capturedEvents.set(new LinkedList<>());\n    }\n\n    public List<E> stopCaptureEvents() {\n        List<E> capturedEvents = this.capturedEvents.get();\n        this.capturedEvents.remove();\n        return capturedEvents;\n    }\n\n    public void onGameEvent(E event, P priority) {\n        if (event.isCancelled())\n            return;\n\n        EnumMap<P, List<RegisteredListener>> gameEventCallbacks = callbacks.get(event.getType());\n        if (gameEventCallbacks != null) {\n            List<RegisteredListener> priorityCallbacks = gameEventCallbacks.get(priority);\n            if (priorityCallbacks != null) {\n                for (RegisteredListener listener : priorityCallbacks) {\n                    if (listener.ignoreCancelled && event.isCancelled()) {\n                        continue;\n                    }\n\n                    try {\n                        listener.callback.execute(event);\n                    } catch (Throwable error) {\n                        Log.error(error, \"Could not pass listener: \" + listener.listener);\n                    }\n                }\n            }\n        }\n\n        List<E> capturedEvents = this.capturedEvents.get();\n        if (capturedEvents != null && filterCapturedEvent(event))\n            capturedEvents.add(event);\n    }\n\n    protected boolean filterCapturedEvent(E event) {\n        return true;\n    }\n\n    public Map<P, List<EventCallback>> getCallbacks(T eventType) {\n        Map<P, List<RegisteredListener>> priorityListeners = callbacks.get(eventType);\n\n        if (priorityListeners == null || priorityListeners.isEmpty())\n            return Collections.emptyMap();\n\n        Map<P, List<EventCallback>> priorityCallbacks = new EnumMap<>(this.priorityClass);\n\n        priorityListeners.forEach((eventPriority, listeners) -> {\n            List<EventCallback> callbacks = new LinkedList<>();\n            listeners.forEach(listener -> callbacks.add(listener.callback));\n            priorityCallbacks.put(eventPriority, callbacks);\n        });\n\n        return priorityCallbacks;\n    }\n\n    protected class RegisteredListener {\n\n        public final L listener;\n        public final boolean ignoreCancelled;\n        public final EventCallback callback;\n\n        RegisteredListener(L listener, boolean ignoreCancelled, EventCallback callback) {\n            this.listener = listener;\n            this.ignoreCancelled = ignoreCancelled;\n            this.callback = callback;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events;\n\npublic interface IEvent<T> {\n\n    T getType();\n\n    boolean isCancelled();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.args;\n\npublic interface IEventArgs {\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.args;\n\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class PluginEventArgs {\n\n    private PluginEventArgs() {\n\n    }\n\n    public static class Empty extends PluginEventArgs {\n\n        public static final Empty INSTANCE = new Empty();\n\n        private Empty() {\n\n        }\n\n    }\n\n    public static class AttemptPlayerSendMessage extends PluginEventArgs {\n\n        public SuperiorPlayer receiver;\n        public String messageType;\n        public Object[] args;\n\n    }\n\n    public static class BlockStack extends StackedBlockChangeCountArgs {\n\n    }\n\n    public static class BlockUnstack extends StackedBlockChangeCountArgs {\n\n    }\n\n    public static class IslandBan extends IslandDoActionArgs {\n\n        public SuperiorPlayer targetPlayer;\n\n    }\n\n    public static class IslandBankDeposit extends IslandBankTransactionArgs {\n\n    }\n\n    public static class IslandBankWithdraw extends IslandBankTransactionArgs {\n\n    }\n\n    public static class IslandBiomeChange extends IslandDoActionArgs {\n\n        public Biome biome;\n\n    }\n\n    public static class IslandChangeBankLimit extends IslandDoActionArgs {\n\n        public BigDecimal bankLimit;\n\n    }\n\n    public static class IslandChangeBlockLimit extends IslandDoActionArgs {\n\n        public Key block;\n        public int blockLimit;\n\n    }\n\n    public static class IslandChangeBorderSize extends IslandDoActionArgs {\n\n        public int borderSize;\n\n    }\n\n    public static class IslandChangeCoopLimit extends IslandDoActionArgs {\n\n        public int coopLimit;\n\n    }\n\n    public static class IslandChangeCropGrowth extends IslandDoActionArgs {\n\n        public double cropGrowth;\n\n    }\n\n    public static class IslandChangeDescription extends IslandDoActionArgs {\n\n        public String description;\n\n    }\n\n    public static class IslandChangeDiscord extends IslandDoActionArgs {\n\n        public String discord;\n\n    }\n\n    public static class IslandChangeEffectLevel extends IslandDoActionArgs {\n\n        public PotionEffectType effectType;\n        public int effectLevel;\n\n    }\n\n    public static class IslandChangeEntityLimit extends IslandDoActionArgs {\n\n        public Key entity;\n        public int entityLimit;\n\n    }\n\n    public static class IslandChangeGeneratorRate extends IslandDoActionArgs {\n\n        public Key block;\n        public Dimension dimension;\n        public int generatorRate;\n\n    }\n\n    public static class IslandChangeLevelBonus extends IslandDoActionArgs {\n\n        public IslandChangeLevelBonusEvent.Reason reason;\n        public BigDecimal levelBonus;\n\n    }\n\n    public static class IslandChangeMembersLimit extends IslandDoActionArgs {\n\n        public int membersLimit;\n\n    }\n\n    public static class IslandChangeMobDrops extends IslandDoActionArgs {\n\n        public double mobDrops;\n\n    }\n\n    public static class IslandChangePaypal extends IslandDoActionArgs {\n\n        public String paypal;\n\n    }\n\n    public static class IslandChangePlayerPrivilege extends IslandDoActionArgs {\n\n        public SuperiorPlayer privilegedPlayer;\n        public boolean privilegeEnabled;\n\n    }\n\n    public static class IslandChangeRoleLimit extends IslandDoActionArgs {\n\n        public PlayerRole playerRole;\n        public int roleLimit;\n\n    }\n\n    public static class IslandChangeSpawnerRates extends IslandDoActionArgs {\n\n        public double spawnerRates;\n\n    }\n\n    public static class IslandChangeWarpCategoryIcon extends WarpCategoryDoActionArgs {\n\n        public ItemStack icon;\n\n    }\n\n    public static class IslandChangeWarpCategorySlot extends WarpCategoryDoActionArgs {\n\n        public int slot;\n        public int maxSlot;\n\n    }\n\n    public static class IslandChangeWarpIcon extends IslandWarpDoActionArgs {\n\n        public ItemStack icon;\n\n    }\n\n    public static class IslandChangeWarpLocation extends IslandWarpDoActionArgs {\n\n        public Location location;\n\n    }\n\n    public static class IslandChangeWarpsLimit extends IslandDoActionArgs {\n\n        public int warpsLimit;\n\n    }\n\n    public static class IslandChangeWorthBonus extends IslandDoActionArgs {\n\n        public IslandChangeWorthBonusEvent.Reason reason;\n        public BigDecimal worthBonus;\n\n    }\n\n    public static class IslandChangeRolePrivilege extends IslandDoActionArgs {\n\n        public PlayerRole playerRole;\n\n    }\n\n    public static class IslandChat extends IslandDoActionArgs {\n\n        public String message;\n\n    }\n\n    public static class IslandChunkReset extends PluginEventArgs {\n\n        public Island island;\n        public ChunkPosition chunkPosition;\n\n    }\n\n    public static class IslandClearFlags extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandClearGeneratorRates extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandClearPlayerPrivileges extends IslandDoActionArgs {\n\n        public SuperiorPlayer privilegedPlayer;\n\n    }\n\n    public static class IslandClearRatings extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandClearRolesPrivileges extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandClose extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandCloseWarp extends IslandWarpDoActionArgs {\n\n    }\n\n    public static class IslandCoopPlayer extends IslandDoActionArgs {\n\n        public SuperiorPlayer targetPlayer;\n\n    }\n\n    public static class IslandCreate extends IslandDoActionArgs {\n\n        public String schematicName;\n        public boolean canTeleport = true;\n\n    }\n\n    public static class IslandCreateWarpCategory extends IslandDoActionArgs {\n\n        public String categoryName;\n\n    }\n\n    public static class IslandCreateWarp extends IslandDoActionArgs {\n\n        public String warpName;\n        public boolean openToPublic;\n        public Location location;\n        public WarpCategory warpCategory;\n\n    }\n\n    public static class IslandDeleteWarp extends IslandWarpDoActionArgs {\n\n    }\n\n    public static class IslandDisableFlag extends IslandDoActionArgs {\n\n        public IslandFlag islandFlag;\n\n    }\n\n    public static class IslandDisband extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandEnableFlag extends IslandDoActionArgs {\n\n        public IslandFlag islandFlag;\n\n    }\n\n    public static class IslandEnter extends IslandDoActionArgs {\n\n        public IslandEnterEvent.EnterCause enterCause;\n\n    }\n\n    public static class IslandEnterPortal extends IslandDoActionArgs {\n\n        public PortalType portalType;\n        public Dimension destination;\n        public Schematic schematic;\n        public boolean ignoreInvalidSchematic;\n\n    }\n\n    public static class IslandEnterProtected extends IslandEnter {\n\n    }\n\n    public static class IslandGenerateBlock extends PluginEventArgs {\n\n        public Island island;\n        public Location location;\n        public Key block;\n        public boolean placeBlock = true;\n\n    }\n\n    public static class IslandHomeTeleport extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandInvite extends IslandDoActionArgs {\n\n        public SuperiorPlayer targetPlayer;\n\n    }\n\n    public static class IslandJoin extends IslandDoActionArgs {\n\n        public IslandJoinEvent.Cause joinCause;\n\n    }\n\n    public static class IslandKick extends IslandDoActionArgs {\n\n        public SuperiorPlayer targetPlayer;\n\n    }\n\n    public static class IslandLeave extends IslandDoActionArgs {\n\n        public IslandLeaveEvent.LeaveCause leaveCause;\n        public Location location;\n\n    }\n\n    public static class IslandLeaveProtected extends IslandLeave {\n\n    }\n\n    public static class IslandLockWorld extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandOpen extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandOpenWarp extends IslandWarpDoActionArgs {\n\n    }\n\n    public static class IslandQuit extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandRate extends IslandDoActionArgs {\n\n        public SuperiorPlayer ratingPlayer;\n        public Rating rating;\n\n    }\n\n    public static class IslandRemoveBlockLimit extends IslandDoActionArgs {\n\n        public Key block;\n\n    }\n\n    public static class IslandRemoveEffect extends IslandDoActionArgs {\n\n        public PotionEffectType effectType;\n\n    }\n\n    public static class IslandRemoveEntityLimit extends IslandDoActionArgs {\n\n        public Key entity;\n\n    }\n\n    public static class IslandRemoveGeneratorRate extends IslandDoActionArgs {\n\n        public Key block;\n        public Dimension dimension;\n\n    }\n\n    public static class IslandRemoveRating extends IslandDoActionArgs {\n\n        public SuperiorPlayer ratingPlayer;\n\n    }\n\n    public static class IslandRemoveRoleLimit extends IslandDoActionArgs {\n\n        public PlayerRole playerRole;\n\n    }\n\n    public static class IslandRemoveVisitorHome extends IslandDoActionArgs {\n\n    }\n\n    public static class IslandRename extends IslandDoActionArgs {\n\n        public String islandName;\n\n    }\n\n    public static class IslandRenameWarpCategory extends WarpCategoryDoActionArgs {\n\n        public String categoryName;\n\n    }\n\n    public static class IslandRenameWarp extends IslandWarpDoActionArgs {\n\n        public String warpName;\n\n    }\n\n    public static class IslandRestrictMove extends IslandDoActionArgs {\n\n        public IslandRestrictMoveEvent.RestrictReason restrictReason;\n\n    }\n\n    public static class IslandSchematicPaste extends IslandDoActionArgs {\n\n        public String schematicName;\n        public Location location;\n\n    }\n\n    public static class IslandSetHome extends IslandDoActionArgs {\n\n        public Location islandHome;\n        public IslandSetHomeEvent.Reason reason;\n\n    }\n\n    public static class IslandSetVisitorHome extends IslandDoActionArgs {\n\n        public Location islandVisitorHome;\n\n    }\n\n    public static class IslandTransfer extends IslandDoActionArgs {\n\n        public SuperiorPlayer previousOwner;\n\n    }\n\n    public static class IslandUnban extends IslandDoActionArgs {\n\n        public SuperiorPlayer unbannedPlayer;\n\n    }\n\n    public static class IslandUncoopPlayer extends IslandDoActionArgs {\n\n        public SuperiorPlayer targetPlayer;\n        public IslandUncoopPlayerEvent.UncoopReason uncoopReason;\n\n    }\n\n    public static class IslandUnlockWorld extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandUpgrade extends IslandDoActionArgs {\n\n        public Upgrade upgrade;\n        public UpgradeLevel nextLevel;\n        public List<String> commands;\n        public IslandUpgradeEvent.Cause upgradeCause;\n        public UpgradeCost upgradeCost;\n\n    }\n\n    public static class IslandVisitorHomeTeleport extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandWarpTeleport extends IslandWarpDoActionArgs {\n\n    }\n\n    public static class IslandWorldReset extends IslandDoActionArgs {\n\n        public Dimension dimension;\n\n    }\n\n    public static class IslandWorthCalculated extends IslandDoActionArgs {\n\n        public BigDecimal islandLevel;\n        public BigDecimal islandWorth;\n\n    }\n\n    public static class IslandWorthUpdate extends PluginEventArgs {\n\n        public Island island;\n        public BigDecimal oldWorth;\n        public BigDecimal oldLevel;\n        public BigDecimal newWorth;\n        public BigDecimal newLevel;\n\n    }\n\n    public static class MissionComplete extends MissionArgs {\n\n        public List<ItemStack> itemRewards;\n        public List<String> commandRewards;\n\n    }\n\n    public static class MissionReset extends MissionArgs {\n\n    }\n\n    public static class PlayerChangeBorderColor extends PlayerDoActionArgs {\n\n        public BorderColor borderColor;\n\n    }\n\n    public static class PlayerChangeLanguage extends PlayerDoActionArgs {\n\n        public Locale language;\n\n    }\n\n    public static class PlayerChangeName extends PlayerDoActionArgs {\n\n        public String newName;\n\n    }\n\n    public static class PlayerChangeRole extends PlayerDoActionArgs {\n\n        public PlayerRole newRole;\n\n    }\n\n    public static class PlayerCloseMenu extends PlayerDoActionArgs {\n\n        public MenuView<?, ?> menuView;\n        public MenuView<?, ?> newMenuView;\n\n    }\n\n    public static class PlayerOpenMenu extends PlayerDoActionArgs {\n\n        public MenuView<?, ?> menuView;\n\n    }\n\n    public static class PlayerReplace extends PlayerDoActionArgs {\n\n        public SuperiorPlayer newPlayer;\n\n    }\n\n    public static class PlayerToggleBlocksStacker extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerToggleBorder extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerToggleBypass extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerToggleFly extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerTogglePanel extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerToggleSpy extends PlayerDoActionArgs {\n\n    }\n\n    public static class PlayerToggleTeamChat extends PlayerDoActionArgs {\n\n    }\n\n    public static class PluginInitialized extends PluginDoActionArgs {\n\n    }\n\n    public static class PluginInitialize extends PluginDoActionArgs {\n\n        public IslandsContainer islandsContainer;\n        public PlayersContainer playersContainer;\n\n    }\n\n    public static class PluginLoadData extends PluginDoActionArgs {\n\n    }\n\n    public static class PostIslandCreate extends IslandDoActionArgs {\n\n    }\n\n    public static class PreIslandCreate extends PluginEventArgs {\n\n        public SuperiorPlayer superiorPlayer;\n        public String islandName;\n\n    }\n\n    public static class SendMessage extends PluginEventArgs {\n\n        public CommandSender receiver;\n        public String messageType;\n        public IMessageComponent messageComponent;\n        public Object[] args;\n\n    }\n\n    private static class StackedBlockChangeCountArgs extends PluginEventArgs {\n\n        public Block block;\n        public Player player;\n        public int originalCount;\n        public int newCount;\n\n    }\n\n    private static class IslandBankTransactionArgs extends PluginEventArgs {\n\n        public Island island;\n        public SuperiorPlayer superiorPlayer;\n        public BigDecimal amount;\n        public String failureReason;\n\n    }\n\n    private static class IslandDoActionArgs extends PluginEventArgs {\n\n        public Island island;\n        public SuperiorPlayer superiorPlayer;\n\n    }\n\n    private static class WarpCategoryDoActionArgs extends IslandDoActionArgs {\n\n        public WarpCategory warpCategory;\n\n    }\n\n    private static class IslandWarpDoActionArgs extends IslandDoActionArgs {\n\n        public IslandWarp islandWarp;\n\n    }\n\n    private static class MissionArgs extends PluginEventArgs {\n\n        public SuperiorPlayer superiorPlayer;\n        public IMissionsHolder missionsHolder;\n        public Mission<?> mission;\n\n    }\n\n    private static class PlayerDoActionArgs extends PluginEventArgs {\n\n        public SuperiorPlayer superiorPlayer;\n\n    }\n\n    private static class PluginDoActionArgs extends PluginEventArgs {\n\n        public SuperiorSkyblock plugin;\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.plugin;\n\nimport com.bgsoftware.superiorskyblock.core.events.IEvent;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\n\npublic class PluginEvent<Args extends PluginEventArgs> implements IEvent<PluginEventType<?>> {\n\n    private final PluginEventType<Args> type;\n    private final Args args;\n\n    private boolean cancelled = false;\n\n    public PluginEvent(PluginEventType<Args> type, Args args) {\n        this.type = type;\n        this.args = args;\n    }\n\n    @Override\n    public PluginEventType<Args> getType() {\n        return type;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return this.cancelled;\n    }\n\n    public Args getArgs() {\n        return args;\n    }\n\n    public void setCancelled() {\n        this.cancelled = true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.plugin;\n\npublic enum PluginEventPriority {\n\n    NORMAL\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.plugin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.events.AttemptPlayerSendMessageEvent;\nimport com.bgsoftware.superiorskyblock.api.events.BlockStackEvent;\nimport com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandBanEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandBankDepositEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandBankWithdrawEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandBiomeChangeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeBankLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeBlockLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeBorderSizeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeCoopLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeCropGrowthEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeDescriptionEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeDiscordEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeEffectLevelEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeEntityLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeMembersLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeMobDropsEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangePaypalEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangePlayerPrivilegeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeRoleLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeRolePrivilegeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeSpawnerRatesEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategoryIconEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategorySlotEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpIconEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpLocationEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpsLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChatEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandClearFlagsEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandClearGeneratorRatesEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandClearPlayerPrivilegesEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandClearRatingsEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandClearRolesPrivilegesEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCloseEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCloseWarpEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpCategoryEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandDeleteWarpEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandDisableFlagEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnableFlagEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterProtectedEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandHomeTeleportEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandInviteEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandKickEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLeaveProtectedEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLockWorldEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandOpenEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandOpenWarpEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandQuitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveBlockLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveEffectEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveEntityLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveGeneratorRateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveRatingEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveRoleLimitEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRemoveVisitorHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRenameEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpCategoryEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSchematicPasteEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetVisitorHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUnbanEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandVisitorHomeTeleportEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandWarpTeleportEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandWorthUpdateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent;\nimport com.bgsoftware.superiorskyblock.api.events.MissionResetEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerChangeBorderColorEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerChangeLanguageEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerChangeNameEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerChangeRoleEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerCloseMenuEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerOpenMenuEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerReplaceEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleBlocksStackerEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleBorderEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleBypassEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleFlyEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerTogglePanelEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleSpyEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PlayerToggleTeamChatEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PluginInitializeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PluginLoadDataEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PostIslandCreateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.PreIslandCreateEvent;\nimport com.bgsoftware.superiorskyblock.api.events.SendMessageEvent;\nimport com.bgsoftware.superiorskyblock.core.events.EventType;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.AttemptPlayerSendMessage;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockStack;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockUnstack;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.Empty;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBan;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankDeposit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankWithdraw;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBiomeChange;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBankLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBlockLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBorderSize;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCoopLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCropGrowth;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDescription;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDiscord;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEffectLevel;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEntityLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeGeneratorRate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeLevelBonus;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMembersLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMobDrops;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePaypal;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePlayerPrivilege;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRoleLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRolePrivilege;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeSpawnerRates;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategoryIcon;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategorySlot;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpIcon;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpLocation;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpsLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearFlags;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRolesPrivileges;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClose;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCloseWarp;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCoopPlayer;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarp;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarpCategory;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDeleteWarp;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisableFlag;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisband;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnableFlag;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnter;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandHomeTeleport;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeave;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeaveProtected;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLockWorld;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpen;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpenWarp;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandQuit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEntityLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveVisitorHome;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRename;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarp;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarpCategory;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRestrictMove;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSchematicPaste;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetHome;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetVisitorHome;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandTransfer;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnban;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandVisitorHomeTeleport;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWarpTeleport;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionComplete;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionReset;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeBorderColor;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeLanguage;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeName;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeRole;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerCloseMenu;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerOpenMenu;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerReplace;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBlocksStacker;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBorder;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBypass;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleFly;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerTogglePanel;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleSpy;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleTeamChat;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialize;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialized;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginLoadData;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PostIslandCreate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate;\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage;\n\npublic abstract class PluginEventType<Args extends PluginEventArgs> extends EventType<Args, PluginEvent<Args>> {\n\n    private static final List<PluginEventType<?>> ALL_TYPES = new LinkedList<>();\n\n    public static final PluginEventType<Empty> SETTINGS_UPDATE_EVENT = new PluginEventType<Empty>(null) {\n        @Override\n        public Event createBukkitEvent(Empty args) {\n            return null;\n        }\n    };\n    public static final PluginEventType<Empty> COMMANDS_UPDATE_EVENT = new PluginEventType<Empty>(null) {\n        @Override\n        public Event createBukkitEvent(Empty args) {\n            return null;\n        }\n    };\n    public static final PluginEventType<Empty> SPAWN_UPDATE_EVENT = new PluginEventType<Empty>(null) {\n        @Override\n        public Event createBukkitEvent(Empty args) {\n            return null;\n        }\n    };\n    public static final PluginEventType<Empty> WORLD_PROVIDER_UPDATE_EVENT = new PluginEventType<Empty>(null) {\n        @Override\n        public Event createBukkitEvent(Empty args) {\n            return null;\n        }\n    };\n\n    public static final PluginEventType<AttemptPlayerSendMessage> ATTEMPT_PLAYER_SEND_MESSAGE_EVENT = new PluginEventType<AttemptPlayerSendMessage>(AttemptPlayerSendMessageEvent.class) {\n        @Override\n        public Event createBukkitEvent(AttemptPlayerSendMessage args) {\n            return new AttemptPlayerSendMessageEvent(args.receiver, args.messageType, args.args);\n        }\n    };\n    public static final PluginEventType<BlockStack> BLOCK_STACK_EVENT = new PluginEventType<BlockStack>(BlockStackEvent.class) {\n        @Override\n        public Event createBukkitEvent(BlockStack args) {\n            return new BlockStackEvent(args.block, args.player, args.originalCount, args.newCount);\n        }\n    };\n    public static final PluginEventType<BlockUnstack> BLOCK_UNSTACK_EVENT = new PluginEventType<BlockUnstack>(BlockUnstackEvent.class) {\n        @Override\n        public Event createBukkitEvent(BlockUnstack args) {\n            return new BlockUnstackEvent(args.block, args.player, args.originalCount, args.newCount);\n        }\n    };\n    public static final PluginEventType<IslandBan> ISLAND_BAN_EVENT = new PluginEventType<IslandBan>(IslandBanEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandBan args) {\n            return new IslandBanEvent(args.superiorPlayer, args.targetPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandBankDeposit> ISLAND_BANK_DEPOSIT_EVENT = new PluginEventType<IslandBankDeposit>(IslandBankDepositEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandBankDeposit args) {\n            return new IslandBankDepositEvent(args.superiorPlayer, args.island, args.amount);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandBankDeposit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().failureReason = ((IslandBankDepositEvent) bukkitEvent).getFailureReason();\n        }\n    };\n    public static final PluginEventType<IslandBankWithdraw> ISLAND_BANK_WITHDRAW_EVENT = new PluginEventType<IslandBankWithdraw>(IslandBankWithdrawEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandBankWithdraw args) {\n            return new IslandBankWithdrawEvent(args.superiorPlayer, args.island, args.amount);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandBankWithdraw> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().failureReason = ((IslandBankWithdrawEvent) bukkitEvent).getFailureReason();\n        }\n    };\n    public static final PluginEventType<IslandBiomeChange> ISLAND_BIOME_CHANGE_EVENT = new PluginEventType<IslandBiomeChange>(IslandBiomeChangeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandBiomeChange args) {\n            return new IslandBiomeChangeEvent(args.superiorPlayer, args.island, args.biome);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandBiomeChange> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().biome = ((IslandBiomeChangeEvent) bukkitEvent).getBiome();\n        }\n    };\n    public static final PluginEventType<IslandChangeBankLimit> ISLAND_CHANGE_BANK_LIMIT_EVENT = new PluginEventType<IslandChangeBankLimit>(IslandChangeBankLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeBankLimit args) {\n            return new IslandChangeBankLimitEvent(args.superiorPlayer, args.island, args.bankLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeBankLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().bankLimit = ((IslandChangeBankLimitEvent) bukkitEvent).getBankLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeBlockLimit> ISLAND_CHANGE_BLOCK_LIMIT_EVENT = new PluginEventType<IslandChangeBlockLimit>(IslandChangeBlockLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeBlockLimit args) {\n            return new IslandChangeBlockLimitEvent(args.superiorPlayer, args.island, args.block, args.blockLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeBlockLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().blockLimit = ((IslandChangeBlockLimitEvent) bukkitEvent).getBlockLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeBorderSize> ISLAND_CHANGE_BORDER_SIZE_EVENT = new PluginEventType<IslandChangeBorderSize>(IslandChangeBorderSizeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeBorderSize args) {\n            return new IslandChangeBorderSizeEvent(args.superiorPlayer, args.island, args.borderSize);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeBorderSize> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().borderSize = ((IslandChangeBorderSizeEvent) bukkitEvent).getBorderSize();\n        }\n    };\n    public static final PluginEventType<IslandChangeCoopLimit> ISLAND_CHANGE_COOP_LIMIT_EVENT = new PluginEventType<IslandChangeCoopLimit>(IslandChangeCoopLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeCoopLimit args) {\n            return new IslandChangeCoopLimitEvent(args.superiorPlayer, args.island, args.coopLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeCoopLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().coopLimit = ((IslandChangeCoopLimitEvent) bukkitEvent).getCoopLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeCropGrowth> ISLAND_CHANGE_CROP_GROWTH_EVENT = new PluginEventType<IslandChangeCropGrowth>(IslandChangeCropGrowthEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeCropGrowth args) {\n            return new IslandChangeCropGrowthEvent(args.superiorPlayer, args.island, args.cropGrowth);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeCropGrowth> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().cropGrowth = ((IslandChangeCropGrowthEvent) bukkitEvent).getCropGrowth();\n        }\n    };\n    public static final PluginEventType<IslandChangeDescription> ISLAND_CHANGE_DESCRIPTION_EVENT = new PluginEventType<IslandChangeDescription>(IslandChangeDescriptionEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeDescription args) {\n            return new IslandChangeDescriptionEvent(args.island, args.superiorPlayer, args.description);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeDescription> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().description = ((IslandChangeDescriptionEvent) bukkitEvent).getDescription();\n        }\n    };\n    public static final PluginEventType<IslandChangeDiscord> ISLAND_CHANGE_DISCORD_EVENT = new PluginEventType<IslandChangeDiscord>(IslandChangeDiscordEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeDiscord args) {\n            return new IslandChangeDiscordEvent(args.superiorPlayer, args.island, args.discord);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeDiscord> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().discord = ((IslandChangeDiscordEvent) bukkitEvent).getDiscord();\n        }\n    };\n    public static final PluginEventType<IslandChangeEffectLevel> ISLAND_CHANGE_EFFECT_LEVEL_EVENT = new PluginEventType<IslandChangeEffectLevel>(IslandChangeEffectLevelEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeEffectLevel args) {\n            return new IslandChangeEffectLevelEvent(args.superiorPlayer, args.island, args.effectType, args.effectLevel);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeEffectLevel> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().effectLevel = ((IslandChangeEffectLevelEvent) bukkitEvent).getEffectLevel();\n        }\n    };\n    public static final PluginEventType<IslandChangeEntityLimit> ISLAND_CHANGE_ENTITY_LIMIT_EVENT = new PluginEventType<IslandChangeEntityLimit>(IslandChangeEntityLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeEntityLimit args) {\n            return new IslandChangeEntityLimitEvent(args.superiorPlayer, args.island, args.entity, args.entityLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeEntityLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().entityLimit = ((IslandChangeEntityLimitEvent) bukkitEvent).getEntityLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeGeneratorRate> ISLAND_CHANGE_GENERATOR_RATE_EVENT = new PluginEventType<IslandChangeGeneratorRate>(IslandChangeGeneratorRateEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeGeneratorRate args) {\n            return new IslandChangeGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension, args.generatorRate);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeGeneratorRate> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().generatorRate = ((IslandChangeGeneratorRateEvent) bukkitEvent).getGeneratorRate();\n        }\n    };\n    public static final PluginEventType<IslandChangeLevelBonus> ISLAND_CHANGE_LEVEL_BONUS_EVENT = new PluginEventType<IslandChangeLevelBonus>(IslandChangeLevelBonusEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeLevelBonus args) {\n            return new IslandChangeLevelBonusEvent(args.superiorPlayer, args.island, args.reason, args.levelBonus);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeLevelBonus> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().levelBonus = ((IslandChangeLevelBonusEvent) bukkitEvent).getLevelBonus();\n        }\n    };\n    public static final PluginEventType<IslandChangeMembersLimit> ISLAND_CHANGE_MEMBERS_LIMIT_EVENT = new PluginEventType<IslandChangeMembersLimit>(IslandChangeMembersLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeMembersLimit args) {\n            return new IslandChangeMembersLimitEvent(args.superiorPlayer, args.island, args.membersLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeMembersLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().membersLimit = ((IslandChangeMembersLimitEvent) bukkitEvent).getMembersLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeMobDrops> ISLAND_CHANGE_MOB_DROPS_EVENT = new PluginEventType<IslandChangeMobDrops>(IslandChangeMobDropsEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeMobDrops args) {\n            return new IslandChangeMobDropsEvent(args.superiorPlayer, args.island, args.mobDrops);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeMobDrops> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().mobDrops = ((IslandChangeMobDropsEvent) bukkitEvent).getMobDrops();\n        }\n    };\n    public static final PluginEventType<IslandChangePaypal> ISLAND_CHANGE_PAYPAL_EVENT = new PluginEventType<IslandChangePaypal>(IslandChangePaypalEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangePaypal args) {\n            return new IslandChangePaypalEvent(args.superiorPlayer, args.island, args.paypal);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangePaypal> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().paypal = ((IslandChangePaypalEvent) bukkitEvent).getPaypal();\n        }\n    };\n    public static final PluginEventType<IslandChangePlayerPrivilege> ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT = new PluginEventType<IslandChangePlayerPrivilege>(IslandChangePlayerPrivilegeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangePlayerPrivilege args) {\n            return new IslandChangePlayerPrivilegeEvent(args.island, args.superiorPlayer, args.privilegedPlayer, args.privilegeEnabled);\n        }\n    };\n    public static final PluginEventType<IslandChangeRoleLimit> ISLAND_CHANGE_ROLE_LIMIT_EVENT = new PluginEventType<IslandChangeRoleLimit>(IslandChangeRoleLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeRoleLimit args) {\n            return new IslandChangeRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole, args.roleLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeRoleLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().roleLimit = ((IslandChangeRoleLimitEvent) bukkitEvent).getRoleLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeSpawnerRates> ISLAND_CHANGE_SPAWNER_RATES_EVENT = new PluginEventType<IslandChangeSpawnerRates>(IslandChangeSpawnerRatesEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeSpawnerRates args) {\n            return new IslandChangeSpawnerRatesEvent(args.superiorPlayer, args.island, args.spawnerRates);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeSpawnerRates> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().spawnerRates = ((IslandChangeSpawnerRatesEvent) bukkitEvent).getSpawnerRates();\n        }\n    };\n    public static final PluginEventType<IslandChangeWarpCategoryIcon> ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT = new PluginEventType<IslandChangeWarpCategoryIcon>(IslandChangeWarpIconEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWarpCategoryIcon args) {\n            return new IslandChangeWarpCategoryIconEvent(args.superiorPlayer, args.island, args.warpCategory, args.icon);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWarpCategoryIcon> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().icon = ((IslandChangeWarpCategoryIconEvent) bukkitEvent).getIcon();\n        }\n    };\n    public static final PluginEventType<IslandChangeWarpCategorySlot> ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT = new PluginEventType<IslandChangeWarpCategorySlot>(IslandChangeWarpCategorySlotEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWarpCategorySlot args) {\n            return new IslandChangeWarpCategorySlotEvent(args.superiorPlayer, args.island, args.warpCategory, args.slot, args.maxSlot);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWarpCategorySlot> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().slot = ((IslandChangeWarpCategorySlotEvent) bukkitEvent).getSlot();\n        }\n    };\n    public static final PluginEventType<IslandChangeWarpIcon> ISLAND_CHANGE_WARP_ICON_EVENT = new PluginEventType<IslandChangeWarpIcon>(IslandChangeWarpIconEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWarpIcon args) {\n            return new IslandChangeWarpIconEvent(args.superiorPlayer, args.island, args.islandWarp, args.icon);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWarpIcon> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().icon = ((IslandChangeWarpIconEvent) bukkitEvent).getIcon();\n        }\n    };\n    public static final PluginEventType<IslandChangeWarpLocation> ISLAND_CHANGE_WARP_LOCATION_EVENT = new PluginEventType<IslandChangeWarpLocation>(IslandChangeWarpLocationEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWarpLocation args) {\n            return new IslandChangeWarpLocationEvent(args.superiorPlayer, args.island, args.islandWarp, args.location);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWarpLocation> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().location = ((IslandChangeWarpLocationEvent) bukkitEvent).getLocation();\n        }\n    };\n    public static final PluginEventType<IslandChangeWarpsLimit> ISLAND_CHANGE_WARPS_LIMIT_EVENT = new PluginEventType<IslandChangeWarpsLimit>(IslandChangeWarpsLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWarpsLimit args) {\n            return new IslandChangeWarpsLimitEvent(args.superiorPlayer, args.island, args.warpsLimit);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWarpsLimit> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().warpsLimit = ((IslandChangeWarpsLimitEvent) bukkitEvent).getWarpsLimit();\n        }\n    };\n    public static final PluginEventType<IslandChangeWorthBonus> ISLAND_CHANGE_WORTH_BONUS_EVENT = new PluginEventType<IslandChangeWorthBonus>(IslandChangeWorthBonusEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeWorthBonus args) {\n            return new IslandChangeWorthBonusEvent(args.superiorPlayer, args.island, args.reason, args.worthBonus);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChangeWorthBonus> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().worthBonus = ((IslandChangeWorthBonusEvent) bukkitEvent).getWorthBonus();\n        }\n    };\n    public static final PluginEventType<IslandChangeRolePrivilege> ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT = new PluginEventType<IslandChangeRolePrivilege>(IslandChangeRolePrivilegeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChangeRolePrivilege args) {\n            return new IslandChangeRolePrivilegeEvent(args.island, args.superiorPlayer, args.playerRole);\n        }\n    };\n    public static final PluginEventType<IslandChat> ISLAND_CHAT_EVENT = new PluginEventType<IslandChat>(IslandChatEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChat args) {\n            return new IslandChatEvent(args.island, args.superiorPlayer, args.message);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChat> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().message = ((IslandChatEvent) bukkitEvent).getMessage();\n        }\n    };\n    public static final PluginEventType<IslandChunkReset> ISLAND_CHUNK_RESET_EVENT = new PluginEventType<IslandChunkReset>(IslandChunkResetEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandChunkReset args) {\n            return new IslandChunkResetEvent(args.island, args.chunkPosition.getWorld(), args.chunkPosition.getX(),\n                    args.chunkPosition.getZ());\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandChunkReset> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<IslandClearGeneratorRates> ISLAND_CLEAR_GENERATOR_RATES_EVENT = new PluginEventType<IslandClearGeneratorRates>(IslandClearGeneratorRatesEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClearGeneratorRates args) {\n            return new IslandClearGeneratorRatesEvent(args.superiorPlayer, args.island, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandClearPlayerPrivileges> ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT = new PluginEventType<IslandClearPlayerPrivileges>(IslandClearPlayerPrivilegesEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClearPlayerPrivileges args) {\n            return new IslandClearPlayerPrivilegesEvent(args.island, args.superiorPlayer, args.privilegedPlayer);\n        }\n    };\n    public static final PluginEventType<IslandClearRatings> ISLAND_CLEAR_RATINGS_EVENT = new PluginEventType<IslandClearRatings>(IslandClearRatingsEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClearRatings args) {\n            return new IslandClearRatingsEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandClearRolesPrivileges> ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT = new PluginEventType<IslandClearRolesPrivileges>(IslandClearRolesPrivilegesEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClearRolesPrivileges args) {\n            return new IslandClearRolesPrivilegesEvent(args.island, args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<IslandClose> ISLAND_CLOSE_EVENT = new PluginEventType<IslandClose>(IslandCloseEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClose args) {\n            return new IslandCloseEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandCloseWarp> ISLAND_CLOSE_WARP_EVENT = new PluginEventType<IslandCloseWarp>(IslandCloseWarpEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandCloseWarp args) {\n            return new IslandCloseWarpEvent(args.superiorPlayer, args.island, args.islandWarp);\n        }\n    };\n    public static final PluginEventType<IslandCoopPlayer> ISLAND_COOP_PLAYER_EVENT = new PluginEventType<IslandCoopPlayer>(IslandCoopPlayerEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandCoopPlayer args) {\n            return new IslandCoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer);\n        }\n    };\n    public static final PluginEventType<IslandCreate> ISLAND_CREATE_EVENT = new PluginEventType<IslandCreate>(IslandCreateEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandCreate args) {\n            return new IslandCreateEvent(args.superiorPlayer, args.island, args.schematicName, args.canTeleport);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandCreate> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().canTeleport = ((IslandCreateEvent) bukkitEvent).canTeleport();\n        }\n    };\n    public static final PluginEventType<IslandCreateWarpCategory> ISLAND_CREATE_WARP_CATEGORY_EVENT = new PluginEventType<IslandCreateWarpCategory>(IslandCreateWarpCategoryEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandCreateWarpCategory args) {\n            return new IslandCreateWarpCategoryEvent(args.superiorPlayer, args.island, args.categoryName);\n        }\n    };\n    public static final PluginEventType<IslandCreateWarp> ISLAND_CREATE_WARP_EVENT = new PluginEventType<IslandCreateWarp>(IslandCreateWarpEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandCreateWarp args) {\n            return new IslandCreateWarpEvent(args.superiorPlayer, args.island, args.warpName, args.location, args.openToPublic, args.warpCategory);\n        }\n    };\n    public static final PluginEventType<IslandDeleteWarp> ISLAND_DELETE_WARP_EVENT = new PluginEventType<IslandDeleteWarp>(IslandDeleteWarpEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandDeleteWarp args) {\n            return new IslandDeleteWarpEvent(args.superiorPlayer, args.island, args.islandWarp);\n        }\n    };\n    public static final PluginEventType<IslandDisableFlag> ISLAND_DISABLE_FLAG_EVENT = new PluginEventType<IslandDisableFlag>(IslandDisableFlagEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandDisableFlag args) {\n            return new IslandDisableFlagEvent(args.superiorPlayer, args.island, args.islandFlag);\n        }\n    };\n    public static final PluginEventType<IslandDisband> ISLAND_DISBAND_EVENT = new PluginEventType<IslandDisband>(IslandDisbandEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandDisband args) {\n            return new IslandDisbandEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandEnableFlag> ISLAND_ENABLE_FLAG_EVENT = new PluginEventType<IslandEnableFlag>(IslandEnableFlagEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandEnableFlag args) {\n            return new IslandEnableFlagEvent(args.superiorPlayer, args.island, args.islandFlag);\n        }\n    };\n    public static final PluginEventType<IslandClearFlags> ISLAND_CLEAR_FLAGS_EVENT = new PluginEventType<IslandClearFlags>(IslandClearFlagsEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandClearFlags args) {\n            return new IslandClearFlagsEvent(args.island, args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<IslandEnter> ISLAND_ENTER_EVENT = new PluginEventType<IslandEnter>(IslandEnterEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandEnter args) {\n            return new IslandEnterEvent(args.superiorPlayer, args.island, args.enterCause);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandEnter> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n\n            IslandEnterEvent islandEnterEvent = (IslandEnterEvent) bukkitEvent;\n\n            if (islandEnterEvent.isCancelled() && islandEnterEvent.getCancelTeleport() != null)\n                pluginEvent.getArgs().superiorPlayer.teleport(islandEnterEvent.getCancelTeleport());\n        }\n    };\n    public static final PluginEventType<IslandEnterPortal> ISLAND_ENTER_PORTAL_EVENT = new PluginEventType<IslandEnterPortal>(IslandEnterPortalEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandEnterPortal args) {\n            return new IslandEnterPortalEvent(args.island, args.superiorPlayer, args.portalType, args.destination,\n                    args.schematic, args.ignoreInvalidSchematic);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandEnterPortal> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().destination = ((IslandEnterPortalEvent) bukkitEvent).getDestinationDimension();\n            pluginEvent.getArgs().schematic = ((IslandEnterPortalEvent) bukkitEvent).getSchematic();\n            pluginEvent.getArgs().ignoreInvalidSchematic = ((IslandEnterPortalEvent) bukkitEvent).isIgnoreInvalidSchematic();\n        }\n    };\n    public static final PluginEventType<IslandEnterProtected> ISLAND_ENTER_PROTECTED_EVENT = new PluginEventType<IslandEnterProtected>(IslandEnterProtectedEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandEnterProtected args) {\n            return new IslandEnterProtectedEvent(args.superiorPlayer, args.island, args.enterCause);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandEnterProtected> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n\n            IslandEnterProtectedEvent islandEnterProtectedEvent = (IslandEnterProtectedEvent) bukkitEvent;\n\n            if (islandEnterProtectedEvent.isCancelled() && islandEnterProtectedEvent.getCancelTeleport() != null)\n                pluginEvent.getArgs().superiorPlayer.teleport(islandEnterProtectedEvent.getCancelTeleport());\n        }\n    };\n    public static final PluginEventType<IslandGenerateBlock> ISLAND_GENERATE_BLOCK_EVENT = new PluginEventType<IslandGenerateBlock>(IslandGenerateBlockEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandGenerateBlock args) {\n            return new IslandGenerateBlockEvent(args.island, args.location, args.block);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandGenerateBlock> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().block = ((IslandGenerateBlockEvent) bukkitEvent).getBlock();\n            pluginEvent.getArgs().placeBlock = ((IslandGenerateBlockEvent) bukkitEvent).isPlaceBlock();\n        }\n    };\n    public static final PluginEventType<IslandHomeTeleport> ISLAND_HOME_TELEPORT_EVENT = new PluginEventType<IslandHomeTeleport>(IslandHomeTeleportEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandHomeTeleport args) {\n            return new IslandHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandInvite> ISLAND_INVITE_EVENT = new PluginEventType<IslandInvite>(IslandInviteEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandInvite args) {\n            return new IslandInviteEvent(args.superiorPlayer, args.targetPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandJoin> ISLAND_JOIN_EVENT = new PluginEventType<IslandJoin>(IslandJoinEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandJoin args) {\n            return new IslandJoinEvent(args.superiorPlayer, args.island, args.joinCause);\n        }\n    };\n    public static final PluginEventType<IslandKick> ISLAND_KICK_EVENT = new PluginEventType<IslandKick>(IslandKickEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandKick args) {\n            return new IslandKickEvent(args.superiorPlayer, args.targetPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandLeave> ISLAND_LEAVE_EVENT = new PluginEventType<IslandLeave>(IslandLeaveEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandLeave args) {\n            return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location);\n        }\n    };\n    public static final PluginEventType<IslandLeaveProtected> ISLAND_LEAVE_PROTECTED_EVENT = new PluginEventType<IslandLeaveProtected>(IslandLeaveProtectedEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandLeaveProtected args) {\n            return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location);\n        }\n    };\n    public static final PluginEventType<IslandLockWorld> ISLAND_LOCK_WORLD_EVENT = new PluginEventType<IslandLockWorld>(IslandLockWorldEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandLockWorld args) {\n            return new IslandLockWorldEvent(args.island, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandOpen> ISLAND_OPEN_EVENT = new PluginEventType<IslandOpen>(IslandOpenEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandOpen args) {\n            return new IslandOpenEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandOpenWarp> ISLAND_OPEN_WARP_EVENT = new PluginEventType<IslandOpenWarp>(IslandOpenWarpEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandOpenWarp args) {\n            return new IslandOpenWarpEvent(args.superiorPlayer, args.island, args.islandWarp);\n        }\n    };\n    public static final PluginEventType<IslandQuit> ISLAND_QUIT_EVENT = new PluginEventType<IslandQuit>(IslandQuitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandQuit args) {\n            return new IslandQuitEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandRate> ISLAND_RATE_EVENT = new PluginEventType<IslandRate>(IslandRateEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRate args) {\n            return new IslandRateEvent(args.superiorPlayer, args.ratingPlayer, args.island, args.rating);\n        }\n    };\n    public static final PluginEventType<IslandRemoveBlockLimit> ISLAND_REMOVE_BLOCK_LIMIT_EVENT = new PluginEventType<IslandRemoveBlockLimit>(IslandRemoveBlockLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveBlockLimit args) {\n            return new IslandRemoveBlockLimitEvent(args.superiorPlayer, args.island, args.block);\n        }\n    };\n    public static final PluginEventType<IslandRemoveEffect> ISLAND_REMOVE_EFFECT_EVENT = new PluginEventType<IslandRemoveEffect>(IslandRemoveEffectEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveEffect args) {\n            return new IslandRemoveEffectEvent(args.superiorPlayer, args.island, args.effectType);\n        }\n    };\n    public static final PluginEventType<IslandRemoveEntityLimit> ISLAND_REMOVE_ENTITY_LIMIT_EVENT = new PluginEventType<IslandRemoveEntityLimit>(IslandRemoveEntityLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveEntityLimit args) {\n            return new IslandRemoveEntityLimitEvent(args.superiorPlayer, args.island, args.entity);\n        }\n    };\n    public static final PluginEventType<IslandRemoveGeneratorRate> ISLAND_REMOVE_GENERATOR_RATE_EVENT = new PluginEventType<IslandRemoveGeneratorRate>(IslandRemoveGeneratorRateEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveGeneratorRate args) {\n            return new IslandRemoveGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandRemoveRating> ISLAND_REMOVE_RATING_EVENT = new PluginEventType<IslandRemoveRating>(IslandRemoveRatingEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveRating args) {\n            return new IslandRemoveRatingEvent(args.superiorPlayer, args.ratingPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandRemoveRoleLimit> ISLAND_REMOVE_ROLE_LIMIT_EVENT = new PluginEventType<IslandRemoveRoleLimit>(IslandRemoveRoleLimitEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveRoleLimit args) {\n            return new IslandRemoveRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole);\n        }\n    };\n    public static final PluginEventType<IslandRemoveVisitorHome> ISLAND_REMOVE_VISITOR_HOME_EVENT = new PluginEventType<IslandRemoveVisitorHome>(IslandRemoveVisitorHomeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRemoveVisitorHome args) {\n            return new IslandRemoveVisitorHomeEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandRename> ISLAND_RENAME_EVENT = new PluginEventType<IslandRename>(IslandRenameEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRename args) {\n            return new IslandRenameEvent(args.island, args.superiorPlayer, args.islandName);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandRename> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().islandName = ((IslandRenameEvent) bukkitEvent).getIslandName();\n        }\n    };\n    public static final PluginEventType<IslandRenameWarpCategory> ISLAND_RENAME_WARP_CATEGORY_EVENT = new PluginEventType<IslandRenameWarpCategory>(IslandRenameWarpCategoryEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRenameWarpCategory args) {\n            return new IslandRenameWarpCategoryEvent(args.superiorPlayer, args.island, args.warpCategory, args.categoryName);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandRenameWarpCategory> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().categoryName = ((IslandRenameWarpCategoryEvent) bukkitEvent).getCategoryName();\n        }\n    };\n    public static final PluginEventType<IslandRenameWarp> ISLAND_RENAME_WARP_EVENT = new PluginEventType<IslandRenameWarp>(IslandRenameWarpEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRenameWarp args) {\n            return new IslandRenameWarpEvent(args.superiorPlayer, args.island, args.islandWarp, args.warpName);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandRenameWarp> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().warpName = ((IslandRenameWarpEvent) bukkitEvent).getWarpName();\n        }\n    };\n    public static final PluginEventType<IslandRestrictMove> ISLAND_RESTRICT_MOVE_EVENT = new PluginEventType<IslandRestrictMove>(IslandRestrictMoveEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandRestrictMove args) {\n            return new IslandRestrictMoveEvent(args.superiorPlayer, args.restrictReason);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandRestrictMove> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<IslandSchematicPaste> ISLAND_SCHEMATIC_PASTE_EVENT = new PluginEventType<IslandSchematicPaste>(IslandSchematicPasteEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandSchematicPaste args) {\n            return new IslandSchematicPasteEvent(args.island, args.schematicName, args.location);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandSchematicPaste> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<IslandSetHome> ISLAND_SET_HOME_EVENT = new PluginEventType<IslandSetHome>(IslandSetHomeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandSetHome args) {\n            return new IslandSetHomeEvent(args.island, args.islandHome, args.reason, args.superiorPlayer);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandSetHome> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().islandHome = ((IslandSetHomeEvent) bukkitEvent).getIslandHome();\n        }\n    };\n    public static final PluginEventType<IslandSetVisitorHome> ISLAND_SET_VISITOR_HOME_EVENT = new PluginEventType<IslandSetVisitorHome>(IslandSetVisitorHomeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandSetVisitorHome args) {\n            return new IslandSetVisitorHomeEvent(args.superiorPlayer, args.island, args.islandVisitorHome);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandSetVisitorHome> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().islandVisitorHome = ((IslandSetVisitorHomeEvent) bukkitEvent).getIslandVisitorHome();\n        }\n    };\n    public static final PluginEventType<IslandTransfer> ISLAND_TRANSFER_EVENT = new PluginEventType<IslandTransfer>(IslandTransferEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandTransfer args) {\n            return new IslandTransferEvent(args.island, args.previousOwner, args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<IslandUnban> ISLAND_UNBAN_EVENT = new PluginEventType<IslandUnban>(IslandUnbanEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandUnban args) {\n            return new IslandUnbanEvent(args.superiorPlayer, args.unbannedPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<IslandUncoopPlayer> ISLAND_UNCOOP_PLAYER_EVENT = new PluginEventType<IslandUncoopPlayer>(IslandUncoopPlayerEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandUncoopPlayer args) {\n            return new IslandUncoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer, args.uncoopReason);\n        }\n    };\n    public static final PluginEventType<IslandUnlockWorld> ISLAND_UNLOCK_WORLD_EVENT = new PluginEventType<IslandUnlockWorld>(IslandUnlockWorldEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandUnlockWorld args) {\n            return new IslandUnlockWorldEvent(args.island, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandUpgrade> ISLAND_UPGRADE_EVENT = new PluginEventType<IslandUpgrade>(IslandUpgradeEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandUpgrade args) {\n            return new IslandUpgradeEvent(args.superiorPlayer, args.island, args.upgrade, args.nextLevel, args.commands,\n                    args.upgradeCause, args.upgradeCost);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandUpgrade> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().commands = ((IslandUpgradeEvent) bukkitEvent).getCommands();\n            pluginEvent.getArgs().upgradeCost = ((IslandUpgradeEvent) bukkitEvent).getUpgradeCost();\n        }\n    };\n    public static final PluginEventType<IslandVisitorHomeTeleport> ISLAND_VISITOR_HOME_TELEPORT_EVENT = new PluginEventType<IslandVisitorHomeTeleport>(IslandVisitorHomeTeleportEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandVisitorHomeTeleport args) {\n            return new IslandVisitorHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandWarpTeleport> ISLAND_WARP_TELEPORT_EVENT = new PluginEventType<IslandWarpTeleport>(IslandWarpTeleportEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandWarpTeleport args) {\n            return new IslandWarpTeleportEvent(args.island, args.superiorPlayer, args.islandWarp);\n        }\n    };\n    public static final PluginEventType<IslandWorldReset> ISLAND_WORLD_RESET_EVENT = new PluginEventType<IslandWorldReset>(IslandWorldResetEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandWorldReset args) {\n            return new IslandWorldResetEvent(args.superiorPlayer, args.island, args.dimension);\n        }\n    };\n    public static final PluginEventType<IslandWorthCalculated> ISLAND_WORTH_CALCULATED_EVENT = new PluginEventType<IslandWorthCalculated>(IslandWorthCalculatedEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandWorthCalculated args) {\n            return new IslandWorthCalculatedEvent(args.island, args.superiorPlayer, args.islandLevel, args.islandWorth);\n        }\n    };\n    public static final PluginEventType<IslandWorthUpdate> ISLAND_WORTH_UPDATE_EVENT = new PluginEventType<IslandWorthUpdate>(IslandWorthUpdateEvent.class) {\n        @Override\n        public Event createBukkitEvent(IslandWorthUpdate args) {\n            return new IslandWorthUpdateEvent(args.island, args.oldWorth, args.oldLevel, args.newWorth, args.newLevel);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<IslandWorthUpdate> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<MissionComplete> MISSION_COMPLETE_EVENT = new PluginEventType<MissionComplete>(MissionCompleteEvent.class) {\n        @Override\n        public Event createBukkitEvent(MissionComplete args) {\n            return new MissionCompleteEvent(args.superiorPlayer, args.missionsHolder, args.mission, args.itemRewards, args.commandRewards);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<MissionComplete> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().itemRewards = ((MissionCompleteEvent) bukkitEvent).getItemRewards();\n            pluginEvent.getArgs().commandRewards = ((MissionCompleteEvent) bukkitEvent).getCommandRewards();\n        }\n    };\n    public static final PluginEventType<MissionReset> MISSION_RESET_EVENT = new PluginEventType<MissionReset>(MissionResetEvent.class) {\n        @Override\n        public Event createBukkitEvent(MissionReset args) {\n            return new MissionResetEvent(args.superiorPlayer, args.missionsHolder, args.mission);\n        }\n    };\n    public static final PluginEventType<PlayerChangeBorderColor> PLAYER_CHANGE_BORDER_COLOR_EVENT = new PluginEventType<PlayerChangeBorderColor>(PlayerChangeBorderColorEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerChangeBorderColor args) {\n            return new PlayerChangeBorderColorEvent(args.superiorPlayer, args.borderColor);\n        }\n    };\n    public static final PluginEventType<PlayerChangeLanguage> PLAYER_CHANGE_LANGUAGE_EVENT = new PluginEventType<PlayerChangeLanguage>(PlayerChangeLanguageEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerChangeLanguage args) {\n            return new PlayerChangeLanguageEvent(args.superiorPlayer, args.language);\n        }\n    };\n    public static final PluginEventType<PlayerChangeName> PLAYER_CHANGE_NAME_EVENT = new PluginEventType<PlayerChangeName>(PlayerChangeNameEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerChangeName args) {\n            return new PlayerChangeNameEvent(args.superiorPlayer, args.newName);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<PlayerChangeName> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<PlayerChangeRole> PLAYER_CHANGE_ROLE_EVENT = new PluginEventType<PlayerChangeRole>(PlayerChangeRoleEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerChangeRole args) {\n            return new PlayerChangeRoleEvent(args.superiorPlayer, args.newRole);\n        }\n    };\n    public static final PluginEventType<PlayerCloseMenu> PLAYER_CLOSE_MENU_EVENT = new PluginEventType<PlayerCloseMenu>(PlayerCloseMenuEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerCloseMenu args) {\n            return new PlayerCloseMenuEvent(args.superiorPlayer, args.menuView, args.newMenuView);\n        }\n    };\n    public static final PluginEventType<PlayerOpenMenu> PLAYER_OPEN_MENU_EVENT = new PluginEventType<PlayerOpenMenu>(PlayerOpenMenuEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerOpenMenu args) {\n            return new PlayerOpenMenuEvent(args.superiorPlayer, args.menuView);\n        }\n    };\n    public static final PluginEventType<PlayerReplace> PLAYER_REPLACE_EVENT = new PluginEventType<PlayerReplace>(PlayerReplaceEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerReplace args) {\n            return new PlayerReplaceEvent(args.superiorPlayer, args.newPlayer);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<PlayerReplace> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<PlayerToggleBlocksStacker> PLAYER_TOGGLE_BLOCKS_STACKER_EVENT = new PluginEventType<PlayerToggleBlocksStacker>(PlayerToggleBlocksStackerEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleBlocksStacker args) {\n            return new PlayerToggleBlocksStackerEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerToggleBorder> PLAYER_TOGGLE_BORDER_EVENT = new PluginEventType<PlayerToggleBorder>(PlayerToggleBorderEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleBorder args) {\n            return new PlayerToggleBorderEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerToggleBypass> PLAYER_TOGGLE_BYPASS_EVENT = new PluginEventType<PlayerToggleBypass>(PlayerToggleBypassEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleBypass args) {\n            return new PlayerToggleBypassEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerToggleFly> PLAYER_TOGGLE_FLY_EVENT = new PluginEventType<PlayerToggleFly>(PlayerToggleFlyEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleFly args) {\n            return new PlayerToggleFlyEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerTogglePanel> PLAYER_TOGGLE_PANEL_EVENT = new PluginEventType<PlayerTogglePanel>(PlayerTogglePanelEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerTogglePanel args) {\n            return new PlayerTogglePanelEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerToggleSpy> PLAYER_TOGGLE_SPY_EVENT = new PluginEventType<PlayerToggleSpy>(PlayerToggleSpyEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleSpy args) {\n            return new PlayerToggleSpyEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PlayerToggleTeamChat> PLAYER_TOGGLE_TEAM_CHAT_EVENT = new PluginEventType<PlayerToggleTeamChat>(PlayerToggleTeamChatEvent.class) {\n        @Override\n        public Event createBukkitEvent(PlayerToggleTeamChat args) {\n            return new PlayerToggleTeamChatEvent(args.superiorPlayer);\n        }\n    };\n    public static final PluginEventType<PluginInitialized> PLUGIN_INITIALIZED_EVENT = new PluginEventType<PluginInitialized>(PluginInitializedEvent.class) {\n        @Override\n        public Event createBukkitEvent(PluginInitialized args) {\n            return new PluginInitializedEvent(args.plugin);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<PluginInitialized> pluginEvent) {\n            // Do nothing\n        }\n    };\n    public static final PluginEventType<PluginInitialize> PLUGIN_INITIALIZE_EVENT = new PluginEventType<PluginInitialize>(PluginInitializeEvent.class) {\n        @Override\n        public Event createBukkitEvent(PluginInitialize args) {\n            return new PluginInitializeEvent(args.plugin);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<PluginInitialize> pluginEvent) {\n            pluginEvent.getArgs().islandsContainer = ((PluginInitializeEvent) bukkitEvent).getIslandsContainer();\n            pluginEvent.getArgs().playersContainer = ((PluginInitializeEvent) bukkitEvent).getPlayersContainer();\n        }\n    };\n    public static final PluginEventType<PluginLoadData> PLUGIN_LOAD_DATA_EVENT = new PluginEventType<PluginLoadData>(null) {\n        @Override\n        public Event createBukkitEvent(PluginLoadData args) {\n            return new PluginLoadDataEvent(args.plugin);\n        }\n    };\n    public static final PluginEventType<PostIslandCreate> POST_ISLAND_CREATE_EVENT = new PluginEventType<PostIslandCreate>(PostIslandCreateEvent.class) {\n        @Override\n        public Event createBukkitEvent(PostIslandCreate args) {\n            return new PostIslandCreateEvent(args.superiorPlayer, args.island);\n        }\n    };\n    public static final PluginEventType<PreIslandCreate> PRE_ISLAND_CREATE_EVENT = new PluginEventType<PreIslandCreate>(PreIslandCreateEvent.class) {\n        @Override\n        public Event createBukkitEvent(PreIslandCreate args) {\n            return new PreIslandCreateEvent(args.superiorPlayer, args.islandName);\n        }\n    };\n    public static final PluginEventType<SendMessage> SEND_MESSAGE_EVENT = new PluginEventType<SendMessage>(SendMessageEvent.class) {\n        @Override\n        public Event createBukkitEvent(SendMessage args) {\n            return new SendMessageEvent(args.receiver, args.messageType, args.messageComponent, args.args);\n        }\n\n        @Override\n        public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<SendMessage> pluginEvent) {\n            super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent);\n            pluginEvent.getArgs().messageComponent = ((SendMessageEvent) bukkitEvent).getMessageComponent();\n        }\n    };\n\n    private final String bukkitEventName;\n\n    private PluginEventType(@Nullable Class<? extends Event> bukkitEventClass) {\n        this.bukkitEventName = bukkitEventClass == null ? null : bukkitEventClass.getSimpleName().toLowerCase(Locale.ENGLISH);\n        ALL_TYPES.add(this);\n    }\n\n    @Override\n    public PluginEvent<Args> createEvent(Args args) {\n        return new PluginEvent<>(this, args);\n    }\n\n    @Nullable\n    public String getBukkitEventName() {\n        return bukkitEventName;\n    }\n\n    @Nullable\n    public abstract Event createBukkitEvent(Args args);\n\n    public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent<Args> pluginEvent) {\n        if (bukkitEvent instanceof Cancellable && ((Cancellable) bukkitEvent).isCancelled())\n            pluginEvent.setCancelled();\n    }\n\n    public static Collection<PluginEventType<?>> values() {\n        return Collections.unmodifiableList(ALL_TYPES);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.plugin;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.commands.CommandsMap;\nimport com.bgsoftware.superiorskyblock.commands.player.CmdAdmin;\nimport com.bgsoftware.superiorskyblock.commands.player.CmdHelp;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.events.EventCallback;\nimport com.bgsoftware.superiorskyblock.core.events.EventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default;\nimport com.bgsoftware.superiorskyblock.island.SIsland;\nimport com.bgsoftware.superiorskyblock.island.SpawnIsland;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.player.SSuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl;\nimport com.bgsoftware.superiorskyblock.world.Dimensions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\n\nimport java.util.EnumMap;\nimport java.util.List;\n\npublic class PluginEventsDispatcher extends EventsDispatcher<\n        Void,\n        PluginEventType<?>,\n        PluginEventPriority,\n        PluginEvent<?>> {\n\n    public PluginEventsDispatcher(SuperiorSkyblockPlugin plugin) {\n        super(plugin, PluginEventPriority.class, PluginEventType.values());\n    }\n\n    public void registerDefaultListeners() {\n        SIsland.registerListeners(this);\n        CommandsMap.registerListeners(this);\n        SpawnIsland.registerListeners(this);\n        RegionManagerServiceImpl.registerListeners(this);\n        CmdHelp.registerListeners(this);\n        CmdAdmin.registerListeners(this);\n        Message.registerListeners(this);\n        SSuperiorPlayer.registerListeners(this);\n        WorldsProvider_Default.registerListeners(this);\n        IslandPrivileges.registerListeners(this);\n        Dimensions.registerListeners(this);\n    }\n\n    public void registerCallback(PluginEventType<?> type, Runnable callback) {\n        registerCallback(type, unused -> callback.run());\n    }\n\n    public <Args extends PluginEventArgs> void registerCallback(PluginEventType<Args> type, EventCallback<PluginEvent<Args>> callback) {\n        registerCallback(null, type, PluginEventPriority.NORMAL, true, callback);\n    }\n\n    public <Args extends PluginEventArgs> PluginEvent<Args> fireEvent(PluginEventType<Args> type, Args args) {\n        PluginEvent<Args> event = type.createEvent(args);\n\n        EnumMap<PluginEventPriority, List<RegisteredListener>> gameEventCallbacks = callbacks.get(type);\n        if (gameEventCallbacks != null) {\n            gameEventCallbacks.forEach((priority, priorityCallbacks) -> {\n                for (RegisteredListener listener : priorityCallbacks) {\n                    if (listener.ignoreCancelled && event.isCancelled()) {\n                        continue;\n                    }\n\n                    try {\n                        listener.callback.execute(event);\n                    } catch (Throwable error) {\n                        Log.error(error, \"Could not pass listener: \" + listener.listener);\n                    }\n                }\n            });\n        }\n\n        String bukkitEventName = type.getBukkitEventName();\n        boolean fireEventDebug = !Text.isBlank(bukkitEventName);\n        if (!fireEventDebug || !plugin.getSettings().getDisabledEvents().contains(bukkitEventName)) {\n            if (fireEventDebug)\n                Log.debug(Debug.FIRE_EVENT, bukkitEventName);\n\n            Event bukkitEvent = type.createBukkitEvent(event.getArgs());\n            if (bukkitEvent != null) {\n                Bukkit.getPluginManager().callEvent(bukkitEvent);\n\n                if (fireEventDebug && bukkitEvent instanceof Cancellable) {\n                    Log.debugResult(Debug.FIRE_EVENT, \"Cancelled:\", ((Cancellable) bukkitEvent).isCancelled());\n                }\n\n                type.applyBukkitToPluginEvent(bukkitEvent, event);\n            }\n        }\n\n\n        return event;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.events.plugin;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.*;\nimport static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.*;\n\npublic class PluginEventsFactory {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static void callSettingsUpdateEvent() {\n        fireEvent(SETTINGS_UPDATE_EVENT, Empty.INSTANCE);\n    }\n\n    public static void callCommandsUpdateEvent() {\n        fireEvent(COMMANDS_UPDATE_EVENT, Empty.INSTANCE);\n    }\n\n    public static void callSpawnUpdateEvent() {\n        fireEvent(SPAWN_UPDATE_EVENT, Empty.INSTANCE);\n    }\n\n    public static void callWorldsProviderUpdateEvent() {\n        fireEvent(WORLD_PROVIDER_UPDATE_EVENT, Empty.INSTANCE);\n    }\n\n    public static boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) {\n        AttemptPlayerSendMessage attemptPlayerSendMessage = new AttemptPlayerSendMessage();\n        attemptPlayerSendMessage.receiver = receiver;\n        attemptPlayerSendMessage.messageType = messageType;\n        attemptPlayerSendMessage.args = args;\n        return !fireEvent(ATTEMPT_PLAYER_SEND_MESSAGE_EVENT, attemptPlayerSendMessage).isCancelled();\n    }\n\n    public static boolean callBlockStackEvent(Block block, Player player, int originalCount, int newCount) {\n        BlockStack blockStack = new BlockStack();\n        blockStack.block = block;\n        blockStack.player = player;\n        blockStack.originalCount = originalCount;\n        blockStack.newCount = newCount;\n        return !fireEvent(BLOCK_STACK_EVENT, blockStack).isCancelled();\n    }\n\n    public static boolean callBlockUnstackEvent(Block block, Player player, int originalCount, int newCount) {\n        BlockUnstack blockUnstack = new BlockUnstack();\n        blockUnstack.block = block;\n        blockUnstack.player = player;\n        blockUnstack.originalCount = originalCount;\n        blockUnstack.newCount = newCount;\n        return !fireEvent(BLOCK_UNSTACK_EVENT, blockUnstack).isCancelled();\n    }\n\n    public static boolean callIslandBanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        IslandBan islandBan = new IslandBan();\n        islandBan.island = island;\n        islandBan.superiorPlayer = superiorPlayer;\n        islandBan.targetPlayer = targetPlayer;\n        return !fireEvent(ISLAND_BAN_EVENT, islandBan).isCancelled();\n    }\n\n    public static PluginEvent<IslandBankDeposit> callIslandBankDepositEvent(Island island, CommandSender commandSender, BigDecimal amount) {\n        return callIslandBankDepositEvent(island, commandSenderToSuperiorPlayer(commandSender), amount);\n    }\n\n    public static PluginEvent<IslandBankDeposit> callIslandBankDepositEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        IslandBankDeposit islandBankDeposit = new IslandBankDeposit();\n        islandBankDeposit.island = island;\n        islandBankDeposit.superiorPlayer = superiorPlayer;\n        islandBankDeposit.amount = amount;\n        return fireEvent(ISLAND_BANK_DEPOSIT_EVENT, islandBankDeposit);\n    }\n\n    public static PluginEvent<IslandBankWithdraw> callIslandBankWithdrawEvent(Island island, CommandSender commandSender, BigDecimal amount) {\n        return callIslandBankWithdrawEvent(island, commandSenderToSuperiorPlayer(commandSender), amount);\n    }\n\n    public static PluginEvent<IslandBankWithdraw> callIslandBankWithdrawEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        IslandBankWithdraw islandBankWithdraw = new IslandBankWithdraw();\n        islandBankWithdraw.island = island;\n        islandBankWithdraw.superiorPlayer = superiorPlayer;\n        islandBankWithdraw.amount = amount;\n        return fireEvent(ISLAND_BANK_WITHDRAW_EVENT, islandBankWithdraw);\n    }\n\n    public static PluginEvent<IslandBiomeChange> callIslandBiomeChangeEvent(Island island, SuperiorPlayer superiorPlayer, Biome biome) {\n        IslandBiomeChange islandBiomeChange = new IslandBiomeChange();\n        islandBiomeChange.island = island;\n        islandBiomeChange.superiorPlayer = superiorPlayer;\n        islandBiomeChange.biome = biome;\n        return fireEvent(ISLAND_BIOME_CHANGE_EVENT, islandBiomeChange);\n    }\n\n    public static PluginEvent<IslandChangeBankLimit> callIslandChangeBankLimitEvent(Island island, CommandSender commandSender, BigDecimal bankLimit) {\n        return callIslandChangeBankLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), bankLimit);\n    }\n\n    public static PluginEvent<IslandChangeBankLimit> callIslandChangeBankLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal bankLimit) {\n        IslandChangeBankLimit islandChangeBankLimit = new IslandChangeBankLimit();\n        islandChangeBankLimit.island = island;\n        islandChangeBankLimit.superiorPlayer = superiorPlayer;\n        islandChangeBankLimit.bankLimit = bankLimit;\n        return fireEvent(ISLAND_CHANGE_BANK_LIMIT_EVENT, islandChangeBankLimit);\n    }\n\n    public static PluginEvent<IslandChangeBlockLimit> callIslandChangeBlockLimitEvent(Island island, CommandSender commandSender, Key block, int blockLimit) {\n        return callIslandChangeBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block, blockLimit);\n    }\n\n    public static PluginEvent<IslandChangeBlockLimit> callIslandChangeBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, int blockLimit) {\n        IslandChangeBlockLimit islandChangeBlockLimit = new IslandChangeBlockLimit();\n        islandChangeBlockLimit.island = island;\n        islandChangeBlockLimit.superiorPlayer = superiorPlayer;\n        islandChangeBlockLimit.block = block;\n        islandChangeBlockLimit.blockLimit = blockLimit;\n        return fireEvent(ISLAND_CHANGE_BLOCK_LIMIT_EVENT, islandChangeBlockLimit);\n    }\n\n    public static PluginEvent<IslandChangeBorderSize> callIslandChangeBorderSizeEvent(Island island, CommandSender commandSender, int borderSize) {\n        return callIslandChangeBorderSizeEvent(island, commandSenderToSuperiorPlayer(commandSender), borderSize);\n    }\n\n    public static PluginEvent<IslandChangeBorderSize> callIslandChangeBorderSizeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int borderSize) {\n        IslandChangeBorderSize islandChangeBorderSize = new IslandChangeBorderSize();\n        islandChangeBorderSize.island = island;\n        islandChangeBorderSize.superiorPlayer = superiorPlayer;\n        islandChangeBorderSize.borderSize = borderSize;\n        return fireEvent(ISLAND_CHANGE_BORDER_SIZE_EVENT, islandChangeBorderSize);\n    }\n\n    public static PluginEvent<IslandChangeCoopLimit> callIslandChangeCoopLimitEvent(Island island, CommandSender commandSender, int coopLimit) {\n        return callIslandChangeCoopLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), coopLimit);\n    }\n\n    public static PluginEvent<IslandChangeCoopLimit> callIslandChangeCoopLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int coopLimit) {\n        IslandChangeCoopLimit islandChangeCoopLimit = new IslandChangeCoopLimit();\n        islandChangeCoopLimit.island = island;\n        islandChangeCoopLimit.superiorPlayer = superiorPlayer;\n        islandChangeCoopLimit.coopLimit = coopLimit;\n        return fireEvent(ISLAND_CHANGE_COOP_LIMIT_EVENT, islandChangeCoopLimit);\n    }\n\n    public static PluginEvent<IslandChangeCropGrowth> callIslandChangeCropGrowthEvent(Island island, CommandSender commandSender, double cropGrowth) {\n        return callIslandChangeCropGrowthEvent(island, commandSenderToSuperiorPlayer(commandSender), cropGrowth);\n    }\n\n    public static PluginEvent<IslandChangeCropGrowth> callIslandChangeCropGrowthEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double cropGrowth) {\n        IslandChangeCropGrowth islandChangeCropGrowth = new IslandChangeCropGrowth();\n        islandChangeCropGrowth.island = island;\n        islandChangeCropGrowth.superiorPlayer = superiorPlayer;\n        islandChangeCropGrowth.cropGrowth = cropGrowth;\n        return fireEvent(ISLAND_CHANGE_CROP_GROWTH_EVENT, islandChangeCropGrowth);\n    }\n\n    public static PluginEvent<IslandChangeDescription> callIslandChangeDescriptionEvent(Island island, SuperiorPlayer superiorPlayer, String description) {\n        IslandChangeDescription islandChangeDescription = new IslandChangeDescription();\n        islandChangeDescription.island = island;\n        islandChangeDescription.superiorPlayer = superiorPlayer;\n        islandChangeDescription.description = description;\n        return fireEvent(ISLAND_CHANGE_DESCRIPTION_EVENT, islandChangeDescription);\n    }\n\n    public static PluginEvent<IslandChangeDiscord> callIslandChangeDiscordEvent(Island island, SuperiorPlayer superiorPlayer, String discord) {\n        IslandChangeDiscord islandChangeDiscord = new IslandChangeDiscord();\n        islandChangeDiscord.island = island;\n        islandChangeDiscord.superiorPlayer = superiorPlayer;\n        islandChangeDiscord.discord = discord;\n        return fireEvent(ISLAND_CHANGE_DISCORD_EVENT, islandChangeDiscord);\n    }\n\n    public static PluginEvent<IslandChangeEffectLevel> callIslandChangeEffectLevelEvent(Island island, CommandSender commandSender,\n                                                                                        PotionEffectType effectType, int effectLevel) {\n        return callIslandChangeEffectLevelEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType, effectLevel);\n    }\n\n    public static PluginEvent<IslandChangeEffectLevel> callIslandChangeEffectLevelEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                        PotionEffectType effectType, int effectLevel) {\n        IslandChangeEffectLevel islandChangeEffectLevel = new IslandChangeEffectLevel();\n        islandChangeEffectLevel.island = island;\n        islandChangeEffectLevel.superiorPlayer = superiorPlayer;\n        islandChangeEffectLevel.effectType = effectType;\n        islandChangeEffectLevel.effectLevel = effectLevel;\n        return fireEvent(ISLAND_CHANGE_EFFECT_LEVEL_EVENT, islandChangeEffectLevel);\n    }\n\n    public static PluginEvent<IslandChangeEntityLimit> callIslandChangeEntityLimitEvent(Island island, CommandSender commandSender,\n                                                                                        Key entity, int entityLimit) {\n        return callIslandChangeEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity, entityLimit);\n    }\n\n    public static PluginEvent<IslandChangeEntityLimit> callIslandChangeEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                        Key entity, int entityLimit) {\n        IslandChangeEntityLimit islandChangeEntityLimit = new IslandChangeEntityLimit();\n        islandChangeEntityLimit.island = island;\n        islandChangeEntityLimit.superiorPlayer = superiorPlayer;\n        islandChangeEntityLimit.entity = entity;\n        islandChangeEntityLimit.entityLimit = entityLimit;\n        return fireEvent(ISLAND_CHANGE_ENTITY_LIMIT_EVENT, islandChangeEntityLimit);\n    }\n\n    public static PluginEvent<IslandChangeGeneratorRate> callIslandChangeGeneratorRateEvent(Island island, CommandSender commandSender,\n                                                                                            Key block, Dimension dimension, int generatorRate) {\n        return callIslandChangeGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension, generatorRate);\n    }\n\n    public static PluginEvent<IslandChangeGeneratorRate> callIslandChangeGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                            Key block, Dimension dimension, int generatorRate) {\n        IslandChangeGeneratorRate islandChangeGeneratorRate = new IslandChangeGeneratorRate();\n        islandChangeGeneratorRate.island = island;\n        islandChangeGeneratorRate.superiorPlayer = superiorPlayer;\n        islandChangeGeneratorRate.block = block;\n        islandChangeGeneratorRate.dimension = dimension;\n        islandChangeGeneratorRate.generatorRate = generatorRate;\n        return fireEvent(ISLAND_CHANGE_GENERATOR_RATE_EVENT, islandChangeGeneratorRate);\n    }\n\n    public static PluginEvent<IslandChangeLevelBonus> callIslandChangeLevelBonusEvent(Island island, CommandSender commandSender,\n                                                                                      IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) {\n        return callIslandChangeLevelBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, levelBonus);\n    }\n\n    public static PluginEvent<IslandChangeLevelBonus> callIslandChangeLevelBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                      IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) {\n        IslandChangeLevelBonus islandChangeLevelBonus = new IslandChangeLevelBonus();\n        islandChangeLevelBonus.island = island;\n        islandChangeLevelBonus.superiorPlayer = superiorPlayer;\n        islandChangeLevelBonus.reason = reason;\n        islandChangeLevelBonus.levelBonus = levelBonus;\n        return fireEvent(ISLAND_CHANGE_LEVEL_BONUS_EVENT, islandChangeLevelBonus);\n    }\n\n    public static PluginEvent<IslandChangeMembersLimit> callIslandChangeMembersLimitEvent(Island island, CommandSender commandSender, int membersLimit) {\n        return callIslandChangeMembersLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), membersLimit);\n    }\n\n    public static PluginEvent<IslandChangeMembersLimit> callIslandChangeMembersLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int membersLimit) {\n        IslandChangeMembersLimit islandChangeMembersLimit = new IslandChangeMembersLimit();\n        islandChangeMembersLimit.island = island;\n        islandChangeMembersLimit.superiorPlayer = superiorPlayer;\n        islandChangeMembersLimit.membersLimit = membersLimit;\n        return fireEvent(ISLAND_CHANGE_MEMBERS_LIMIT_EVENT, islandChangeMembersLimit);\n    }\n\n    public static PluginEvent<IslandChangeMobDrops> callIslandChangeMobDropsEvent(Island island, CommandSender commandSender, double mobDrops) {\n        return callIslandChangeMobDropsEvent(island, commandSenderToSuperiorPlayer(commandSender), mobDrops);\n    }\n\n    public static PluginEvent<IslandChangeMobDrops> callIslandChangeMobDropsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double mobDrops) {\n        IslandChangeMobDrops islandChangeMobDrops = new IslandChangeMobDrops();\n        islandChangeMobDrops.island = island;\n        islandChangeMobDrops.superiorPlayer = superiorPlayer;\n        islandChangeMobDrops.mobDrops = mobDrops;\n        return fireEvent(ISLAND_CHANGE_MOB_DROPS_EVENT, islandChangeMobDrops);\n    }\n\n    public static PluginEvent<IslandChangePaypal> callIslandChangePaypalEvent(Island island, SuperiorPlayer superiorPlayer, String paypal) {\n        IslandChangePaypal islandChangePaypal = new IslandChangePaypal();\n        islandChangePaypal.island = island;\n        islandChangePaypal.superiorPlayer = superiorPlayer;\n        islandChangePaypal.paypal = paypal;\n        return fireEvent(ISLAND_CHANGE_PAYPAL_EVENT, islandChangePaypal);\n    }\n\n    public static boolean callIslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                               SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) {\n        IslandChangePlayerPrivilege islandChangePlayerPrivilege = new IslandChangePlayerPrivilege();\n        islandChangePlayerPrivilege.island = island;\n        islandChangePlayerPrivilege.superiorPlayer = superiorPlayer;\n        islandChangePlayerPrivilege.privilegedPlayer = privilegedPlayer;\n        islandChangePlayerPrivilege.privilegeEnabled = privilegeEnabled;\n        return !fireEvent(ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT, islandChangePlayerPrivilege).isCancelled();\n    }\n\n    public static PluginEvent<IslandChangeRoleLimit> callIslandChangeRoleLimitEvent(Island island, CommandSender commandSender,\n                                                                                    PlayerRole playerRole, int roleLimit) {\n        return callIslandChangeRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole, roleLimit);\n    }\n\n    public static PluginEvent<IslandChangeRoleLimit> callIslandChangeRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                    PlayerRole playerRole, int roleLimit) {\n        IslandChangeRoleLimit islandChangeRoleLimit = new IslandChangeRoleLimit();\n        islandChangeRoleLimit.island = island;\n        islandChangeRoleLimit.superiorPlayer = superiorPlayer;\n        islandChangeRoleLimit.playerRole = playerRole;\n        islandChangeRoleLimit.roleLimit = roleLimit;\n        return fireEvent(ISLAND_CHANGE_ROLE_LIMIT_EVENT, islandChangeRoleLimit);\n    }\n\n    public static PluginEvent<IslandChangeSpawnerRates> callIslandChangeSpawnerRatesEvent(Island island, CommandSender commandSender, double spawnerRates) {\n        return callIslandChangeSpawnerRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), spawnerRates);\n    }\n\n    public static PluginEvent<IslandChangeSpawnerRates> callIslandChangeSpawnerRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double spawnerRates) {\n        IslandChangeSpawnerRates islandChangeSpawnerRates = new IslandChangeSpawnerRates();\n        islandChangeSpawnerRates.island = island;\n        islandChangeSpawnerRates.superiorPlayer = superiorPlayer;\n        islandChangeSpawnerRates.spawnerRates = spawnerRates;\n        return fireEvent(ISLAND_CHANGE_SPAWNER_RATES_EVENT, islandChangeSpawnerRates);\n    }\n\n    public static PluginEvent<IslandChangeWarpCategoryIcon> callIslandChangeWarpCategoryIconEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                                  WarpCategory warpCategory, @Nullable ItemStack icon) {\n        IslandChangeWarpCategoryIcon islandChangeWarpCategoryIcon = new IslandChangeWarpCategoryIcon();\n        islandChangeWarpCategoryIcon.island = island;\n        islandChangeWarpCategoryIcon.superiorPlayer = superiorPlayer;\n        islandChangeWarpCategoryIcon.warpCategory = warpCategory;\n        islandChangeWarpCategoryIcon.icon = icon;\n        return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT, islandChangeWarpCategoryIcon);\n    }\n\n    public static PluginEvent<IslandChangeWarpCategorySlot> callIslandChangeWarpCategorySlotEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                                  WarpCategory warpCategory, int slot, int maxSlot) {\n        IslandChangeWarpCategorySlot islandChangeWarpCategorySlot = new IslandChangeWarpCategorySlot();\n        islandChangeWarpCategorySlot.island = island;\n        islandChangeWarpCategorySlot.superiorPlayer = superiorPlayer;\n        islandChangeWarpCategorySlot.warpCategory = warpCategory;\n        islandChangeWarpCategorySlot.slot = slot;\n        islandChangeWarpCategorySlot.maxSlot = maxSlot;\n        return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT, islandChangeWarpCategorySlot);\n    }\n\n    public static PluginEvent<IslandChangeWarpIcon> callIslandChangeWarpIconEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                  IslandWarp islandWarp, @Nullable ItemStack icon) {\n        IslandChangeWarpIcon islandChangeWarpIcon = new IslandChangeWarpIcon();\n        islandChangeWarpIcon.island = island;\n        islandChangeWarpIcon.superiorPlayer = superiorPlayer;\n        islandChangeWarpIcon.islandWarp = islandWarp;\n        islandChangeWarpIcon.icon = icon;\n        return fireEvent(ISLAND_CHANGE_WARP_ICON_EVENT, islandChangeWarpIcon);\n    }\n\n    public static PluginEvent<IslandChangeWarpLocation> callIslandChangeWarpLocationEvent(Island island, Player player,\n                                                                                          IslandWarp islandWarp, Location location) {\n        return callIslandChangeWarpLocationEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, location);\n    }\n\n    public static PluginEvent<IslandChangeWarpLocation> callIslandChangeWarpLocationEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                          IslandWarp islandWarp, Location location) {\n        IslandChangeWarpLocation islandChangeWarpLocation = new IslandChangeWarpLocation();\n        islandChangeWarpLocation.island = island;\n        islandChangeWarpLocation.superiorPlayer = superiorPlayer;\n        islandChangeWarpLocation.islandWarp = islandWarp;\n        islandChangeWarpLocation.location = location;\n        return fireEvent(ISLAND_CHANGE_WARP_LOCATION_EVENT, islandChangeWarpLocation);\n    }\n\n    public static PluginEvent<IslandChangeWarpsLimit> callIslandChangeWarpsLimitEvent(Island island, CommandSender commandSender, int warpsLimit) {\n        return callIslandChangeWarpsLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), warpsLimit);\n    }\n\n    public static PluginEvent<IslandChangeWarpsLimit> callIslandChangeWarpsLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int warpsLimit) {\n        IslandChangeWarpsLimit islandChangeWarpsLimit = new IslandChangeWarpsLimit();\n        islandChangeWarpsLimit.island = island;\n        islandChangeWarpsLimit.superiorPlayer = superiorPlayer;\n        islandChangeWarpsLimit.warpsLimit = warpsLimit;\n        return fireEvent(ISLAND_CHANGE_WARPS_LIMIT_EVENT, islandChangeWarpsLimit);\n    }\n\n    public static PluginEvent<IslandChangeWorthBonus> callIslandChangeWorthBonusEvent(Island island, CommandSender commandSender,\n                                                                                      IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) {\n        return callIslandChangeWorthBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, worthBonus);\n    }\n\n    public static PluginEvent<IslandChangeWorthBonus> callIslandChangeWorthBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                                      IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) {\n        IslandChangeWorthBonus islandChangeWorthBonus = new IslandChangeWorthBonus();\n        islandChangeWorthBonus.island = island;\n        islandChangeWorthBonus.superiorPlayer = superiorPlayer;\n        islandChangeWorthBonus.reason = reason;\n        islandChangeWorthBonus.worthBonus = worthBonus;\n        return fireEvent(ISLAND_CHANGE_WORTH_BONUS_EVENT, islandChangeWorthBonus);\n    }\n\n    public static boolean callIslandChangeRolePrivilegeEvent(Island island, CommandSender commandSender, PlayerRole playerRole) {\n        return callIslandChangeRolePrivilegeEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole);\n    }\n\n    public static boolean callIslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        IslandChangeRolePrivilege islandChangeRolePrivilege = new IslandChangeRolePrivilege();\n        islandChangeRolePrivilege.island = island;\n        islandChangeRolePrivilege.superiorPlayer = superiorPlayer;\n        islandChangeRolePrivilege.playerRole = playerRole;\n        return !fireEvent(ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT, islandChangeRolePrivilege).isCancelled();\n    }\n\n    public static PluginEvent<IslandChat> callIslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) {\n        IslandChat islandChat = new IslandChat();\n        islandChat.island = island;\n        islandChat.superiorPlayer = superiorPlayer;\n        islandChat.message = message;\n        return fireEvent(ISLAND_CHAT_EVENT, islandChat);\n    }\n\n    public static void callIslandChunkResetEvent(Island island, ChunkPosition chunkPosition) {\n        IslandChunkReset islandChunkReset = new IslandChunkReset();\n        islandChunkReset.island = island;\n        islandChunkReset.chunkPosition = chunkPosition;\n        fireEvent(ISLAND_CHUNK_RESET_EVENT, islandChunkReset);\n    }\n\n    public static boolean callIslandClearFlagsEvent(Island island, CommandSender commandSender) {\n        return callIslandClearFlagsEvent(island, commandSenderToSuperiorPlayer(commandSender));\n    }\n\n    public static boolean callIslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) {\n        IslandClearFlags islandClearFlags = new IslandClearFlags();\n        islandClearFlags.island = island;\n        islandClearFlags.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_CLEAR_FLAGS_EVENT, islandClearFlags).isCancelled();\n    }\n\n    public static boolean callIslandClearGeneratorRatesEvent(Island island, CommandSender commandSender, Dimension dimension) {\n        return callIslandClearGeneratorRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension);\n    }\n\n    public static boolean callIslandClearGeneratorRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandClearGeneratorRates islandClearGeneratorRates = new IslandClearGeneratorRates();\n        islandClearGeneratorRates.island = island;\n        islandClearGeneratorRates.superiorPlayer = superiorPlayer;\n        islandClearGeneratorRates.dimension = dimension;\n        return !fireEvent(ISLAND_CLEAR_GENERATOR_RATES_EVENT, islandClearGeneratorRates).isCancelled();\n    }\n\n    public static boolean callIslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                               SuperiorPlayer privilegedPlayer) {\n        IslandClearPlayerPrivileges islandClearPlayerPrivileges = new IslandClearPlayerPrivileges();\n        islandClearPlayerPrivileges.island = island;\n        islandClearPlayerPrivileges.superiorPlayer = superiorPlayer;\n        islandClearPlayerPrivileges.privilegedPlayer = privilegedPlayer;\n        return !fireEvent(ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT, islandClearPlayerPrivileges).isCancelled();\n    }\n\n    public static boolean callIslandClearRatingsEvent(Island island, CommandSender commandSender) {\n        return callIslandClearRatingsEvent(island, commandSenderToSuperiorPlayer(commandSender));\n    }\n\n    public static boolean callIslandClearRatingsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) {\n        IslandClearRatings islandClearRatings = new IslandClearRatings();\n        islandClearRatings.island = island;\n        islandClearRatings.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_CLEAR_RATINGS_EVENT, islandClearRatings).isCancelled();\n    }\n\n    public static boolean callIslandClearRolesPrivilegesEvent(Island island, CommandSender commandSender) {\n        return callIslandClearRolesPrivilegesEvent(island, commandSenderToSuperiorPlayer(commandSender));\n    }\n\n    public static boolean callIslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) {\n        IslandClearRolesPrivileges islandClearRolesPrivileges = new IslandClearRolesPrivileges();\n        islandClearRolesPrivileges.island = island;\n        islandClearRolesPrivileges.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT, islandClearRolesPrivileges).isCancelled();\n    }\n\n    public static boolean callIslandCloseEvent(Island island, CommandSender commandSender) {\n        return callIslandCloseEvent(island, commandSenderToSuperiorPlayer(commandSender));\n    }\n\n    public static boolean callIslandCloseEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) {\n        IslandClose islandClose = new IslandClose();\n        islandClose.island = island;\n        islandClose.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_CLOSE_EVENT, islandClose).isCancelled();\n    }\n\n    public static boolean callIslandCloseWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        IslandCloseWarp islandCloseWarp = new IslandCloseWarp();\n        islandCloseWarp.island = island;\n        islandCloseWarp.superiorPlayer = superiorPlayer;\n        islandCloseWarp.islandWarp = islandWarp;\n        return !fireEvent(ISLAND_CLOSE_WARP_EVENT, islandCloseWarp).isCancelled();\n    }\n\n    public static boolean callIslandCoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        IslandCoopPlayer islandCoopPlayer = new IslandCoopPlayer();\n        islandCoopPlayer.island = island;\n        islandCoopPlayer.superiorPlayer = superiorPlayer;\n        islandCoopPlayer.targetPlayer = targetPlayer;\n        return !fireEvent(ISLAND_COOP_PLAYER_EVENT, islandCoopPlayer).isCancelled();\n    }\n\n    public static PluginEvent<IslandCreate> callIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer, String schematicName, boolean canTeleport) {\n        IslandCreate islandCreate = new IslandCreate();\n        islandCreate.island = island;\n        islandCreate.superiorPlayer = superiorPlayer;\n        islandCreate.schematicName = schematicName;\n        islandCreate.canTeleport = canTeleport;\n        return fireEvent(ISLAND_CREATE_EVENT, islandCreate);\n    }\n\n    public static boolean callIslandCreateWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, String categoryName) {\n        IslandCreateWarpCategory islandCreateWarpCategory = new IslandCreateWarpCategory();\n        islandCreateWarpCategory.island = island;\n        islandCreateWarpCategory.superiorPlayer = superiorPlayer;\n        islandCreateWarpCategory.categoryName = categoryName;\n        return !fireEvent(ISLAND_CREATE_WARP_CATEGORY_EVENT, islandCreateWarpCategory).isCancelled();\n    }\n\n    public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName,\n                                                    Location location, @Nullable WarpCategory warpCategory) {\n        return callIslandCreateWarpEvent(island, superiorPlayer, warpName, location, plugin.getSettings().isPublicWarps(), warpCategory);\n    }\n\n    public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName,\n                                                    Location location, boolean openToPublic, @Nullable WarpCategory warpCategory) {\n        IslandCreateWarp islandCreateWarp = new IslandCreateWarp();\n        islandCreateWarp.island = island;\n        islandCreateWarp.superiorPlayer = superiorPlayer;\n        islandCreateWarp.warpName = warpName;\n        islandCreateWarp.location = location;\n        islandCreateWarp.openToPublic = openToPublic;\n        islandCreateWarp.warpCategory = warpCategory;\n        return !fireEvent(ISLAND_CREATE_WARP_EVENT, islandCreateWarp).isCancelled();\n    }\n\n    public static boolean callIslandDeleteWarpEvent(Island island, CommandSender commandSender, IslandWarp islandWarp) {\n        return callIslandDeleteWarpEvent(island, commandSenderToSuperiorPlayer(commandSender), islandWarp);\n    }\n\n    public static boolean callIslandDeleteWarpEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        IslandDeleteWarp islandDeleteWarp = new IslandDeleteWarp();\n        islandDeleteWarp.island = island;\n        islandDeleteWarp.superiorPlayer = superiorPlayer;\n        islandDeleteWarp.islandWarp = islandWarp;\n        return !fireEvent(ISLAND_DELETE_WARP_EVENT, islandDeleteWarp).isCancelled();\n    }\n\n    public static boolean callIslandDisableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) {\n        return callIslandDisableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag);\n    }\n\n    public static boolean callIslandDisableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) {\n        IslandDisableFlag islandDisableFlag = new IslandDisableFlag();\n        islandDisableFlag.island = island;\n        islandDisableFlag.superiorPlayer = superiorPlayer;\n        islandDisableFlag.islandFlag = islandFlag;\n        return !fireEvent(ISLAND_DISABLE_FLAG_EVENT, islandDisableFlag).isCancelled();\n    }\n\n    public static boolean callIslandDisbandEvent(Island island, SuperiorPlayer superiorPlayer) {\n        IslandDisband islandDisband = new IslandDisband();\n        islandDisband.island = island;\n        islandDisband.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_DISBAND_EVENT, islandDisband).isCancelled();\n    }\n\n    public static boolean callIslandEnableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) {\n        return callIslandEnableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag);\n    }\n\n    public static boolean callIslandEnableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) {\n        IslandEnableFlag islandEnableFlag = new IslandEnableFlag();\n        islandEnableFlag.island = island;\n        islandEnableFlag.superiorPlayer = superiorPlayer;\n        islandEnableFlag.islandFlag = islandFlag;\n        return !fireEvent(ISLAND_ENABLE_FLAG_EVENT, islandEnableFlag).isCancelled();\n    }\n\n    public static boolean callIslandEnterEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) {\n        IslandEnter islandEnter = new IslandEnter();\n        islandEnter.island = island;\n        islandEnter.superiorPlayer = superiorPlayer;\n        islandEnter.enterCause = enterCause;\n        return !fireEvent(ISLAND_ENTER_EVENT, islandEnter).isCancelled();\n    }\n\n    public static PluginEvent<IslandEnterPortal> callIslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                            PortalType portalType, Dimension destination,\n                                                                            @Nullable Schematic schematic, boolean ignoreInvalidSchematic) {\n        IslandEnterPortal islandEnterPortal = new IslandEnterPortal();\n        islandEnterPortal.island = island;\n        islandEnterPortal.superiorPlayer = superiorPlayer;\n        islandEnterPortal.portalType = portalType;\n        islandEnterPortal.destination = destination;\n        islandEnterPortal.schematic = schematic;\n        islandEnterPortal.ignoreInvalidSchematic = ignoreInvalidSchematic;\n        return fireEvent(ISLAND_ENTER_PORTAL_EVENT, islandEnterPortal);\n    }\n\n    public static boolean callIslandEnterProtectedEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) {\n        IslandEnterProtected islandEnterProtected = new IslandEnterProtected();\n        islandEnterProtected.island = island;\n        islandEnterProtected.superiorPlayer = superiorPlayer;\n        islandEnterProtected.enterCause = enterCause;\n        return !fireEvent(ISLAND_ENTER_PROTECTED_EVENT, islandEnterProtected).isCancelled();\n    }\n\n    public static PluginEvent<IslandGenerateBlock> callIslandGenerateBlockEvent(Island island, Location location, Key block) {\n        IslandGenerateBlock islandGenerateBlock = new IslandGenerateBlock();\n        islandGenerateBlock.island = island;\n        islandGenerateBlock.location = location;\n        islandGenerateBlock.block = block;\n        return fireEvent(ISLAND_GENERATE_BLOCK_EVENT, islandGenerateBlock);\n    }\n\n    public static boolean callIslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandHomeTeleport islandHomeTeleport = new IslandHomeTeleport();\n        islandHomeTeleport.island = island;\n        islandHomeTeleport.superiorPlayer = superiorPlayer;\n        islandHomeTeleport.dimension = dimension;\n        return !fireEvent(ISLAND_HOME_TELEPORT_EVENT, islandHomeTeleport).isCancelled();\n    }\n\n    public static boolean callIslandInviteEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        IslandInvite islandInvite = new IslandInvite();\n        islandInvite.island = island;\n        islandInvite.superiorPlayer = superiorPlayer;\n        islandInvite.targetPlayer = targetPlayer;\n        return !fireEvent(ISLAND_INVITE_EVENT, islandInvite).isCancelled();\n    }\n\n    public static boolean callIslandJoinEvent(Island island, SuperiorPlayer superiorPlayer, IslandJoinEvent.Cause joinCause) {\n        IslandJoin islandJoin = new IslandJoin();\n        islandJoin.island = island;\n        islandJoin.superiorPlayer = superiorPlayer;\n        islandJoin.joinCause = joinCause;\n        return !fireEvent(ISLAND_JOIN_EVENT, islandJoin).isCancelled();\n    }\n\n    public static boolean callIslandKickEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        IslandKick islandKick = new IslandKick();\n        islandKick.island = island;\n        islandKick.superiorPlayer = superiorPlayer;\n        islandKick.targetPlayer = targetPlayer;\n        return !fireEvent(ISLAND_KICK_EVENT, islandKick).isCancelled();\n    }\n\n    public static boolean callIslandLeaveEvent(Island island, SuperiorPlayer superiorPlayer,\n                                               IslandLeaveEvent.LeaveCause leaveCause, Location location) {\n        IslandLeave islandLeave = new IslandLeave();\n        islandLeave.island = island;\n        islandLeave.superiorPlayer = superiorPlayer;\n        islandLeave.leaveCause = leaveCause;\n        islandLeave.location = location;\n        return !fireEvent(ISLAND_LEAVE_EVENT, islandLeave).isCancelled();\n    }\n\n    public static boolean callIslandLeaveProtectedEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                        IslandLeaveEvent.LeaveCause leaveCause, Location location) {\n        IslandLeaveProtected islandLeaveProtected = new IslandLeaveProtected();\n        islandLeaveProtected.island = island;\n        islandLeaveProtected.superiorPlayer = superiorPlayer;\n        islandLeaveProtected.leaveCause = leaveCause;\n        islandLeaveProtected.location = location;\n        return !fireEvent(ISLAND_LEAVE_PROTECTED_EVENT, islandLeaveProtected).isCancelled();\n    }\n\n    public static boolean callIslandLockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) {\n        return callIslandLockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension);\n    }\n\n    public static boolean callIslandLockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandLockWorld islandLockWorld = new IslandLockWorld();\n        islandLockWorld.island = island;\n        islandLockWorld.superiorPlayer = superiorPlayer;\n        islandLockWorld.dimension = dimension;\n        return !fireEvent(ISLAND_LOCK_WORLD_EVENT, islandLockWorld).isCancelled();\n    }\n\n    public static boolean callIslandOpenEvent(Island island, CommandSender commandSender) {\n        return callIslandOpenEvent(island, commandSenderToSuperiorPlayer(commandSender));\n    }\n\n    public static boolean callIslandOpenEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) {\n        IslandOpen islandOpen = new IslandOpen();\n        islandOpen.island = island;\n        islandOpen.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_OPEN_EVENT, islandOpen).isCancelled();\n    }\n\n    public static boolean callIslandOpenWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        IslandOpenWarp islandOpenWarp = new IslandOpenWarp();\n        islandOpenWarp.island = island;\n        islandOpenWarp.superiorPlayer = superiorPlayer;\n        islandOpenWarp.islandWarp = islandWarp;\n        return !fireEvent(ISLAND_OPEN_WARP_EVENT, islandOpenWarp).isCancelled();\n    }\n\n    public static boolean callIslandQuitEvent(Island island, SuperiorPlayer superiorPlayer) {\n        IslandQuit islandQuit = new IslandQuit();\n        islandQuit.island = island;\n        islandQuit.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_QUIT_EVENT, islandQuit).isCancelled();\n    }\n\n    public static boolean callIslandRateEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer, Rating rating) {\n        return callIslandRateEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer, rating);\n    }\n\n    public static boolean callIslandRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Rating rating) {\n        IslandRate islandRate = new IslandRate();\n        islandRate.island = island;\n        islandRate.superiorPlayer = superiorPlayer;\n        islandRate.ratingPlayer = ratingPlayer;\n        islandRate.rating = rating;\n        return !fireEvent(ISLAND_RATE_EVENT, islandRate).isCancelled();\n    }\n\n    public static boolean callIslandRemoveBlockLimitEvent(Island island, CommandSender commandSender, Key block) {\n        return callIslandRemoveBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block);\n    }\n\n    public static boolean callIslandRemoveBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block) {\n        IslandRemoveBlockLimit islandRemoveBlockLimit = new IslandRemoveBlockLimit();\n        islandRemoveBlockLimit.island = island;\n        islandRemoveBlockLimit.superiorPlayer = superiorPlayer;\n        islandRemoveBlockLimit.block = block;\n        return !fireEvent(ISLAND_REMOVE_BLOCK_LIMIT_EVENT, islandRemoveBlockLimit).isCancelled();\n    }\n\n    public static boolean callIslandRemoveEffectEvent(Island island, CommandSender commandSender, PotionEffectType effectType) {\n        return callIslandRemoveEffectEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType);\n    }\n\n    public static boolean callIslandRemoveEffectEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PotionEffectType effectType) {\n        IslandRemoveEffect islandRemoveEffect = new IslandRemoveEffect();\n        islandRemoveEffect.island = island;\n        islandRemoveEffect.superiorPlayer = superiorPlayer;\n        islandRemoveEffect.effectType = effectType;\n        return !fireEvent(ISLAND_REMOVE_EFFECT_EVENT, islandRemoveEffect).isCancelled();\n    }\n\n    public static boolean callIslandRemoveEntityLimitEvent(Island island, CommandSender commandSender, Key entity) {\n        return callIslandRemoveEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity);\n    }\n\n    public static boolean callIslandRemoveEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key entity) {\n        IslandRemoveEntityLimit islandRemoveEntityLimit = new IslandRemoveEntityLimit();\n        islandRemoveEntityLimit.island = island;\n        islandRemoveEntityLimit.superiorPlayer = superiorPlayer;\n        islandRemoveEntityLimit.entity = entity;\n        return !fireEvent(ISLAND_REMOVE_ENTITY_LIMIT_EVENT, islandRemoveEntityLimit).isCancelled();\n    }\n\n    public static boolean callIslandRemoveGeneratorRateEvent(Island island, CommandSender commandSender, Key block, Dimension dimension) {\n        return callIslandRemoveGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension);\n    }\n\n    public static boolean callIslandRemoveGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, Dimension dimension) {\n        IslandRemoveGeneratorRate islandRemoveGeneratorRate = new IslandRemoveGeneratorRate();\n        islandRemoveGeneratorRate.island = island;\n        islandRemoveGeneratorRate.superiorPlayer = superiorPlayer;\n        islandRemoveGeneratorRate.block = block;\n        islandRemoveGeneratorRate.dimension = dimension;\n        return !fireEvent(ISLAND_REMOVE_GENERATOR_RATE_EVENT, islandRemoveGeneratorRate).isCancelled();\n    }\n\n    public static boolean callIslandRemoveRatingEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer) {\n        return callIslandRemoveRatingEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer);\n    }\n\n    public static boolean callIslandRemoveRatingEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer) {\n        IslandRemoveRating islandRemoveRating = new IslandRemoveRating();\n        islandRemoveRating.island = island;\n        islandRemoveRating.superiorPlayer = superiorPlayer;\n        islandRemoveRating.ratingPlayer = ratingPlayer;\n        return !fireEvent(ISLAND_REMOVE_RATING_EVENT, islandRemoveRating).isCancelled();\n    }\n\n    public static boolean callIslandRemoveRoleLimitEvent(Island island, CommandSender commandSender, PlayerRole playerRole) {\n        return callIslandRemoveRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole);\n    }\n\n    public static boolean callIslandRemoveRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        IslandRemoveRoleLimit islandRemoveRoleLimit = new IslandRemoveRoleLimit();\n        islandRemoveRoleLimit.island = island;\n        islandRemoveRoleLimit.superiorPlayer = superiorPlayer;\n        islandRemoveRoleLimit.playerRole = playerRole;\n        return !fireEvent(ISLAND_REMOVE_ROLE_LIMIT_EVENT, islandRemoveRoleLimit).isCancelled();\n    }\n\n    public static boolean callIslandRemoveVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer) {\n        IslandRemoveVisitorHome islandRemoveVisitorHome = new IslandRemoveVisitorHome();\n        islandRemoveVisitorHome.island = island;\n        islandRemoveVisitorHome.superiorPlayer = superiorPlayer;\n        return !fireEvent(ISLAND_REMOVE_VISITOR_HOME_EVENT, islandRemoveVisitorHome).isCancelled();\n    }\n\n    public static PluginEvent<IslandRename> callIslandRenameEvent(Island island, CommandSender commandSender, String islandName) {\n        return callIslandRenameEvent(island, commandSenderToSuperiorPlayer(commandSender), islandName);\n    }\n\n    public static PluginEvent<IslandRename> callIslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) {\n        IslandRename islandRename = new IslandRename();\n        islandRename.island = island;\n        islandRename.superiorPlayer = superiorPlayer;\n        islandRename.islandName = islandName;\n        return fireEvent(ISLAND_RENAME_EVENT, islandRename);\n    }\n\n    public static PluginEvent<IslandRenameWarpCategory> callIslandRenameWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                          WarpCategory warpCategory, String categoryName) {\n        IslandRenameWarpCategory islandRenameWarpCategory = new IslandRenameWarpCategory();\n        islandRenameWarpCategory.island = island;\n        islandRenameWarpCategory.superiorPlayer = superiorPlayer;\n        islandRenameWarpCategory.warpCategory = warpCategory;\n        islandRenameWarpCategory.categoryName = categoryName;\n        return fireEvent(ISLAND_RENAME_WARP_CATEGORY_EVENT, islandRenameWarpCategory);\n    }\n\n    public static PluginEvent<IslandRenameWarp> callIslandRenameWarpEvent(Island island, Player player,\n                                                                          IslandWarp islandWarp, String warpName) {\n        return callIslandRenameWarpEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, warpName);\n    }\n\n    public static PluginEvent<IslandRenameWarp> callIslandRenameWarpEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                          IslandWarp islandWarp, String warpName) {\n        IslandRenameWarp islandRenameWarp = new IslandRenameWarp();\n        islandRenameWarp.island = island;\n        islandRenameWarp.superiorPlayer = superiorPlayer;\n        islandRenameWarp.islandWarp = islandWarp;\n        islandRenameWarp.warpName = warpName;\n        return fireEvent(ISLAND_RENAME_WARP_EVENT, islandRenameWarp);\n    }\n\n    public static void callIslandRestrictMoveEvent(Island island, SuperiorPlayer superiorPlayer, IslandRestrictMoveEvent.RestrictReason restrictReason) {\n        IslandRestrictMove islandRestrictMove = new IslandRestrictMove();\n        islandRestrictMove.island = island;\n        islandRestrictMove.superiorPlayer = superiorPlayer;\n        islandRestrictMove.restrictReason = restrictReason;\n        fireEvent(ISLAND_RESTRICT_MOVE_EVENT, islandRestrictMove);\n    }\n\n    public static void callIslandSchematicPasteEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String schematicName, Location location) {\n        IslandSchematicPaste islandSchematicPaste = new IslandSchematicPaste();\n        islandSchematicPaste.island = island;\n        islandSchematicPaste.superiorPlayer = superiorPlayer;\n        islandSchematicPaste.schematicName = schematicName;\n        islandSchematicPaste.location = location;\n        fireEvent(ISLAND_SCHEMATIC_PASTE_EVENT, islandSchematicPaste);\n    }\n\n    public static PluginEvent<IslandSetHome> callIslandSetHomeEvent(Island island, CommandSender commandSender,\n                                                                    Location islandHome, IslandSetHomeEvent.Reason reason) {\n        return callIslandSetHomeEvent(island, commandSenderToSuperiorPlayer(commandSender), islandHome, reason);\n    }\n\n    public static PluginEvent<IslandSetHome> callIslandSetHomeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                    Location islandHome, IslandSetHomeEvent.Reason reason) {\n        IslandSetHome islandRenameWarp = new IslandSetHome();\n        islandRenameWarp.island = island;\n        islandRenameWarp.superiorPlayer = superiorPlayer;\n        islandRenameWarp.islandHome = islandHome;\n        islandRenameWarp.reason = reason;\n        return fireEvent(ISLAND_SET_HOME_EVENT, islandRenameWarp);\n    }\n\n    public static PluginEvent<IslandSetVisitorHome> callIslandSetVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer,\n                                                                                  Location islandVisitorHome) {\n        IslandSetVisitorHome islandSetVisitorHome = new IslandSetVisitorHome();\n        islandSetVisitorHome.island = island;\n        islandSetVisitorHome.superiorPlayer = superiorPlayer;\n        islandSetVisitorHome.islandVisitorHome = islandVisitorHome;\n        return fireEvent(ISLAND_SET_VISITOR_HOME_EVENT, islandSetVisitorHome);\n    }\n\n    public static boolean callIslandTransferEvent(Island island, SuperiorPlayer previousOwner, SuperiorPlayer superiorPlayer) {\n        IslandTransfer islandTransfer = new IslandTransfer();\n        islandTransfer.island = island;\n        islandTransfer.superiorPlayer = superiorPlayer;\n        islandTransfer.previousOwner = previousOwner;\n        return !fireEvent(ISLAND_TRANSFER_EVENT, islandTransfer).isCancelled();\n    }\n\n    public static boolean callIslandUnbanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer unbannedPlayer) {\n        IslandUnban islandUnban = new IslandUnban();\n        islandUnban.island = island;\n        islandUnban.superiorPlayer = superiorPlayer;\n        islandUnban.unbannedPlayer = unbannedPlayer;\n        return !fireEvent(ISLAND_UNBAN_EVENT, islandUnban).isCancelled();\n    }\n\n    public static boolean callIslandUncoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer,\n                                                      IslandUncoopPlayerEvent.UncoopReason uncoopReason) {\n        IslandUncoopPlayer islandUncoopPlayer = new IslandUncoopPlayer();\n        islandUncoopPlayer.island = island;\n        islandUncoopPlayer.superiorPlayer = superiorPlayer;\n        islandUncoopPlayer.targetPlayer = targetPlayer;\n        islandUncoopPlayer.uncoopReason = uncoopReason;\n        return !fireEvent(ISLAND_UNCOOP_PLAYER_EVENT, islandUncoopPlayer).isCancelled();\n    }\n\n    public static boolean callIslandUnlockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) {\n        return callIslandUnlockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension);\n    }\n\n    public static boolean callIslandUnlockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandUnlockWorld islandUncoopPlayer = new IslandUnlockWorld();\n        islandUncoopPlayer.island = island;\n        islandUncoopPlayer.superiorPlayer = superiorPlayer;\n        islandUncoopPlayer.dimension = dimension;\n        return !fireEvent(ISLAND_UNLOCK_WORLD_EVENT, islandUncoopPlayer).isCancelled();\n    }\n\n    public static PluginEvent<IslandUpgrade> callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                    Upgrade upgrade, UpgradeLevel currentLevel,\n                                                                    UpgradeLevel nextLevel, IslandUpgradeEvent.Cause upgradeCause) {\n        return callIslandUpgradeEvent(island, superiorPlayer, upgrade, nextLevel, currentLevel.getCommands(),\n                upgradeCause, currentLevel.getCost());\n    }\n\n    public static PluginEvent<IslandUpgrade> callIslandUpgradeEvent(Island island, CommandSender commandSender,\n                                                                    Upgrade upgrade, UpgradeLevel nextLevel,\n                                                                    IslandUpgradeEvent.Cause upgradeCause) {\n        return callIslandUpgradeEvent(island, commandSenderToSuperiorPlayer(commandSender), upgrade, nextLevel,\n                Collections.emptyList(), upgradeCause, null);\n    }\n\n    public static PluginEvent<IslandUpgrade> callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer,\n                                                                    Upgrade upgrade, UpgradeLevel nextLevel,\n                                                                    List<String> commands, IslandUpgradeEvent.Cause upgradeCause,\n                                                                    @Nullable UpgradeCost upgradeCost) {\n        IslandUpgrade islandUpgrade = new IslandUpgrade();\n        islandUpgrade.island = island;\n        islandUpgrade.superiorPlayer = superiorPlayer;\n        islandUpgrade.upgrade = upgrade;\n        islandUpgrade.nextLevel = nextLevel;\n        islandUpgrade.commands = commands;\n        islandUpgrade.upgradeCause = upgradeCause;\n        islandUpgrade.upgradeCost = upgradeCost;\n        return fireEvent(ISLAND_UPGRADE_EVENT, islandUpgrade);\n    }\n\n    public static boolean callIslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandVisitorHomeTeleport islandVisitorHomeTeleport = new IslandVisitorHomeTeleport();\n        islandVisitorHomeTeleport.island = island;\n        islandVisitorHomeTeleport.superiorPlayer = superiorPlayer;\n        islandVisitorHomeTeleport.dimension = dimension;\n        return !fireEvent(ISLAND_VISITOR_HOME_TELEPORT_EVENT, islandVisitorHomeTeleport).isCancelled();\n    }\n\n    public static boolean callIslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        IslandWarpTeleport islandWarpTeleport = new IslandWarpTeleport();\n        islandWarpTeleport.island = island;\n        islandWarpTeleport.superiorPlayer = superiorPlayer;\n        islandWarpTeleport.islandWarp = islandWarp;\n        return !fireEvent(ISLAND_WARP_TELEPORT_EVENT, islandWarpTeleport).isCancelled();\n    }\n\n    public static boolean callIslandWorldResetEvent(Island island, CommandSender commandSender, Dimension dimension) {\n        return callIslandWorldResetEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension);\n    }\n\n    public static boolean callIslandWorldResetEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) {\n        IslandWorldReset islandWorldReset = new IslandWorldReset();\n        islandWorldReset.island = island;\n        islandWorldReset.superiorPlayer = superiorPlayer;\n        islandWorldReset.dimension = dimension;\n        return !fireEvent(ISLAND_WORLD_RESET_EVENT, islandWorldReset).isCancelled();\n    }\n\n    public static void callIslandWorthCalculatedEvent(Island island, SuperiorPlayer asker, BigDecimal islandLevel, BigDecimal islandWorth) {\n        IslandWorthCalculated islandWorthCalculated = new IslandWorthCalculated();\n        islandWorthCalculated.island = island;\n        islandWorthCalculated.superiorPlayer = asker;\n        islandWorthCalculated.islandLevel = islandLevel;\n        islandWorthCalculated.islandWorth = islandWorth;\n        fireEvent(ISLAND_WORTH_CALCULATED_EVENT, islandWorthCalculated);\n    }\n\n    public static void callIslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) {\n        IslandWorthUpdate islandWorthUpdate = new IslandWorthUpdate();\n        islandWorthUpdate.island = island;\n        islandWorthUpdate.oldWorth = oldWorth;\n        islandWorthUpdate.oldLevel = oldLevel;\n        islandWorthUpdate.newWorth = newWorth;\n        islandWorthUpdate.newLevel = newLevel;\n        fireEvent(ISLAND_WORTH_UPDATE_EVENT, islandWorthUpdate);\n    }\n\n    public static PluginEvent<MissionComplete> callMissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder,\n                                                                        Mission<?> mission, List<ItemStack> itemRewards,\n                                                                        List<String> commandRewards) {\n        MissionComplete missionComplete = new MissionComplete();\n        missionComplete.superiorPlayer = superiorPlayer;\n        missionComplete.missionsHolder = missionsHolder;\n        missionComplete.mission = mission;\n        missionComplete.itemRewards = itemRewards;\n        missionComplete.commandRewards = commandRewards;\n        return fireEvent(MISSION_COMPLETE_EVENT, missionComplete);\n    }\n\n    public static boolean callMissionResetEvent(CommandSender commandSender, IMissionsHolder missionsHolder, Mission<?> mission) {\n        return callMissionResetEvent(commandSenderToSuperiorPlayer(commandSender), missionsHolder, mission);\n    }\n\n    public static boolean callMissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission<?> mission) {\n        MissionReset missionReset = new MissionReset();\n        missionReset.superiorPlayer = superiorPlayer;\n        missionReset.missionsHolder = missionsHolder;\n        missionReset.mission = mission;\n        return !fireEvent(MISSION_RESET_EVENT, missionReset).isCancelled();\n    }\n\n    public static boolean callPlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) {\n        PlayerChangeBorderColor playerChangeBorderColor = new PlayerChangeBorderColor();\n        playerChangeBorderColor.superiorPlayer = superiorPlayer;\n        playerChangeBorderColor.borderColor = borderColor;\n        return !fireEvent(PLAYER_CHANGE_BORDER_COLOR_EVENT, playerChangeBorderColor).isCancelled();\n    }\n\n    public static boolean callPlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) {\n        PlayerChangeLanguage playerChangeLanguage = new PlayerChangeLanguage();\n        playerChangeLanguage.superiorPlayer = superiorPlayer;\n        playerChangeLanguage.language = language;\n        return !fireEvent(PLAYER_CHANGE_LANGUAGE_EVENT, playerChangeLanguage).isCancelled();\n    }\n\n    public static void callPlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) {\n        PlayerChangeName missionComplete = new PlayerChangeName();\n        missionComplete.superiorPlayer = superiorPlayer;\n        missionComplete.newName = newName;\n        fireEvent(PLAYER_CHANGE_NAME_EVENT, missionComplete);\n    }\n\n    public static boolean callPlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newRole) {\n        PlayerChangeRole playerChangeRole = new PlayerChangeRole();\n        playerChangeRole.superiorPlayer = superiorPlayer;\n        playerChangeRole.newRole = newRole;\n        return !fireEvent(PLAYER_CHANGE_ROLE_EVENT, playerChangeRole).isCancelled();\n    }\n\n    public static PluginEvent<PlayerCloseMenu> callPlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView<?, ?> menuView,\n                                                                        @Nullable MenuView<?, ?> newMenuView) {\n        PlayerCloseMenu playerCloseMenu = new PlayerCloseMenu();\n        playerCloseMenu.superiorPlayer = superiorPlayer;\n        playerCloseMenu.menuView = menuView;\n        playerCloseMenu.newMenuView = newMenuView;\n        return fireEvent(PLAYER_CLOSE_MENU_EVENT, playerCloseMenu);\n    }\n\n    public static boolean callPlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView<?, ?> menuView) {\n        PlayerOpenMenu playerOpenMenu = new PlayerOpenMenu();\n        playerOpenMenu.superiorPlayer = superiorPlayer;\n        playerOpenMenu.menuView = menuView;\n        return !fireEvent(PLAYER_OPEN_MENU_EVENT, playerOpenMenu).isCancelled();\n    }\n\n    public static void callPlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) {\n        PlayerReplace playerReplace = new PlayerReplace();\n        playerReplace.superiorPlayer = oldPlayer;\n        playerReplace.newPlayer = newPlayer;\n        fireEvent(PLAYER_REPLACE_EVENT, playerReplace);\n    }\n\n    public static boolean callPlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleBlocksStacker playerToggleBlocksStacker = new PlayerToggleBlocksStacker();\n        playerToggleBlocksStacker.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_BLOCKS_STACKER_EVENT, playerToggleBlocksStacker).isCancelled();\n    }\n\n    public static boolean callPlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleBorder playerToggleBorder = new PlayerToggleBorder();\n        playerToggleBorder.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_BORDER_EVENT, playerToggleBorder).isCancelled();\n    }\n\n    public static boolean callPlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleBypass playerToggleBypass = new PlayerToggleBypass();\n        playerToggleBypass.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_BYPASS_EVENT, playerToggleBypass).isCancelled();\n    }\n\n    public static boolean callPlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleFly playerToggleFly = new PlayerToggleFly();\n        playerToggleFly.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_FLY_EVENT, playerToggleFly).isCancelled();\n    }\n\n    public static boolean callPlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) {\n        PlayerTogglePanel playerTogglePanel = new PlayerTogglePanel();\n        playerTogglePanel.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_PANEL_EVENT, playerTogglePanel).isCancelled();\n    }\n\n    public static boolean callPlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleSpy playerToggleSpy = new PlayerToggleSpy();\n        playerToggleSpy.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_SPY_EVENT, playerToggleSpy).isCancelled();\n    }\n\n    public static boolean callPlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) {\n        PlayerToggleTeamChat playerToggleTeamChat = new PlayerToggleTeamChat();\n        playerToggleTeamChat.superiorPlayer = superiorPlayer;\n        return !fireEvent(PLAYER_TOGGLE_TEAM_CHAT_EVENT, playerToggleTeamChat).isCancelled();\n    }\n\n    public static void callPluginInitializedEvent() {\n        PluginInitialized pluginInitialized = new PluginInitialized();\n        pluginInitialized.plugin = plugin;\n        fireEvent(PLUGIN_INITIALIZED_EVENT, pluginInitialized);\n    }\n\n    public static PluginEvent<PluginInitialize> callPluginInitializeEvent() {\n        PluginInitialize pluginInitialize = new PluginInitialize();\n        pluginInitialize.plugin = plugin;\n        return fireEvent(PLUGIN_INITIALIZE_EVENT, pluginInitialize);\n    }\n\n    public static boolean callPluginLoadDataEvent() {\n        PluginLoadData pluginLoadData = new PluginLoadData();\n        pluginLoadData.plugin = plugin;\n        return !fireEvent(PLUGIN_LOAD_DATA_EVENT, pluginLoadData).isCancelled();\n    }\n\n    public static void callPostIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer) {\n        PostIslandCreate postIslandCreate = new PostIslandCreate();\n        postIslandCreate.island = island;\n        postIslandCreate.superiorPlayer = superiorPlayer;\n        fireEvent(POST_ISLAND_CREATE_EVENT, postIslandCreate);\n    }\n\n    public static boolean callPreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) {\n        PreIslandCreate preIslandCreate = new PreIslandCreate();\n        preIslandCreate.superiorPlayer = superiorPlayer;\n        preIslandCreate.islandName = islandName;\n        return !fireEvent(PRE_ISLAND_CREATE_EVENT, preIslandCreate).isCancelled();\n    }\n\n    public static PluginEvent<SendMessage> callSendMessageEvent(CommandSender receiver, String messageType,\n                                                                IMessageComponent messageComponent, Object... args) {\n        SendMessage pluginInitialize = new SendMessage();\n        pluginInitialize.receiver = receiver;\n        pluginInitialize.messageType = messageType;\n        pluginInitialize.messageComponent = messageComponent;\n        pluginInitialize.args = args;\n        return fireEvent(SEND_MESSAGE_EVENT, pluginInitialize);\n    }\n\n    private static <Args extends PluginEventArgs> PluginEvent<Args> fireEvent(PluginEventType<Args> type, Args args) {\n        return plugin.getPluginEventsDispatcher().fireEvent(type, args);\n    }\n\n    @Nullable\n    private static SuperiorPlayer commandSenderToSuperiorPlayer(@Nullable CommandSender commandSender) {\n        return commandSender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(commandSender) : null;\n    }\n\n    private PluginEventsFactory() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultBanksFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.factory;\n\nimport com.bgsoftware.superiorskyblock.api.factory.BanksFactory;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\n\npublic class DefaultBanksFactory implements BanksFactory {\n\n    private static final DefaultBanksFactory INSTANCE = new DefaultBanksFactory();\n\n    public static DefaultBanksFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultBanksFactory() {\n    }\n\n    @Override\n    public IslandBank createIslandBank(Island island, IslandBank original) {\n        return original;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultDatabaseBridgeFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.factory;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class DefaultDatabaseBridgeFactory implements DatabaseBridgeFactory {\n\n    private static final DefaultDatabaseBridgeFactory INSTANCE = new DefaultDatabaseBridgeFactory();\n\n    public static DefaultDatabaseBridgeFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultDatabaseBridgeFactory() {\n    }\n\n    @Override\n    public DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original) {\n        return original;\n    }\n\n    @Override\n    public DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original) {\n        return original;\n    }\n\n    @Override\n    public DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original) {\n        return original;\n    }\n\n    @Override\n    public DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original) {\n        return original;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultIslandsFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.factory;\n\nimport com.bgsoftware.superiorskyblock.api.factory.IslandsFactory;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\n\npublic class DefaultIslandsFactory implements IslandsFactory {\n\n    private static final DefaultIslandsFactory INSTANCE = new DefaultIslandsFactory();\n\n    public static DefaultIslandsFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultIslandsFactory() {\n    }\n\n    @Override\n    public Island createIsland(Island original) {\n        return original;\n    }\n\n    @Override\n    public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original) {\n        return original;\n    }\n\n    @Override\n    public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original) {\n        return original;\n    }\n\n    @Override\n    public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original) {\n        return original;\n    }\n\n    @Override\n    public PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original) {\n        return original;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultPlayersFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.factory;\n\nimport com.bgsoftware.superiorskyblock.api.factory.PlayersFactory;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class DefaultPlayersFactory implements PlayersFactory {\n\n    private static final DefaultPlayersFactory INSTANCE = new DefaultPlayersFactory();\n\n    public static DefaultPlayersFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultPlayersFactory() {\n    }\n\n    @Override\n    public SuperiorPlayer createPlayer(SuperiorPlayer original) {\n        return original;\n    }\n\n    @Override\n    public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original) {\n        return original;\n    }\n\n    @Override\n    public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original) {\n        return original;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.factory;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\nimport com.bgsoftware.superiorskyblock.api.factory.BanksFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.IslandsFactory;\nimport com.bgsoftware.superiorskyblock.api.factory.PlayersFactory;\nimport com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.WorldInfoImpl;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.sql.SQLDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.persistence.PersistentDataContainerImpl;\nimport com.bgsoftware.superiorskyblock.island.SIsland;\nimport com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.bank.SBankTransaction;\nimport com.bgsoftware.superiorskyblock.island.bank.SIslandBank;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.bgsoftware.superiorskyblock.player.SSuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.player.algorithm.DefaultPlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl;\nimport com.bgsoftware.superiorskyblock.world.schematic.options.SchematicOptionsBuilderImpl;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.Sound;\n\nimport java.math.BigDecimal;\nimport java.util.UUID;\nimport java.util.function.Supplier;\n\npublic class FactoriesManagerImpl implements FactoriesManager {\n\n    private IslandsFactory islandsFactory = DefaultIslandsFactory.getInstance();\n    private PlayersFactory playersFactory = DefaultPlayersFactory.getInstance();\n    private BanksFactory banksFactory = DefaultBanksFactory.getInstance();\n    private DatabaseBridgeFactory databaseBridgeFactory = DefaultDatabaseBridgeFactory.getInstance();\n\n    @Override\n    public void registerIslandsFactory(@Nullable IslandsFactory islandsFactory) {\n        this.islandsFactory = islandsFactory == null ? DefaultIslandsFactory.getInstance() : islandsFactory;\n    }\n\n    @Override\n    public IslandsFactory getIslandsFactory() {\n        return islandsFactory;\n    }\n\n    @Override\n    public void registerPlayersFactory(@Nullable PlayersFactory playersFactory) {\n        this.playersFactory = playersFactory == null ? DefaultPlayersFactory.getInstance() : playersFactory;\n    }\n\n    @Override\n    public PlayersFactory getPlayersFactory() {\n        return playersFactory;\n    }\n\n    @Override\n    public void registerBanksFactory(@Nullable BanksFactory banksFactory) {\n        this.banksFactory = banksFactory == null ? DefaultBanksFactory.getInstance() : banksFactory;\n    }\n\n    @Override\n    public BanksFactory getBanksFactory() {\n        return banksFactory;\n    }\n\n    @Override\n    public void registerDatabaseBridgeFactory(@Nullable DatabaseBridgeFactory databaseBridgeFactory) {\n        this.databaseBridgeFactory = databaseBridgeFactory == null ? DefaultDatabaseBridgeFactory.getInstance() : databaseBridgeFactory;\n    }\n\n    @Override\n    public DatabaseBridgeFactory getDatabaseBridgeFactory() {\n        return databaseBridgeFactory;\n    }\n\n    @Override\n    public Island createIsland(@Nullable SuperiorPlayer owner, UUID uuid, Location center, String islandName, String schemName) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        Preconditions.checkNotNull(center, \"center parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        Preconditions.checkNotNull(schemName, \"schemName parameter cannot be null.\");\n        return createIslandBuilder()\n                .setOwner(owner)\n                .setUniqueId(uuid)\n                .setCenter(center)\n                .setName(islandName)\n                .setSchematicName(schemName)\n                .build();\n    }\n\n    @Override\n    public Island.Builder createIslandBuilder() {\n        return new IslandBuilderImpl();\n    }\n\n    public Island createIsland(IslandBuilderImpl builder) {\n        return islandsFactory.createIsland(new SIsland(builder));\n    }\n\n    @Override\n    public SuperiorPlayer createPlayer(UUID playerUUID) {\n        Preconditions.checkNotNull(playerUUID, \"playerUUID parameter cannot be null.\");\n        OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerUUID);\n        SuperiorPlayer.Builder builder = createPlayerBuilder()\n                .setUniqueId(playerUUID);\n\n        if (offlinePlayer != null && offlinePlayer.getName() != null)\n            builder.setName(offlinePlayer.getName());\n\n        return builder.build();\n    }\n\n    @Override\n    public SuperiorPlayer.Builder createPlayerBuilder() {\n        return new SuperiorPlayerBuilderImpl();\n    }\n\n    public SuperiorPlayer createPlayer(SuperiorPlayerBuilderImpl builder) {\n        return playersFactory.createPlayer(new SSuperiorPlayer(builder));\n    }\n\n    @Override\n    public BlockOffset createBlockOffset(int offsetX, int offsetY, int offsetZ) {\n        return SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ);\n    }\n\n    @Override\n    @Deprecated\n    public BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ) {\n        return createBlockPosition(blockX, blockY, blockZ);\n    }\n\n    @Override\n    public BlockPosition createBlockPosition(int blockX, int blockY, int blockZ) {\n        return SBlockPosition.of(blockX, blockY, blockZ);\n    }\n\n    @Override\n    public BlockPosition createBlockPosition(Location location) {\n        Preconditions.checkNotNull(location, \"location cannot be null.\");\n        return SBlockPosition.of(location);\n    }\n\n    @Override\n    public WorldPosition createWorldPosition(double x, double y, double z) {\n        return SWorldPosition.of(x, y, z);\n    }\n\n    @Override\n    public WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch) {\n        return SWorldPosition.of(x, y, z, yaw, pitch);\n    }\n\n    @Override\n    public WorldPosition createWorldPosition(Location location) {\n        Preconditions.checkNotNull(location, \"location cannot be null.\");\n        return SWorldPosition.of(location);\n    }\n\n    @Override\n    public BankTransaction createTransaction(@Nullable UUID player, BankAction action, int position, long time,\n                                             String failureReason, BigDecimal amount) {\n        Preconditions.checkNotNull(action, \"action parameter cannot be null\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null\");\n        return new SBankTransaction(player, action, position, time, failureReason, amount);\n    }\n\n    @Override\n    public WorldInfo createWorldInfo(String worldName, Dimension dimension) {\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n        return new WorldInfoImpl(worldName, dimension);\n    }\n\n    @Override\n    public GameSound createGameSound(Sound sound, float volume, float pitch) {\n        Preconditions.checkNotNull(sound, \"sound parameter cannot be null\");\n        return new GameSoundImpl(sound, volume, pitch);\n    }\n\n    @Override\n    public SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName) {\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null\");\n        return new SchematicOptionsBuilderImpl(schematicName);\n    }\n\n    public IslandBank createIslandBank(Island island, Supplier<Boolean> isGiveInterestFailed) {\n        return banksFactory.createIslandBank(island, new SIslandBank(island, isGiveInterestFailed));\n    }\n\n    public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) {\n        try {\n            // noinspection deprecation\n            return islandsFactory.createIslandCalculationAlgorithm(island);\n        } catch (UnsupportedOperationException error) {\n            return islandsFactory.createIslandCalculationAlgorithm(island, DefaultIslandCalculationAlgorithm.getInstance());\n        }\n    }\n\n    public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) {\n        try {\n            // noinspection deprecation\n            return islandsFactory.createIslandBlocksTrackerAlgorithm(island);\n        } catch (UnsupportedOperationException error) {\n            return islandsFactory.createIslandBlocksTrackerAlgorithm(island, new DefaultIslandBlocksTrackerAlgorithm(island));\n        }\n    }\n\n    public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) {\n        try {\n            // noinspection deprecation\n            return islandsFactory.createIslandEntitiesTrackerAlgorithm(island);\n        } catch (UnsupportedOperationException error) {\n            return islandsFactory.createIslandEntitiesTrackerAlgorithm(island, new DefaultIslandEntitiesTrackerAlgorithm(island));\n        }\n    }\n\n    public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) {\n        try {\n            // noinspection deprecation\n            return playersFactory.createPlayerTeleportAlgorithm(superiorPlayer);\n        } catch (UnsupportedOperationException error) {\n            return playersFactory.createPlayerTeleportAlgorithm(superiorPlayer, DefaultPlayerTeleportAlgorithm.getInstance());\n        }\n    }\n\n    public boolean hasCustomDatabaseBridge() {\n        return databaseBridgeFactory != DefaultDatabaseBridgeFactory.getInstance();\n    }\n\n    public DatabaseBridge createDatabaseBridge(Island island) {\n        return databaseBridgeFactory.createIslandsDatabaseBridge(island, new SQLDatabaseBridge());\n    }\n\n    public DatabaseBridge createDatabaseBridge(SuperiorPlayer superiorPlayer) {\n        return databaseBridgeFactory.createPlayersDatabaseBridge(superiorPlayer, new SQLDatabaseBridge());\n    }\n\n    public DatabaseBridge createDatabaseBridge(GridManager gridManager) {\n        return databaseBridgeFactory.createGridDatabaseBridge(gridManager, new SQLDatabaseBridge());\n    }\n\n    public DatabaseBridge createDatabaseBridge(StackedBlocksManager stackedBlocksManager) {\n        return databaseBridgeFactory.createStackedBlocksDatabaseBridge(stackedBlocksManager, new SQLDatabaseBridge());\n    }\n\n    public PersistentDataContainer createPersistentDataContainer(Island island) {\n        return islandsFactory.createPersistentDataContainer(island, new PersistentDataContainerImpl<>(\n                island, IslandsDatabaseBridge::markPersistentDataContainerToBeSaved));\n    }\n\n    public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer) {\n        return playersFactory.createPersistentDataContainer(superiorPlayer, new PersistentDataContainerImpl<>(\n                superiorPlayer, PlayersDatabaseBridge::markPersistentDataContainerToBeSaved));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting;\n\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.BlockPositionFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.BooleanFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.BorderColorFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.CapitalizedFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.ColorFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.CommaFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.DateFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.FancyNumberFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.LocaleFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.LocationFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.NumberFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.RatingFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.StripColorFormatter;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.TimeFormatter;\nimport org.bukkit.Location;\n\nimport java.time.Duration;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class Formatters {\n\n    public static final IBiFormatter<Boolean, Locale> BOOLEAN_FORMATTER = BooleanFormatter.getInstance();\n    public static final IBiFormatter<BorderColor, Locale> BORDER_COLOR_FORMATTER = BorderColorFormatter.getInstance();\n    public static final IFormatter<String> CAPITALIZED_FORMATTER = CapitalizedFormatter.getInstance();\n    public static final IFormatter<String> COLOR_FORMATTER = ColorFormatter.getInstance();\n    public static final IFormatter<Stream<String>> COMMA_FORMATTER = CommaFormatter.getInstance();\n    public static final IFormatter<Date> DATE_FORMATTER = DateFormatter.getInstance();\n    public static final IBiFormatter<Number, Locale> FANCY_NUMBER_FORMATTER = FancyNumberFormatter.getInstance();\n    public static final IFormatter<Locale> LOCALE_FORMATTER = LocaleFormatter.getInstance();\n    public static final IFormatter<Location> LOCATION_FORMATTER = LocationFormatter.getInstance();\n    public static final IFormatter<Number> NUMBER_FORMATTER = NumberFormatter.getInstance();\n    public static final IBiFormatter<Number, Locale> RATING_FORMATTER = RatingFormatter.getInstance();\n    public static final IFormatter<String> STRIP_COLOR_FORMATTER = StripColorFormatter.getInstance();\n    public static final IBiFormatter<Duration, Locale> TIME_FORMATTER = TimeFormatter.getInstance();\n    public static final IFormatter<ChatFormatter.ChatFormatArgs> CHAT_FORMATTER = ChatFormatter.getInstance();\n    public static final IBiFormatter<BlockPosition, WorldInfo> BLOCK_POSITION_FORMATTER = BlockPositionFormatter.getInstance();\n\n    private Formatters() {\n\n    }\n\n    public static <T> List<String> formatList(List<T> list, IFormatter<T> formatter) {\n        return list.stream().map(formatter::format).collect(Collectors.toList());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting;\n\npublic interface IBiFormatter<T, K> {\n\n    String format(T value, K value2);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting;\n\npublic interface IFormatter<T> {\n\n    String format(T value);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\n\npublic class BlockPositionFormatter implements IBiFormatter<BlockPosition, WorldInfo> {\n\n    private static final BlockPositionFormatter INSTANCE = new BlockPositionFormatter();\n\n    public static BlockPositionFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private BlockPositionFormatter() {\n\n    }\n\n    @Override\n    public String format(BlockPosition value, WorldInfo worldInfo) {\n        return worldInfo.getName() + \", \" + value.getX() + \", \" + value.getY() + \", \" + value.getZ();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\n\nimport java.util.Locale;\n\npublic class BooleanFormatter implements IBiFormatter<Boolean, Locale> {\n\n    private static final BooleanFormatter INSTANCE = new BooleanFormatter();\n\n    public static BooleanFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private BooleanFormatter() {\n\n    }\n\n    @Override\n    public String format(Boolean value, Locale locale) {\n        return (value ? Message.PLACEHOLDER_YES : Message.PLACEHOLDER_NO).getMessage(locale);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\n\nimport java.util.EnumMap;\nimport java.util.Locale;\n\npublic class BorderColorFormatter implements IBiFormatter<BorderColor, Locale> {\n\n    private static final BorderColorFormatter INSTANCE = new BorderColorFormatter();\n\n    private static final EnumMap<BorderColor, Message> BORDER_COLOR_MESSAGES = new EnumMap<>(BorderColor.class);\n\n    static {\n        BORDER_COLOR_MESSAGES.put(BorderColor.RED, Message.BORDER_PLAYER_COLOR_NAME_RED);\n        BORDER_COLOR_MESSAGES.put(BorderColor.BLUE, Message.BORDER_PLAYER_COLOR_NAME_BLUE);\n        BORDER_COLOR_MESSAGES.put(BorderColor.GREEN, Message.BORDER_PLAYER_COLOR_NAME_GREEN);\n    }\n\n    public static BorderColorFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private BorderColorFormatter() {\n\n    }\n\n    @Override\n    public String format(BorderColor value, Locale locale) {\n        return BORDER_COLOR_MESSAGES.get(value).getMessage(locale);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/CapitalizedFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\n\nimport java.util.Locale;\n\npublic class CapitalizedFormatter implements IFormatter<String> {\n\n    private static final CapitalizedFormatter INSTANCE = new CapitalizedFormatter();\n\n    public static CapitalizedFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private CapitalizedFormatter() {\n\n    }\n\n    @Override\n    public String format(String value) {\n        StringBuilder formattedKey = new StringBuilder();\n\n        try {\n            String[] split = value.split(\":\");\n            //Checking if the type is <TYPE>:<INTEGER>\n            Integer.parseInt(split[1]);\n            value = split[0];\n        } catch (Throwable ignored) {\n        }\n\n        value = value.replace(\":\", \"_-_\");\n\n        for (String subKey : value.split(\"_\")) {\n            if (!Text.isBlank(subKey)) {\n                formattedKey.append(\" \")\n                        .append(subKey.substring(0, 1).toUpperCase(Locale.ENGLISH))\n                        .append(subKey.substring(1).toLowerCase(Locale.ENGLISH));\n            }\n        }\n\n        return formattedKey.substring(1);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\n\npublic class ChatFormatter implements IFormatter<ChatFormatter.ChatFormatArgs> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ChatFormatter INSTANCE = new ChatFormatter();\n\n    public static ChatFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private ChatFormatter() {\n\n    }\n\n    @Override\n    public String format(ChatFormatter.ChatFormatArgs args) {\n        String islandNameFormat = Message.NAME_CHAT_FORMAT.getMessage(PlayerLocales.getDefaultLocale(),\n                args.island == null ? \"\" : args.island.getName());\n\n        return args.format\n                .replace(\"{island-level}\", String.valueOf(args.island == null ? 0 : args.island.getIslandLevel()))\n                .replace(\"{island-level-format}\", String.valueOf(args.island == null ? 0 :\n                        Formatters.FANCY_NUMBER_FORMATTER.format(args.island.getIslandLevel(), args.superiorPlayer.getUserLocale())))\n                .replace(\"{island-worth}\", String.valueOf(args.island == null ? 0 : args.island.getWorth()))\n                .replace(\"{island-worth-format}\", String.valueOf(args.island == null ? 0 :\n                        Formatters.FANCY_NUMBER_FORMATTER.format(args.island.getWorth(), args.superiorPlayer.getUserLocale())))\n                .replace(\"{island-name}\", islandNameFormat == null ? \"\" : islandNameFormat)\n                .replace(\"{island-role}\", args.superiorPlayer.getPlayerRole().getDisplayName())\n                .replace(\"{island-position-worth}\", args.island == null ? \"\" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_WORTH) + 1) + \"\")\n                .replace(\"{island-position-level}\", args.island == null ? \"\" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_LEVEL) + 1) + \"\")\n                .replace(\"{island-position-rating}\", args.island == null ? \"\" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_RATING) + 1) + \"\")\n                .replace(\"{island-position-players}\", args.island == null ? \"\" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_PLAYERS) + 1) + \"\");\n    }\n\n    public static class ChatFormatArgs {\n\n        private final String format;\n        private final SuperiorPlayer superiorPlayer;\n        @Nullable\n        private final Island island;\n\n        public ChatFormatArgs(String format, SuperiorPlayer superiorPlayer, @Nullable Island island) {\n            this.format = format;\n            this.superiorPlayer = superiorPlayer;\n            this.island = island;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\nimport com.bgsoftware.superiorskyblock.external.text.ITextFormatter;\nimport org.bukkit.ChatColor;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class ColorFormatter implements IFormatter<String> {\n\n    private static final ColorFormatter INSTANCE = new ColorFormatter();\n\n    private static final List<ITextFormatter> TEXT_FORMATTERS = new LinkedList<>();\n\n    static {\n        TEXT_FORMATTERS.add(ChatColorTextFormatter.INSTANCE);\n        if (ServerVersion.isAtLeast(ServerVersion.v1_16))\n            TEXT_FORMATTERS.add(HexTextFormatter.INSTANCE);\n    }\n\n    private static final Pattern HEX_COLOR_PATTERN = Pattern.compile(\"([&§])(\\\\{HEX:([0-9A-Fa-f]*)})\");\n\n    public static ColorFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private ColorFormatter() {\n\n    }\n\n    @Override\n    public String format(String value) {\n        if (Text.isBlank(value))\n            return \"\";\n\n        String output = value;\n        for (ITextFormatter formatter : TEXT_FORMATTERS) {\n            output = formatter.format(output);\n        }\n\n        return output;\n    }\n\n    private static class ChatColorTextFormatter implements ITextFormatter {\n\n        private static final ChatColorTextFormatter INSTANCE = new ChatColorTextFormatter();\n\n        @Override\n        public String format(String value) {\n            return ChatColor.translateAlternateColorCodes('&', value);\n        }\n\n    }\n\n    private static class HexTextFormatter implements ITextFormatter {\n\n        private static final HexTextFormatter INSTANCE = new HexTextFormatter();\n\n        @Override\n        public String format(String value) {\n            while (true) {\n                Matcher matcher = HEX_COLOR_PATTERN.matcher(value);\n\n                if (!matcher.find())\n                    break;\n\n                value = matcher.replaceFirst(parseHexColor(matcher.group(3)));\n            }\n\n            return value;\n        }\n\n        private static String parseHexColor(String hexColor) {\n            if (hexColor.length() != 6 && hexColor.length() != 3)\n                return hexColor;\n\n            StringBuilder magic = new StringBuilder(ChatColor.COLOR_CHAR + \"x\");\n            int multiplier = hexColor.length() == 3 ? 2 : 1;\n\n            for (char ch : hexColor.toCharArray()) {\n                for (int i = 0; i < multiplier; i++)\n                    magic.append(ChatColor.COLOR_CHAR).append(ch);\n            }\n\n            return magic.toString();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/CommaFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\n\nimport java.util.stream.Stream;\n\npublic class CommaFormatter implements IFormatter<Stream<String>> {\n\n    private static final CommaFormatter INSTANCE = new CommaFormatter();\n\n    public static CommaFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private CommaFormatter() {\n    }\n\n    @Override\n    public String format(Stream<String> values) {\n        StringBuilder stringBuilder = new StringBuilder();\n        values.forEach(value -> stringBuilder.append(\", \").append(value));\n        return stringBuilder.substring(2);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/DateFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class DateFormatter implements IFormatter<Date> {\n\n    private static final DateFormatter INSTANCE = new DateFormatter();\n\n    private static SimpleDateFormat dateFormatter;\n\n    public static void setDateFormatter(SuperiorSkyblockPlugin plugin, String dateFormat) {\n        dateFormatter = new SimpleDateFormat(dateFormat);\n        try {\n            for (Island island : plugin.getGrid().getIslands()) {\n                island.updateDatesFormatter();\n            }\n        } catch (Exception ignored) {\n        }\n    }\n\n    public static DateFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private DateFormatter() {\n\n    }\n\n    @Override\n    public String format(Date value) {\n        return dateFormatter.format(value);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\n\nimport java.util.Locale;\n\npublic class FancyNumberFormatter implements IBiFormatter<Number, Locale> {\n\n    private static final FancyNumberFormatter INSTANCE = new FancyNumberFormatter();\n\n    private static final double Q = 1000000000000000D;\n    private static final double T = 1000000000000D;\n    private static final double B = 1000000000D;\n    private static final double M = 1000000D;\n    private static final double K = 1000D;\n\n    public static FancyNumberFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private FancyNumberFormatter() {\n\n    }\n\n    @Override\n    public String format(Number value, Locale locale) {\n        double doubleValue = value.doubleValue();\n        if (doubleValue >= Q)\n            return Formatters.NUMBER_FORMATTER.format(doubleValue / Q) + Message.FORMAT_QUAD.getMessage(locale);\n        else if (doubleValue >= T)\n            return Formatters.NUMBER_FORMATTER.format(doubleValue / T) + Message.FORMAT_TRILLION.getMessage(locale);\n        else if (doubleValue >= B)\n            return Formatters.NUMBER_FORMATTER.format(doubleValue / B) + Message.FORMAT_BILLION.getMessage(locale);\n        else if (doubleValue >= M)\n            return Formatters.NUMBER_FORMATTER.format(doubleValue / M) + Message.FORMAT_MILLION.getMessage(locale);\n        else if (doubleValue >= K)\n            return Formatters.NUMBER_FORMATTER.format(doubleValue / K) + Message.FORMAT_THOUSANDS.getMessage(locale);\n        else\n            return Formatters.NUMBER_FORMATTER.format(value);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/LocaleFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\n\nimport java.util.Locale;\n\npublic class LocaleFormatter implements IFormatter<Locale> {\n\n    private static final LocaleFormatter INSTANCE = new LocaleFormatter();\n\n    public static LocaleFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private LocaleFormatter() {\n\n    }\n\n    @Override\n    public String format(Locale value) {\n        return value.getLanguage() + \"-\" + value.getCountry();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/LocationFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\nimport org.bukkit.Location;\n\npublic class LocationFormatter implements IFormatter<Location> {\n\n    private static final LocationFormatter INSTANCE = new LocationFormatter();\n\n    public static LocationFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private LocationFormatter() {\n\n    }\n\n    @Override\n    public String format(Location value) {\n        return LazyWorldLocation.getWorldName(value) + \", \" + value.getBlockX() + \", \" + value.getBlockY() + \", \" + value.getBlockZ();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/NumberFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.math.RoundingMode;\nimport java.text.DecimalFormat;\nimport java.text.NumberFormat;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class NumberFormatter implements IFormatter<Number> {\n\n    private static final NumberFormatter INSTANCE = new NumberFormatter();\n\n    private static final Pattern NUMBER_PATTERN = Pattern.compile(\"^[a-z]{2}[_|-][A-Z]{2}$\");\n    private static final char SPACE_ASCII = 160;\n\n    private static Pattern DECIMAL_PATTERN;\n    private static DecimalFormat numberFormatter;\n    private static char decimalSeparator;\n\n    public static void setNumberFormatter(String numberFormat) {\n        numberFormat = numberFormat.replace(\"_\", \"-\");\n\n        if (!NUMBER_PATTERN.matcher(numberFormat).matches()) {\n            Log.warn(\"The number format \\\"\", numberFormat, \"\\\" is invalid. Using default one: en-US.\");\n            numberFormat = \"en-US\";\n        }\n\n        String[] numberFormatSections = numberFormat.split(\"-\");\n        numberFormatter = (DecimalFormat) NumberFormat.getInstance(new java.util.Locale(numberFormatSections[0], numberFormatSections[1]));\n        numberFormatter.setGroupingUsed(true);\n        numberFormatter.setMinimumFractionDigits(2);\n        numberFormatter.setMaximumFractionDigits(2);\n        numberFormatter.setRoundingMode(RoundingMode.FLOOR);\n\n        decimalSeparator = numberFormatter.getDecimalFormatSymbols().getDecimalSeparator();\n\n        DECIMAL_PATTERN = Pattern.compile(\"(.*)\" + Pattern.quote(decimalSeparator + \"\") + \"(\\\\d)0\");\n    }\n\n    public static NumberFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private NumberFormatter() {\n\n    }\n\n    @Override\n    public String format(Number value) {\n        //Because of some issues with formatting, spaces are converted to ascii 160.\n        String formattedNumber = numberFormatter.format(value).replace(SPACE_ASCII, ' ');\n\n        Matcher matcher;\n\n        if (formattedNumber.endsWith(decimalSeparator + \"00\")) {\n            return formattedNumber.replace(decimalSeparator + \"00\", \"\");\n        } else if ((matcher = DECIMAL_PATTERN.matcher(formattedNumber)).matches()) {\n            return formattedNumber.replaceAll(Pattern.quote(decimalSeparator + \"\") + \"(\\\\d)0\", decimalSeparator + matcher.group(2));\n        }\n\n        return formattedNumber;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\n\nimport java.util.Locale;\n\npublic class RatingFormatter implements IBiFormatter<Number, Locale> {\n\n    private static final RatingFormatter INSTANCE = new RatingFormatter();\n\n    public static RatingFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private RatingFormatter() {\n\n    }\n\n    @Override\n    public String format(Number value, Locale locale) {\n        StringBuilder starsString = new StringBuilder();\n        double rating = value.doubleValue();\n\n        if (rating >= 1)\n            starsString.append(Message.ISLAND_INFO_RATE_ONE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale));\n        if (rating >= 2)\n            starsString.append(Message.ISLAND_INFO_RATE_TWO_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale));\n        if (rating >= 3)\n            starsString.append(Message.ISLAND_INFO_RATE_THREE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale));\n        if (rating >= 4)\n            starsString.append(Message.ISLAND_INFO_RATE_FOUR_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale));\n        if (rating >= 5)\n            starsString.append(Message.ISLAND_INFO_RATE_FIVE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale));\n\n        for (int i = 5; i > rating && i > 0; i--)\n            starsString.append(Message.ISLAND_INFO_RATE_EMPTY_SYMBOL.getMessage(locale));\n\n        return starsString.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/StripColorFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.formatting.IFormatter;\nimport com.bgsoftware.superiorskyblock.core.Text;\n\nimport java.util.regex.Pattern;\n\npublic class StripColorFormatter implements IFormatter<String> {\n\n    private static final StripColorFormatter INSTANCE = new StripColorFormatter();\n\n    private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile(\"(?i)([&§])[0-9A-FK-OR]\");\n\n    public static StripColorFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private StripColorFormatter() {\n\n    }\n\n    @Override\n    public String format(String value) {\n        return Text.isBlank(value) ? \"\" : STRIP_COLOR_PATTERN.matcher(value).replaceAll(\"\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.formatting.impl;\n\nimport com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\n\nimport java.time.Duration;\nimport java.util.Locale;\n\npublic class TimeFormatter implements IBiFormatter<Duration, Locale> {\n\n    private static final TimeFormatter INSTANCE = new TimeFormatter();\n\n    public static TimeFormatter getInstance() {\n        return INSTANCE;\n    }\n\n    private TimeFormatter() {\n\n    }\n\n    @Override\n    public String format(Duration value, Locale locale) {\n        Locale formatLocale = locale == null ? PlayerLocales.getDefaultLocale() : locale;\n\n        StringBuilder timeBuilder = new StringBuilder();\n        boolean RTL = PlayerLocales.isRightToLeft(formatLocale);\n\n        {\n            long days = value.toDays();\n            if (days > 0) {\n                formatTimeSection(timeBuilder, RTL, days, days == 1 ? Message.FORMAT_DAY_NAME : Message.FORMAT_DAYS_NAME, formatLocale);\n                value = value.minusDays(days);\n            }\n        }\n\n        {\n            long hours = value.toHours();\n            if (hours > 0) {\n                formatTimeSection(timeBuilder, RTL, hours, hours == 1 ? Message.FORMAT_HOUR_NAME : Message.FORMAT_HOURS_NAME, formatLocale);\n                value = value.minusHours(hours);\n            }\n        }\n\n        {\n            long minutes = value.toMinutes();\n            if (minutes > 0) {\n                formatTimeSection(timeBuilder, RTL, minutes, minutes == 1 ? Message.FORMAT_MINUTE_NAME : Message.FORMAT_MINUTES_NAME, formatLocale);\n                value = value.minusMinutes(minutes);\n            }\n        }\n\n        {\n            long seconds = value.getSeconds();\n            if (seconds > 0)\n                formatTimeSection(timeBuilder, RTL, seconds, seconds == 1 ? Message.FORMAT_SECOND_NAME : Message.FORMAT_SECONDS_NAME, formatLocale);\n        }\n\n        if (timeBuilder.length() == 0) {\n            if (RTL) {\n                timeBuilder.insert(0, \"1 \").append(Message.FORMAT_SECOND_NAME.getMessage(formatLocale)).insert(0, \" ,\");\n            } else {\n                timeBuilder.append(\"1 \").append(Message.FORMAT_SECOND_NAME.getMessage(formatLocale)).append(\", \");\n            }\n        }\n\n        return RTL ? timeBuilder.substring(2) : timeBuilder.substring(0, timeBuilder.length() - 2);\n    }\n\n    private static void formatTimeSection(StringBuilder stringBuilder, boolean RTL, long value,\n                                          Message timeFormatMessage, Locale locale) {\n        if (RTL) {\n            stringBuilder.insert(0, value)\n                    .insert(0, \" \")\n                    .insert(0, timeFormatMessage.getMessage(locale))\n                    .insert(0, \", \");\n        } else {\n            stringBuilder.append(value)\n                    .append(\" \")\n                    .append(timeFormatMessage.getMessage(locale))\n                    .append(\", \");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/ClassProcessor.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\npublic interface ClassProcessor {\n\n    byte[] processClass(byte[] classBytes, String path);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/FileClassLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.google.common.io.ByteStreams;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.security.CodeSigner;\nimport java.security.CodeSource;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\npublic class FileClassLoader extends URLClassLoader {\n\n    private final Map<String, Class<?>> classes = new ConcurrentHashMap<>();\n\n    private JarFile jar;\n    private final Manifest manifest;\n    private final URL url;\n    @Nullable\n    private final ClassProcessor classProcessor;\n\n    public FileClassLoader(File file, ClassLoader pluginClassLoader, @Nullable ClassProcessor classProcessor) throws IOException {\n        super(new URL[]{file.toURI().toURL()}, pluginClassLoader);\n\n        this.jar = new JarFile(file);\n        this.manifest = jar.getManifest();\n        this.url = file.toURI().toURL();\n        this.classProcessor = classProcessor;\n    }\n\n    @Nullable\n    @Override\n    public URL getResource(String name) {\n        URL url = findResource(name);\n        return url == null ? super.getResource(name) : url;\n    }\n\n    @Override\n    public void close() throws IOException {\n        this.classes.clear();\n\n        jar.close();\n        this.jar = null;\n\n        super.close();\n    }\n\n    @Override\n    protected Class<?> findClass(String name) throws ClassNotFoundException {\n        Class<?> result = classes.get(name);\n\n        if (result == null) {\n            String path = name.replace('.', '/').concat(\".class\");\n            JarEntry entry = jar.getJarEntry(path);\n\n            if (entry != null) {\n                byte[] classBytes;\n\n                try (InputStream is = jar.getInputStream(entry)) {\n                    //noinspection UnstableApiUsage\n                    classBytes = ByteStreams.toByteArray(is);\n                } catch (IOException ex) {\n                    throw new ClassNotFoundException(name, ex);\n                }\n\n                if (classProcessor != null)\n                    classBytes = classProcessor.processClass(classBytes, path);\n\n                int dot = name.lastIndexOf('.');\n                if (dot != -1) {\n                    String pkgName = name.substring(0, dot);\n                    if (getPackage(pkgName) == null) {\n                        try {\n                            if (manifest != null) {\n                                definePackage(pkgName, manifest, url);\n                            } else {\n                                definePackage(pkgName, null, null, null, null, null, null, null);\n                            }\n                        } catch (IllegalArgumentException ex) {\n                            if (getPackage(pkgName) == null) {\n                                throw new IllegalStateException(\"Cannot find package \" + pkgName);\n                            }\n                        }\n                    }\n                }\n\n                CodeSigner[] signers = entry.getCodeSigners();\n                CodeSource source = new CodeSource(url, signers);\n\n                result = defineClass(name, classBytes, 0, classBytes.length, source);\n            }\n\n            if (result == null) {\n                result = super.findClass(name);\n            }\n\n            classes.put(name, result);\n        }\n\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/Files.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport javax.annotation.Nullable;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic class Files {\n\n    private static final Set<String> BLACKLISTED_FILE_NAMES = initializeBlacklistedFileNames();\n\n    private static final Object mutex = new Object();\n\n    private Files() {\n\n    }\n\n    public static void deleteDirectory(File directory) {\n        if (directory.isDirectory()) {\n            File[] childFiles = directory.listFiles();\n            if (childFiles != null) {\n                for (File file : childFiles)\n                    deleteDirectory(file);\n            }\n        }\n\n        //noinspection ResultOfMethodCallIgnored\n        directory.delete();\n    }\n\n    public static void replaceString(File file, String str, String replace) {\n        synchronized (mutex) {\n            StringBuilder stringBuilder = new StringBuilder();\n\n            try {\n                try (BufferedReader reader = new BufferedReader(new FileReader(file))) {\n                    String line;\n                    while ((line = reader.readLine()) != null)\n                        stringBuilder.append(\"\\n\").append(line);\n                }\n\n                if (stringBuilder.length() > 0) {\n                    try (FileWriter writer = new FileWriter(file)) {\n                        writer.write(stringBuilder.substring(1).replace(str, replace));\n                    }\n                }\n            } catch (Exception error) {\n                Log.entering(\"ENTER\", file.getName(), str, replace);\n                Log.error(error, \"An unexpected error occurred while replacing strings in file:\");\n            }\n        }\n    }\n\n    public static List<File> listFolderFiles(File folder, boolean recursive) {\n        return listFolderFiles(folder, recursive, null);\n    }\n\n    public static List<File> listFolderFiles(File folder, boolean recursive, @Nullable Predicate<File> predicate) {\n        if (!folder.isDirectory())\n            return Collections.emptyList();\n\n        List<File> folderFiles = new LinkedList<>();\n\n        File[] folderFilesArr = folder.listFiles();\n        if (folderFilesArr != null && folderFilesArr.length > 0) {\n            for (File file : folderFilesArr) {\n                if (file.isDirectory()) {\n                    if (recursive)\n                        folderFiles.addAll(listFolderFiles(folder, true, predicate));\n                } else if (!BLACKLISTED_FILE_NAMES.contains(file.getName().toLowerCase(Locale.ENGLISH)) &&\n                        (predicate == null || predicate.test(file))) {\n                    folderFiles.add(file);\n                }\n            }\n        }\n\n        return folderFiles.isEmpty() ? Collections.emptyList() : folderFiles;\n    }\n\n    public static String getFileName(File file) {\n        String[] fileNameSections = file.getName().split(\"\\\\.\");\n        return fileNameSections.length == 1 ? fileNameSections[0] :\n                file.getName().replace(\".\" + fileNameSections[fileNameSections.length - 1], \"\");\n    }\n\n    private static Set<String> initializeBlacklistedFileNames() {\n        return Collections.singleton(\".ds_store\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/IOUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class IOUtils {\n\n    private static final int EOF = -1;\n\n    private IOUtils() {\n\n    }\n\n    public static byte[] toByteArray(InputStream inputStream) throws IOException {\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        copy(inputStream, outputStream);\n        return outputStream.toByteArray();\n    }\n\n    public static int copy(InputStream inputStream, OutputStream outputStream) throws IOException {\n        long bytesCopied = copyLarge(inputStream, outputStream);\n        return bytesCopied > 0x7FFFFFFFL ? -1 : (int) bytesCopied;\n    }\n\n    public static long copyLarge(InputStream inputStream, OutputStream outputStream) throws IOException {\n        return copyLarge(inputStream, outputStream, new byte[4096]);\n    }\n\n    public static long copyLarge(InputStream inputStream, OutputStream outputStream, byte[] buf) throws IOException {\n        long totalBytesCopied = 0;\n\n        int bytesCopied;\n        while ((bytesCopied = inputStream.read(buf)) != EOF) {\n            outputStream.write(buf, 0, bytesCopied);\n            totalBytesCopied += bytesCopied;\n        }\n\n        return totalBytesCopied;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/JarFiles.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport com.bgsoftware.superiorskyblock.core.Either;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarInputStream;\n\npublic class JarFiles {\n\n    private JarFiles() {\n\n    }\n\n    public static Either<Class<?>, Throwable> getClass(URL jar, Class<?> clazz, ClassLoader classLoader) {\n        try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, classLoader); JarInputStream jis = new JarInputStream(jar.openStream())) {\n            JarEntry jarEntry;\n            while ((jarEntry = jis.getNextJarEntry()) != null) {\n                String name = jarEntry.getName();\n\n                if (!name.endsWith(\".class\")) {\n                    continue;\n                }\n\n                name = name.replace(\"/\", \".\");\n                String clazzName = name.substring(0, name.lastIndexOf(\".class\"));\n\n                try {\n                    Class<?> c = cl.loadClass(clazzName);\n                    if (clazz.isAssignableFrom(c)) {\n                        return Either.left(c);\n                    }\n                } catch (NoClassDefFoundError ignored) {\n                    // If we can't find the class, can just be ignored.\n                }\n            }\n        } catch (Throwable error) {\n            return Either.right(error);\n        }\n\n        return Either.right(null);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.parser.MenuParseException;\nimport com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.itemstack.MinecraftNamesMapper;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BackButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl;\nimport org.bukkit.DyeColor;\nimport org.bukkit.Material;\nimport org.bukkit.Sound;\nimport org.bukkit.block.banner.PatternType;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.InvalidConfigurationException;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.ItemFlag;\nimport org.bukkit.potion.PotionEffect;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.function.Function;\n\npublic class MenuParserImpl implements MenuParser {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final MenuParserImpl INSTANCE = new MenuParserImpl();\n    private static final LazyReference<MinecraftNamesMapper> NAMES_MAPPER = new LazyReference<MinecraftNamesMapper>() {\n        @Override\n        protected MinecraftNamesMapper create() {\n            return new MinecraftNamesMapper();\n        }\n    };\n\n    public static MenuParserImpl getInstance() {\n        return INSTANCE;\n    }\n\n    private MenuParserImpl() {\n\n    }\n\n    @Override\n    public <V extends MenuView<V, ?>> MenuParseResult<V> parseMenu(String callerName, YamlConfiguration cfg) throws MenuParseException {\n        RegularMenuLayoutImpl.Builder<V> menuLayoutBuilder = new RegularMenuLayoutImpl.Builder<>();\n\n        menuLayoutBuilder.setTitle(Formatters.COLOR_FORMATTER.format(cfg.getString(\"title\", \"\")));\n        menuLayoutBuilder.setInventoryType(getMinecraftEnum(InventoryType.class, cfg.getString(\"type\", \"CHEST\")));\n\n        MenuPatternSlots menuPatternSlots = new MenuPatternSlots();\n        List<String> pattern = cfg.getStringList(\"pattern\");\n\n        menuLayoutBuilder.setRowsCount(pattern.size());\n\n        for (int row = 0; row < pattern.size() && row < 6; row++) {\n            String patternLine = pattern.get(row).replace(\" \", \"\");\n            for (int i = 0; i < patternLine.length() && i < 9; i++) {\n                int slot = row * 9 + i;\n\n                char ch = patternLine.charAt(i);\n\n                AbstractMenuTemplateButton.AbstractBuilder<V> buttonBuilder = new DummyButton.Builder<>();\n\n                buttonBuilder.setButtonItem(getItemStack(callerName, cfg.getConfigurationSection(\"items.\" + ch)));\n                buttonBuilder.setClickCommands(cfg.getStringList(\"commands.\" + ch));\n                buttonBuilder.setClickSound(getSound(cfg.getConfigurationSection(\"sounds.\" + ch)));\n                buttonBuilder.setRequiredPermission(cfg.getString(\"permissions.\" + ch + \".permission\"));\n                buttonBuilder.setLackPermissionsSound(getSound(cfg.getConfigurationSection(\"permissions.\" + ch + \".no-access-sound\")));\n\n                menuLayoutBuilder.setButton(slot, buttonBuilder.build());\n\n                menuPatternSlots.addSlot(ch, slot);\n            }\n        }\n\n        boolean previousMoveAllowed = cfg.getBoolean(\"previous-menu\", true);\n        boolean skipOneItem = cfg.getBoolean(\"skip-one-item\", false);\n        GameSound openingSound = getSound(cfg.getConfigurationSection(\"open-sound\"));\n\n        return new MenuParseResult<>(menuLayoutBuilder, openingSound, previousMoveAllowed, skipOneItem, menuPatternSlots, cfg);\n    }\n\n    @Override\n    public <V extends PagedMenuView<V, ?, E>, E> MenuParseResult<V> parseMenu(\n            String callerName, YamlConfiguration cfg, PagedMenuTemplateButton.Builder<V, E> pagedButtonBuilder) throws MenuParseException {\n        PagedMenuLayoutImpl.Builder<V, E> menuLayoutBuilder = new PagedMenuLayoutImpl.Builder<>();\n\n        menuLayoutBuilder.setTitle(Formatters.COLOR_FORMATTER.format(cfg.getString(\"title\", \"\")));\n        menuLayoutBuilder.setInventoryType(getMinecraftEnum(InventoryType.class, cfg.getString(\"type\", \"CHEST\")));\n\n        MenuPatternSlots menuPatternSlots = new MenuPatternSlots();\n        List<String> pattern = cfg.getStringList(\"pattern\");\n\n        menuLayoutBuilder.setRowsCount(pattern.size());\n\n        String backButton = cfg.getString(\"back\", \"\");\n        boolean backButtonFound = false;\n\n        for (int row = 0; row < pattern.size() && row < 6; row++) {\n            String patternLine = pattern.get(row).replace(\" \", \"\");\n            for (int i = 0; i < patternLine.length() && i < 9; i++) {\n                int slot = row * 9 + i;\n\n                char ch = patternLine.charAt(i);\n\n                boolean isBackButton = backButton.contains(ch + \"\");\n\n                if (isBackButton) {\n                    backButtonFound = true;\n                }\n\n                AbstractMenuTemplateButton.AbstractBuilder<V> buttonBuilder = isBackButton ?\n                        new BackButton.Builder<>() : new DummyButton.Builder<>();\n\n                buttonBuilder.setButtonItem(getItemStackUnsafe(callerName, cfg.getConfigurationSection(\"items.\" + ch)));\n                buttonBuilder.setClickCommands(cfg.getStringList(\"commands.\" + ch));\n                buttonBuilder.setClickSound(getSound(cfg.getConfigurationSection(\"sounds.\" + ch)));\n                buttonBuilder.setRequiredPermission(cfg.getString(\"permissions.\" + ch + \".permission\"));\n                buttonBuilder.setLackPermissionsSound(getSound(cfg.getConfigurationSection(\"permissions.\" + ch + \".no-access-sound\")));\n\n                menuLayoutBuilder.setButton(slot, buttonBuilder.build());\n\n                menuPatternSlots.addSlot(ch, slot);\n            }\n        }\n\n        if (plugin.getSettings().isOnlyBackButton() && !backButtonFound) {\n            throw new MenuParseException(\"Menu doesn't have a back button, it's impossible to close it.\");\n        }\n\n        menuLayoutBuilder.setPreviousPageSlots(parseButtonSlots(cfg, \"previous-page\", menuPatternSlots));\n        menuLayoutBuilder.setCurrentPageSlots(parseButtonSlots(cfg, \"current-page\", menuPatternSlots));\n        menuLayoutBuilder.setNextPageSlots(parseButtonSlots(cfg, \"next-page\", menuPatternSlots));\n        menuLayoutBuilder.setPagedObjectSlots(parseButtonSlots(cfg, \"slots\", menuPatternSlots), pagedButtonBuilder);\n\n        if (cfg.isList(\"custom-order\"))\n            menuLayoutBuilder.setCustomLayoutOrder(cfg.getIntegerList(\"custom-order\"));\n\n        boolean previousMoveAllowed = cfg.getBoolean(\"previous-menu\", true);\n        boolean skipOneItem = cfg.getBoolean(\"skip-one-item\", false);\n        GameSound openingSound = getSound(cfg.getConfigurationSection(\"open-sound\"));\n\n        return new MenuParseResult<>(menuLayoutBuilder, openingSound, previousMoveAllowed, skipOneItem, menuPatternSlots, cfg);\n    }\n\n    @Nullable\n    public <V extends MenuView<V, ?>> MenuParseResult<V> loadCustomMenu(String fileName, @Nullable IMenuConverter converter) {\n        return loadMenuInternal(fileName, true, converter);\n    }\n\n    @Nullable\n    public <V extends MenuView<V, ?>> MenuParseResult<V> loadMenu(String fileName, @Nullable IMenuConverter converter) {\n        return loadMenuInternal(fileName, false, converter);\n    }\n\n    @Nullable\n    public <V extends PagedMenuView<V, ?, E>, E> MenuParseResult<V> loadMenu(String fileName, @Nullable IMenuConverter converter,\n                                                                             PagedMenuTemplateButton.Builder<V, E> pagedButtonItemBuilder) {\n        File file = new File(plugin.getDataFolder(), \"menus/\" + fileName);\n\n        CommentedConfiguration cfg = loadMenuFile(file, fileName, false, converter);\n\n        if (cfg != null) {\n            try {\n                return parseMenu(fileName, cfg, pagedButtonItemBuilder);\n            } catch (MenuParseException error) {\n                Log.errorFromFile(fileName, error.getMessage());\n            }\n        }\n\n        return null;\n    }\n\n    @Nullable\n    public TemplateItem getItemStack(String fileName, ConfigurationSection section) {\n        try {\n            return getItemStackUnsafe(fileName, section);\n        } catch (MenuParseException error) {\n            Log.errorFromFile(fileName, error.getMessage());\n            return null;\n        }\n    }\n\n    @Nullable\n    public GameSound getSound(ConfigurationSection section) {\n        if (section == null)\n            return null;\n\n        String soundType = section.getString(\"type\");\n\n        if (soundType == null)\n            return null;\n\n        Sound sound;\n\n        try {\n            sound = getMinecraftEnum(Sound.class, soundType);\n        } catch (Exception ignored) {\n            return null;\n        }\n\n        return new GameSoundImpl(sound, (float) section.getDouble(\"volume\", 1),\n                (float) section.getDouble(\"pitch\", 1));\n    }\n\n    @Nullable\n    private <V extends MenuView<V, ?>> MenuParseResult<V> loadMenuInternal(String fileName, boolean customMenu,\n                                                                           @Nullable IMenuConverter converter) {\n        String menuPath = customMenu ? \"custom/\" : \"\";\n\n        File file = new File(plugin.getDataFolder(), \"menus/\" + menuPath + fileName);\n\n        CommentedConfiguration cfg = loadMenuFile(file, fileName, customMenu, converter);\n\n        if (cfg != null) {\n            try {\n                return parseMenu(fileName, cfg);\n            } catch (MenuParseException error) {\n                Log.errorFromFile(fileName, error.getMessage());\n            }\n        }\n\n        return null;\n    }\n\n    @Nullable\n    private static CommentedConfiguration loadMenuFile(File file, String fileName, boolean customMenu,\n                                                       @Nullable IMenuConverter converter) {\n        if (!file.exists() && !customMenu)\n            Resources.saveResource(\"menus/\" + fileName);\n\n        CommentedConfiguration cfg = new CommentedConfiguration();\n\n        try {\n            cfg.load(file);\n        } catch (InvalidConfigurationException error) {\n            Log.errorFromFile(error, fileName, \"There is an issue with the format of the file:\");\n            return null;\n        } catch (IOException error) {\n            Log.errorFromFile(error, fileName, \"An unexpected error occurred while parsing file:\");\n            return null;\n        }\n\n        if (converter != null && converter.convert(plugin, cfg)) {\n            try {\n                cfg.save(file);\n            } catch (Exception error) {\n                Log.errorFromFile(error, fileName, \"An unexpected error occurred while saving file:\");\n            }\n        }\n\n        return cfg;\n    }\n\n    private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSection section) throws MenuParseException {\n        if (section == null)\n            return null;\n\n        TemplateItem templateItem;\n\n        String sourceItem = section.getString(\"source\");\n        if (sourceItem != null) {\n            templateItem = getItemStackUnsafe(fileName, section.getRoot().getConfigurationSection(sourceItem));\n        } else {\n            if (!section.isString(\"type\"))\n                return null;\n\n            Material type;\n            short data;\n\n            try {\n                String materialType = section.getString(\"type\");\n                materialType = MinecraftNamesMapper.getMinecraftName(materialType)\n                        .map(minecraftKey -> NAMES_MAPPER.get().getMappedName(Material.class, minecraftKey).orElse(minecraftKey))\n                        .orElse(materialType);\n                if (materialType.contains(\":\")) {\n                    String[] materialSections = materialType.toUpperCase(Locale.ENGLISH).split(\":\");\n                    if (materialSections.length < 2)\n                        throw new IllegalArgumentException();\n                    type = Material.valueOf(materialSections[0]);\n                    data = Short.parseShort(materialSections[1]);\n                } else {\n                    type = Material.valueOf(materialType.toUpperCase(Locale.ENGLISH));\n                    data = (short) section.getInt(\"data\");\n                }\n            } catch (IllegalArgumentException error) {\n                throw new MenuParseException(\"Couldn't convert \" + section.getCurrentPath() + \" into an item stack. Check type & data sections!\");\n            }\n\n            templateItem = new TemplateItem(new ItemBuilder(type, data));\n        }\n\n        ItemBuilder itemBuilder = templateItem.getEditableBuilder();\n\n        if (section.isString(\"name\"))\n            itemBuilder.withName(Formatters.COLOR_FORMATTER.format(section.getString(\"name\")));\n\n        if (section.isList(\"lore\"))\n            itemBuilder.withLore(section.getStringList(\"lore\"));\n\n        if (section.isInt(\"amount\"))\n            itemBuilder.withAmount(section.getInt(\"amount\"));\n\n        if (section.isConfigurationSection(\"enchants\")) {\n            for (String enchantmentName : section.getConfigurationSection(\"enchants\").getKeys(false)) {\n                Enchantment enchantment;\n\n                try {\n                    enchantment = getMinecraftEnum(Enchantment.class, enchantmentName, Enchantment::getByName);\n                } catch (IllegalArgumentException ex) {\n                    Log.warnFromFile(fileName, \"Couldn't convert \", section.getCurrentPath(),\n                            \".enchants.\", enchantmentName.toUpperCase(Locale.ENGLISH), \" into an enchantment, skipping...\");\n                    continue;\n                }\n\n                itemBuilder.withEnchant(enchantment, section.getInt(\"enchants.\" + enchantmentName));\n            }\n        }\n\n        if (section.getBoolean(\"glow\", false)) {\n            itemBuilder.makeItemGlow();\n        }\n\n        if (section.isList(\"flags\")) {\n            for (String flag : section.getStringList(\"flags\")) {\n                String flagName = flag.toUpperCase(Locale.ENGLISH);\n                try {\n                    itemBuilder.withFlags(ItemFlag.valueOf(flagName));\n                } catch (IllegalArgumentException error) {\n                    Log.warnFromFile(fileName, \"Couldn't convert \", section.getCurrentPath(),\n                            \" (\", flagName, \") into an item flag, skipping...\");\n                }\n            }\n        }\n\n        if (section.isString(\"skull\")) {\n            itemBuilder.asSkullOf(section.getString(\"skull\"));\n        }\n\n        if (section.getBoolean(\"unbreakable\", false)) {\n            itemBuilder.setUnbreakable();\n        }\n\n        if (section.getBoolean(\"hideTooltip\", false)) {\n            itemBuilder.setHideTooltip();\n        }\n\n        if (section.isConfigurationSection(\"effects\")) {\n            ConfigurationSection effectsSection = section.getConfigurationSection(\"effects\");\n            for (String effectName : effectsSection.getKeys(false)) {\n                PotionEffectType potionEffectType;\n\n                try {\n                    potionEffectType = getMinecraftEnum(PotionEffectType.class, effectName, PotionEffectType::getByName);\n                } catch (IllegalArgumentException error) {\n                    Log.warnFromFile(fileName, \"Couldn't convert \", effectsSection.getCurrentPath(),\n                            \".\", effectName.toUpperCase(Locale.ENGLISH), \" into a potion effect, skipping...\");\n                    continue;\n                }\n\n                int duration = effectsSection.getInt(effectName + \".duration\", -1);\n                int amplifier = effectsSection.getInt(effectName + \".amplifier\", 0);\n\n                if (duration == -1) {\n                    Log.warnFromFile(fileName, \"Potion effect \", effectsSection.getCurrentPath(),\n                            \".\", effectName, \" is missing duration, skipping...\");\n                    continue;\n                }\n\n                itemBuilder.withPotionEffect(new PotionEffect(potionEffectType, duration, amplifier));\n            }\n        }\n\n        if (section.isString(\"entity\")) {\n            String entity = section.getString(\"entity\");\n            try {\n                itemBuilder.withEntityType(getMinecraftEnum(EntityType.class, entity));\n            } catch (IllegalArgumentException ex) {\n                Log.warnFromFile(fileName, \"Couldn't convert \", entity, \" into an entity type, skipping...\");\n            }\n        }\n\n        if (section.isConfigurationSection(\"bannerMeta\")) {\n            for (String dyeColorName : section.getConfigurationSection(\"bannerMeta\").getKeys(false)) {\n                DyeColor dyeColor;\n                PatternType patternType;\n\n                try {\n                    dyeColor = DyeColor.valueOf(dyeColorName.toUpperCase(Locale.ENGLISH));\n                } catch (IllegalArgumentException error) {\n                    Log.warnFromFile(fileName, \"Couldn't convert \", section.getCurrentPath(),\n                            \".bannerMeta.\", dyeColorName.toUpperCase(Locale.ENGLISH), \" into an dye color, skipping...\");\n                    continue;\n                }\n\n                try {\n                    patternType = PatternType.valueOf(section.getString(\"bannerMeta.\" + dyeColorName));\n                } catch (IllegalArgumentException error) {\n                    Log.warnFromFile(fileName, \"Couldn't convert \", section.getCurrentPath(),\n                            \".bannerMeta.\", dyeColorName.toUpperCase(Locale.ENGLISH), \".\",\n                            section.getString(\"bannerMeta.\" + dyeColorName), \" into an pattern type, skipping...\");\n                    continue;\n                }\n\n                itemBuilder.withBannerMeta(dyeColor, patternType);\n            }\n        }\n\n        if (section.isInt(\"customModel\")) {\n            itemBuilder.withCustomModel(section.getInt(\"customModel\"));\n        }\n\n        if (section.isString(\"itemModel\")) {\n            itemBuilder.withItemModel(section.getString(\"itemModel\"));\n        }\n\n        if (section.isString(\"rarity\")) {\n            String rarity = section.getString(\"rarity\");\n\n            try {\n                itemBuilder.withRarity(rarity);\n            } catch (IllegalArgumentException error) {\n                Log.warnFromFile(fileName, \"Couldn't convert \", rarity, \" into a rarity, skipping...\");\n            }\n        }\n\n        if (section.isConfigurationSection(\"trim\")) {\n            String trimMaterial = section.getString(\"trim.material\");\n            String trimPattern = section.getString(\"trim.pattern\");\n\n            if (trimMaterial == null) {\n                Log.warnFromFile(fileName, \"Couldn't find trim material for item with trim pattern, skipping...\");\n            } else if (trimPattern == null) {\n                Log.warnFromFile(fileName, \"Couldn't find trim pattern for item with trim material, skipping...\");\n            } else {\n                try {\n                    itemBuilder.withTrim(trimMaterial, trimPattern);\n                } catch (IllegalArgumentException error) {\n                    Log.warnFromFile(fileName, error.getMessage());\n                }\n            }\n        }\n\n        if (section.isString(\"leatherColor\")) {\n            String leatherColor = section.getString(\"leatherColor\");\n            if (leatherColor.startsWith(\"#\"))\n                leatherColor = leatherColor.substring(1);\n\n            try {\n                itemBuilder.withLeatherColor(Integer.parseInt(leatherColor, 16));\n            } catch (IllegalArgumentException error) {\n                Log.warnFromFile(fileName, \"Couldn't convert \", leatherColor, \" into a color, skipping...\");\n            }\n        }\n\n        return templateItem;\n    }\n\n    public List<Integer> parseButtonSlots(ConfigurationSection section, String key, MenuPatternSlots menuPatternSlots) {\n        return !section.isString(key) ? Collections.emptyList() : menuPatternSlots.getSlots(section.getString(key));\n    }\n\n    private static <T> T getMinecraftEnum(Class<T> type, String name) throws IllegalArgumentException {\n        return getMinecraftEnum(type, name, mappedName -> EnumHelper.getEnum(type, mappedName));\n    }\n\n    private static <T> T getMinecraftEnum(Class<T> type, String name, Function<String, T> enumCreator) throws IllegalArgumentException {\n        String mappedName = MinecraftNamesMapper.getMinecraftName(name)\n                .map(minecraftKey -> NAMES_MAPPER.get().getMappedName(type, minecraftKey).orElse(minecraftKey))\n                .orElse(name);\n\n        return Optional.ofNullable(enumCreator.apply(mappedName.toUpperCase(Locale.ENGLISH)))\n                .orElseThrow(() -> new IllegalArgumentException(\"No enum constant \" + type.getCanonicalName() + \".\" + name));\n    }\n\n    public interface IMenuConverter {\n\n        boolean convert(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/Resources.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.io.File;\nimport java.io.InputStream;\n\npublic class Resources {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private Resources() {\n\n    }\n\n    public static void copyResource(String resourcePath) {\n        String fixedPath = resourcePath + \".jar\";\n        File dstFile = new File(plugin.getDataFolder(), fixedPath);\n\n        if (dstFile.exists())\n            //noinspection ResultOfMethodCallIgnored\n            dstFile.delete();\n\n        plugin.saveResource(resourcePath, true);\n\n        File file = new File(plugin.getDataFolder(), resourcePath);\n        //noinspection ResultOfMethodCallIgnored\n        file.renameTo(dstFile);\n    }\n\n    public static void saveResource(String resourcePath) {\n        saveResource(resourcePath, resourcePath);\n    }\n\n    public static void saveResource(String destination, String resourcePath) {\n        try {\n            for (ServerVersion serverVersion : ServerVersion.getByOrder()) {\n                String version = serverVersion.name().substring(1);\n                if (resourcePath.endsWith(\".yml\") && plugin.getResource(resourcePath.replace(\".yml\", version + \".yml\")) != null) {\n                    resourcePath = resourcePath.replace(\".yml\", version + \".yml\");\n                    break;\n                } else if (resourcePath.endsWith(\".schematic\") && plugin.getResource(resourcePath.replace(\".schematic\", version + \".schematic\")) != null) {\n                    resourcePath = resourcePath.replace(\".schematic\", version + \".schematic\");\n                    break;\n                }\n            }\n\n            File file = new File(plugin.getDataFolder(), resourcePath);\n            plugin.saveResource(resourcePath, true);\n\n            if (!destination.equals(resourcePath)) {\n                File dest = new File(plugin.getDataFolder(), destination);\n                //noinspection ResultOfMethodCallIgnored\n                file.renameTo(dest);\n            }\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", destination, resourcePath);\n            Log.error(error, \"An unexpected error occurred while saving resource:\");\n        }\n    }\n\n    public static InputStream getResource(String resourcePath) {\n        String[] suffixAndPath = getPathAndSuffix(resourcePath);\n        String resourcePathNoSuffix = suffixAndPath[0];\n        String suffix = suffixAndPath[1];\n\n        try {\n            for (ServerVersion serverVersion : ServerVersion.getByOrder()) {\n                String version = serverVersion.name().substring(1);\n\n                String realPath = resourcePathNoSuffix + version + suffix;\n\n                try (InputStream resource = plugin.getResource(realPath)) {\n                    if (resource != null) {\n                        resourcePath = realPath;\n                        break;\n                    }\n                }\n            }\n\n            return plugin.getResource(resourcePath);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", resourcePath);\n            Log.error(error, \"An unexpected error occurred while retrieving resource:\");\n            return null;\n        }\n    }\n\n    private static String[] getPathAndSuffix(String name) {\n        int lastIndex = name.lastIndexOf('.');\n        String suffix = lastIndex == -1 || lastIndex + 1 >= name.length() ? \"\" : name.substring(lastIndex + 1);\n        return suffix.isEmpty() ? new String[]{name, \"\"} : new String[]{name.substring(0, name.length() - suffix.length()), suffix};\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/ZipFiles.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\npublic class ZipFiles {\n\n    private ZipFiles() {\n\n    }\n\n    public static void zipFolder(File input, File output) throws IOException {\n        if (!input.isDirectory())\n            throw new IOException(\"Input file must be a directory.\");\n\n        try (ZipOutputStream outputStream = new ZipOutputStream(Files.newOutputStream(output.toPath()))) {\n            zipFolderInternal(input, \"\", outputStream);\n        }\n    }\n\n    public static void zipFile(File input, File output) throws IOException {\n        if (input.isDirectory())\n            throw new IOException(\"Input file must be a file.\");\n\n        try (ZipOutputStream outputStream = new ZipOutputStream(Files.newOutputStream(output.toPath()))) {\n            zipFileInternal(input, input.getName(), outputStream);\n        }\n    }\n\n    private static void zipFolderInternal(File input, String parent, ZipOutputStream outputStream) throws IOException {\n        // Add the folder as an entry\n        String folderPath = parent + input.getName() + File.separator;\n        ZipEntry zipEntry = new ZipEntry(folderPath);\n        outputStream.putNextEntry(zipEntry);\n        outputStream.closeEntry();\n\n        for (File innerFile : input.listFiles()) {\n            if (innerFile.isDirectory()) {\n                zipFolderInternal(innerFile, folderPath, outputStream);\n            } else {\n                zipFileInternal(innerFile, folderPath + innerFile.getName(), outputStream);\n            }\n        }\n    }\n\n    private static void zipFileInternal(File input, String zipEntryName, ZipOutputStream outputStream) throws IOException {\n        ZipEntry zipEntry = new ZipEntry(zipEntryName);\n        try {\n            outputStream.putNextEntry(zipEntry);\n            Files.copy(input.toPath(), outputStream);\n        } finally {\n            outputStream.closeEntry();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/DefaultFilesLookupProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io.loader;\n\nimport java.io.File;\n\npublic class DefaultFilesLookupProvider implements FilesLookupProvider {\n\n    private static final DefaultFilesLookupProvider INSTANCE = new DefaultFilesLookupProvider();\n\n    public static DefaultFilesLookupProvider getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultFilesLookupProvider() {\n\n    }\n\n    @Override\n    public FilesLookup createFilesLookup(File folder) {\n        return new DefaultFilesLookup(folder);\n    }\n\n    private static class DefaultFilesLookup implements FilesLookup {\n\n        private final File folder;\n\n        DefaultFilesLookup(File folder) {\n            this.folder = folder;\n        }\n\n        @Override\n        public File getFile(String name) {\n            return new File(this.folder, name);\n        }\n\n        @Override\n        public void close() {\n            // Do nothing\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookup.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io.loader;\n\nimport java.io.File;\n\npublic interface FilesLookup extends AutoCloseable {\n\n    File getFile(String name);\n\n    @Override\n    void close();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookupFactory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io.loader;\n\nimport java.io.File;\n\npublic class FilesLookupFactory {\n\n    private static final FilesLookupFactory INSTANCE = new FilesLookupFactory();\n\n    public static FilesLookupFactory getInstance() {\n        return INSTANCE;\n    }\n\n    private FilesLookupProvider filesLookupProvider = findSuitableFilesLookupProvider();\n\n    private FilesLookupFactory() {\n\n    }\n\n    public void setProvider(FilesLookupProvider filesLookupProvider) {\n        this.filesLookupProvider = filesLookupProvider;\n    }\n\n    public FilesLookup lookupFolder(File folder) {\n        try {\n            return this.filesLookupProvider.createFilesLookup(folder);\n        } catch (IllegalStateException error) {\n            if (this.filesLookupProvider == DefaultFilesLookupProvider.getInstance())\n                throw error;\n\n            this.filesLookupProvider = DefaultFilesLookupProvider.getInstance();\n            return lookupFolder(folder);\n        }\n    }\n\n    private static FilesLookupProvider findSuitableFilesLookupProvider() {\n        try {\n            Class.forName(\"io.papermc.paper.pluginremap.PluginRemapper\");\n            return (FilesLookupProvider) Class.forName(\n                            \"com.bgsoftware.superiorskyblock.external.remapper.PluginRemapperFilesLookupProvider\")\n                    .newInstance();\n        } catch (Throwable ignored) {\n        }\n\n        return DefaultFilesLookupProvider.getInstance();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookupProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.core.io.loader;\n\nimport java.io.File;\n\npublic interface FilesLookupProvider {\n\n    FilesLookup createFilesLookup(File folder) throws IllegalStateException;\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java",
    "content": "package com.bgsoftware.superiorskyblock.core.itemstack;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Color;\nimport org.bukkit.DyeColor;\nimport org.bukkit.Material;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.block.banner.Pattern;\nimport org.bukkit.block.banner.PatternType;\nimport org.bukkit.enchantments.Enchantment;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemFlag;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.BannerMeta;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.LeatherArmorMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.inventory.meta.SpawnEggMeta;\nimport org.bukkit.potion.PotionEffect;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class ItemBuilder {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private ItemStack itemStack;\n    @Nullable\n    private ItemMeta itemMeta;\n    private String textureValue = \"\";\n\n    public ItemBuilder(ItemStack itemStack) {\n        this(itemStack.getType(), itemStack.getDurability());\n        this.itemMeta = itemStack.getItemMeta().clone();\n    }\n\n    public ItemBuilder(Material type) {\n        this(type, 0);\n    }\n\n    public ItemBuilder(Material type, int damage) {\n        itemStack = new ItemStack(type, 1, (short) damage);\n        itemMeta = itemStack.getItemMeta();\n    }\n\n    public ItemBuilder withType(Material type) {\n        this.itemStack.setType(type);\n        return this;\n    }\n\n    public ItemBuilder withDurablity(short durability) {\n        if (durability >= 0)\n            this.itemStack.setDurability(durability);\n        return this;\n    }\n\n    public ItemBuilder withAmount(int amount) {\n        if (amount >= 1 && amount <= itemStack.getMaxStackSize())\n            itemStack.setAmount(amount);\n        return this;\n    }\n\n    public ItemBuilder asSkullOf(SuperiorPlayer superiorPlayer) {\n        if (itemStack.getType() == Materials.PLAYER_HEAD.toBukkitType())\n            textureValue = superiorPlayer == null ? ItemSkulls.getNullPlayerTexture() : superiorPlayer.getTextureValue();\n        return this;\n    }\n\n    public ItemBuilder asSkullOf(String textureValue) {\n        if (itemStack.getType() == Materials.PLAYER_HEAD.toBukkitType())\n            this.textureValue = ItemSkulls.parseTexture(textureValue);\n        return this;\n    }\n\n    public ItemBuilder withName(String name) {\n        if (itemMeta != null && name != null)\n            itemMeta.setDisplayName(Formatters.COLOR_FORMATTER.format(name));\n        return this;\n    }\n\n    public ItemBuilder replaceName(String regex, String replace) {\n        if (itemMeta != null && itemMeta.hasDisplayName())\n            withName(itemMeta.getDisplayName().replace(regex, replace));\n        return this;\n    }\n\n    public ItemBuilder withLore(List<String> lore) {\n        if (itemMeta != null && lore != null)\n            itemMeta.setLore(new SequentialListBuilder<String>()\n                    .build(lore, Formatters.COLOR_FORMATTER::format));\n        return this;\n    }\n\n    public ItemBuilder appendLore(List<String> lore) {\n        if (itemMeta == null || itemMeta.getLore() == null) {\n            return withLore(lore);\n        } else {\n            List<String> currentLore = itemMeta.getLore();\n            currentLore.addAll(lore);\n            return withLore(currentLore);\n        }\n    }\n\n    public ItemBuilder withLore(String... lore) {\n        return withLore(Arrays.asList(lore));\n    }\n\n    public ItemBuilder withLore(String firstLine, List<String> listLine) {\n        if (itemMeta == null)\n            return this;\n\n        List<String> loreList = new LinkedList<>();\n\n        firstLine = Formatters.COLOR_FORMATTER.format(firstLine);\n        loreList.add(firstLine);\n\n        for (String line : listLine)\n            loreList.add(ChatColor.getLastColors(firstLine) + Formatters.COLOR_FORMATTER.format(line));\n\n        if (loreList.size() > 10) {\n            for (int i = 10; i < loreList.size(); i++) {\n                loreList.remove(loreList.get(i));\n            }\n            loreList.add(ChatColor.getLastColors(firstLine) + \"...\");\n        }\n\n        itemMeta.setLore(loreList);\n        return this;\n    }\n\n    public ItemBuilder replaceLore(String regex, String replace) {\n        if (itemMeta == null || !itemMeta.hasLore())\n            return this;\n\n        List<String> loreList = new ArrayList<>(itemMeta.getLore().size());\n\n        for (String line : itemMeta.getLore()) {\n            loreList.add(line.replace(regex, replace));\n        }\n\n        withLore(loreList);\n        return this;\n    }\n\n    public ItemBuilder replaceLoreWithLines(String regex, String... lines) {\n        if (itemMeta == null || !itemMeta.hasLore())\n            return this;\n\n        List<String> currentLore = itemMeta.getLore();\n\n        List<String> loreList = new ArrayList<>(currentLore.size());\n        List<String> linesToAdd = Arrays.asList(lines);\n        boolean isEmpty = linesToAdd.isEmpty() || linesToAdd.stream().allMatch(String::isEmpty);\n\n        for (String line : currentLore) {\n            if (line.contains(regex)) {\n                if (!isEmpty)\n                    loreList.addAll(linesToAdd);\n            } else {\n                loreList.add(line);\n            }\n        }\n\n        withLore(loreList);\n        return this;\n    }\n\n    public ItemBuilder replaceAll(String regex, String replace) {\n        replaceName(regex, replace);\n        replaceLore(regex, replace);\n        return this;\n    }\n\n    public ItemBuilder withEnchant(Enchantment enchant, int level) {\n        if (itemMeta != null)\n            itemMeta.addEnchant(enchant, level, true);\n        return this;\n    }\n\n    public ItemBuilder makeItemGlow() {\n        plugin.getNMSAlgorithms().makeItemGlow(itemMeta);\n        return this;\n    }\n\n    public ItemBuilder withFlags(ItemFlag... itemFlags) {\n        if (itemMeta != null) {\n            itemMeta.addItemFlags(itemFlags);\n            for (ItemFlag itemFlag : itemFlags) {\n                if (itemFlag == ItemFlag.HIDE_ATTRIBUTES) {\n                    plugin.getNMSAlgorithms().hideAttributes(itemMeta);\n                    break;\n                }\n            }\n        }\n        return this;\n    }\n\n    public ItemBuilder setUnbreakable() {\n        if (itemMeta != null)\n            itemMeta.spigot().setUnbreakable(true);\n        return this;\n    }\n\n    public ItemBuilder setHideTooltip() {\n        if (itemMeta != null)\n            plugin.getNMSAlgorithms().setHideTooltip(itemMeta);\n        return this;\n    }\n\n    public ItemBuilder withPotionEffect(PotionEffect potionEffect) {\n        if (itemMeta instanceof PotionMeta)\n            plugin.getNMSAlgorithms().addPotion((PotionMeta) itemMeta, potionEffect);\n        return this;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public ItemBuilder withEntityType(EntityType entityType) {\n        if (itemMeta == null)\n            return this;\n\n        if (BukkitItems.isValidAndSpawnEgg(itemStack)) {\n            if (ServerVersion.isLegacy()) {\n                try {\n                    ((SpawnEggMeta) itemMeta).setSpawnedType(entityType);\n                } catch (NoClassDefFoundError error) {\n                    itemStack.setDurability(entityType.getTypeId());\n                }\n            } else {\n                itemStack.setType(Material.valueOf(entityType.name() + \"_SPAWN_EGG\"));\n            }\n        }\n\n        return this;\n    }\n\n    public ItemBuilder withBannerMeta(DyeColor dyeColor, PatternType patternType) {\n        if (itemMeta instanceof BannerMeta) {\n            BannerMeta bannerMeta = (BannerMeta) itemMeta;\n            bannerMeta.addPattern(new Pattern(dyeColor, patternType));\n        }\n        return this;\n    }\n\n    public ItemBuilder withCustomModel(int customModel) {\n        plugin.getNMSAlgorithms().setCustomModel(itemMeta, customModel);\n        return this;\n    }\n\n    public ItemBuilder withItemModel(String itemModel) {\n        plugin.getNMSAlgorithms().setItemModel(itemMeta, itemModel);\n        return this;\n    }\n\n    public ItemBuilder withRarity(String rarity) {\n        plugin.getNMSAlgorithms().setRarity(itemMeta, rarity.toUpperCase(Locale.ENGLISH));\n        return this;\n    }\n\n    public ItemBuilder withTrim(String trimMaterial, String trimPattern) {\n        plugin.getNMSAlgorithms().setTrim(itemMeta, trimMaterial.toLowerCase(Locale.ENGLISH), trimPattern.toLowerCase(Locale.ENGLISH));\n        return this;\n    }\n\n    public ItemBuilder withLeatherColor(int leatherColor) {\n        if (itemMeta instanceof LeatherArmorMeta) {\n            LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemMeta;\n            leatherArmorMeta.setColor(Color.fromRGB(leatherColor));\n        }\n        return this;\n    }\n\n    @Nullable\n    public ItemMeta getItemMeta() {\n        return itemMeta;\n    }\n\n    public ItemStack build(SuperiorPlayer superiorPlayer) {\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n\n        if (itemMeta != null) {\n            if (itemMeta.hasDisplayName()) {\n                withName(placeholdersService.get().parsePlaceholders(offlinePlayer, itemMeta.getDisplayName()));\n            }\n\n            if (itemMeta.hasLore()) {\n                withLore(new SequentialListBuilder<String>()\n                        .build(itemMeta.getLore(), line -> placeholdersService.get().parsePlaceholders(offlinePlayer, line)));\n            }\n        }\n\n        if (textureValue.equals(\"%superior_player_texture%\"))\n            textureValue = superiorPlayer.getTextureValue();\n\n        return build();\n    }\n\n    public ItemStack build() {\n        itemStack.setItemMeta(itemMeta);\n        return textureValue.isEmpty() ? itemStack : ItemSkulls.getPlayerHead(itemStack, textureValue);\n    }\n\n    public ItemBuilder copy() {\n        ItemBuilder itemBuilder = new ItemBuilder(Material.AIR);\n        itemBuilder.itemStack = itemStack.clone();\n        if (itemMeta != null)\n            itemBuilder.itemMeta = itemMeta.clone();\n        itemBuilder.textureValue = textureValue;\n        return itemBuilder;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java",
    "content": "package com.bgsoftware.superiorskyblock.core.itemstack;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.io.Resources;\nimport com.bgsoftware.superiorskyblock.core.itemstack.heads.MinecraftHeadsClient;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.IntArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\n@SuppressWarnings(\"WeakerAccess\")\npublic class ItemSkulls {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final String NULL_PLAYER_TEXTURE = \"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19\";\n    private static final Map<String, String> entitySkullTextures = new HashMap<>();\n    private static final LazyReference<MinecraftHeadsClient> minecraftHeadsClient = new LazyReference<MinecraftHeadsClient>() {\n        @Override\n        protected MinecraftHeadsClient create() {\n            return new MinecraftHeadsClient();\n        }\n    };\n\n    private ItemSkulls() {\n\n    }\n\n    public static void readTextures(SuperiorSkyblockPlugin plugin) {\n        entitySkullTextures.clear();\n\n        File file = new File(plugin.getDataFolder(), \"heads.yml\");\n\n        if (!file.exists())\n            Resources.saveResource(\"heads.yml\");\n\n        CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file);\n\n        try {\n            cfg.syncWithConfig(file, Resources.getResource(\"heads.yml\"));\n        } catch (Exception error) {\n            Log.entering(\"ENTER\");\n            Log.error(error, \"An unexpected error occurred while syncing heads file:\");\n        }\n\n        for (String entityType : cfg.getConfigurationSection(\"\").getKeys(false))\n            entitySkullTextures.put(entityType, parseTexture(cfg.getString(entityType)));\n    }\n\n    public static ItemStack getPlayerHead(ItemStack itemStack, String texture) {\n        return plugin.getNMSTags().getSkullWithTexture(itemStack, texture);\n    }\n\n    public static ItemStack getPlayerHeadNoNMS(ItemStack itemStack, String texture) {\n        CompoundTag compoundTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack);\n\n        CompoundTag tagCompound = compoundTag.getCompound(\"tag\").orElseGet(CompoundTag::of);\n\n        CompoundTag skullOwner = tagCompound.getCompound(\"SkullOwner\").orElseGet(CompoundTag::of);\n\n        UUID ownerUUID = new UUID(texture.hashCode(), texture.hashCode());\n\n        if (ServerVersion.isAtLeast(ServerVersion.v1_16)) {\n            skullOwner.setTag(\"Id\", IntArrayTag.fromUUID(ownerUUID));\n        } else {\n            skullOwner.setString(\"Id\", ownerUUID.toString());\n        }\n\n        CompoundTag properties = CompoundTag.of();\n\n        ListTag textures = ListTag.of(CompoundTag.class);\n        CompoundTag signature = CompoundTag.of();\n        signature.setString(\"Value\", texture);\n        textures.addTag(signature);\n\n        properties.setTag(\"textures\", textures);\n\n        skullOwner.setTag(\"Properties\", properties);\n\n        tagCompound.setTag(\"SkullOwner\", skullOwner);\n\n        compoundTag.setTag(\"nbt\", tagCompound);\n\n        return Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(compoundTag);\n    }\n\n    public static String getNullPlayerTexture() {\n        return NULL_PLAYER_TEXTURE;\n    }\n\n    public static String getTexture(String entityType) {\n        return entitySkullTextures.getOrDefault(entityType, \"\");\n    }\n\n    public static String parseTexture(String texture) {\n        return MinecraftHeadsClient.getMinecraftHeadsTextureId(texture)\n                .map(textureId -> minecraftHeadsClient.get().getTexture(textureId))\n                .orElse(texture);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/MinecraftNamesMapper.java",
    "content": "package com.bgsoftware.superiorskyblock.core.itemstack;\n\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonObject;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MinecraftNamesMapper {\n\n    private static final Pattern MINECRAFT_KEY_PATTERN = Pattern.compile(\"minecraft:(.+)\");\n    private static final String MINECRAFT_NAMES_MAPPING_URL = \"https://bg-software.com/minecraft_mappings.json\";\n    private static final String MINECRAFT_NAMES_MAPPING_LEGACY_URL = \"https://bg-software.com/minecraft_mappings_legacy.json\";\n    private static final Gson GSON = new Gson();\n\n    public static Optional<String> getMinecraftName(String name) {\n        Matcher matcher = MINECRAFT_KEY_PATTERN.matcher(name);\n        return matcher.matches() ? Optional.of(matcher.group(1).toLowerCase(Locale.ENGLISH)) : Optional.empty();\n    }\n\n    private final Map<Class<?>, Map<String, String>> enumNamesMapping;\n\n    public MinecraftNamesMapper() {\n        this.enumNamesMapping = fetchEnumNamesMapping();\n    }\n\n    public Optional<String> getMappedName(Class<?> expectedEnumClass, String name) {\n        return Optional.ofNullable(enumNamesMapping.get(expectedEnumClass))\n                .map(mappings -> mappings.get(name));\n    }\n\n    private static Map<Class<?>, Map<String, String>> fetchEnumNamesMapping() {\n        Map<Class<?>, Map<String, String>> mappedNames = new ArrayMap<>();\n\n        try {\n            HttpsURLConnection connection = (HttpsURLConnection) new URL(ServerVersion.isLegacy() ?\n                    MINECRAFT_NAMES_MAPPING_LEGACY_URL : MINECRAFT_NAMES_MAPPING_URL).openConnection();\n\n            connection.setRequestMethod(\"GET\");\n            connection.setRequestProperty(\"User-Agent\", \"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB;     rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)\");\n            connection.setDoInput(true);\n\n            try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) {\n                JsonElement mappingsElement = GSON.fromJson(reader, JsonElement.class);\n                if (!mappingsElement.isJsonArray())\n                    throw new MappingFormatException(\"Expected to receive json array, received \" + mappingsElement.getClass());\n\n                JsonArray mappings = mappingsElement.getAsJsonArray();\n\n                for (JsonElement classMappingElement : mappings) {\n                    if (!classMappingElement.isJsonObject())\n                        continue;\n\n                    JsonObject classMapping = classMappingElement.getAsJsonObject();\n                    String className = ensureFieldExists(classMapping, \"type\").getAsString();\n                    Class<?> clazz;\n\n                    try {\n                        clazz = Class.forName(className);\n                    } catch (ClassNotFoundException error) {\n                        throw new MappingFormatException(\"Invalid class name: \" + className);\n                    }\n\n                    Map<String, String> classMappings = new HashMap<>();\n\n                    JsonElement jsonMappingsElement = ensureFieldExists(classMapping, \"mappings\");\n                    if (!jsonMappingsElement.isJsonObject())\n                        throw new MappingFormatException(\"Mapping for class '\" + className + \"' is not an object\");\n\n                    JsonObject jsonMappings = jsonMappingsElement.getAsJsonObject();\n                    jsonMappings.entrySet().forEach(entry -> {\n                        if (!entry.getValue().isJsonPrimitive()) {\n                            Log.warn(\"Mapping entry is not string: \" + entry.getKey() + \", skipping...\");\n                            return;\n                        }\n                        classMappings.put(entry.getKey(), entry.getValue().getAsString());\n                    });\n\n                    if (!classMappings.isEmpty())\n                        mappedNames.put(clazz, classMappings);\n                }\n\n            }\n\n        } catch (Exception error) {\n            Log.error(error, \"Failed to fetch minecraft names mapper:\");\n        }\n\n        return mappedNames.isEmpty() ? Collections.emptyMap() : mappedNames;\n    }\n\n    private static JsonElement ensureFieldExists(JsonObject object, String fieldName) throws MappingFormatException {\n        JsonElement value = object.get(fieldName);\n        if (value != null)\n            return value;\n        throw new MappingFormatException(\"Missing field: \" + fieldName);\n    }\n\n    private static class MappingFormatException extends IllegalArgumentException {\n\n        MappingFormatException(String message) {\n            super(message);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/heads/MinecraftHeadsClient.java",
    "content": "package com.bgsoftware.superiorskyblock.core.itemstack.heads;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.DynamicArray;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MinecraftHeadsClient {\n\n    private static final Pattern MINECRAFT_HEADS_PATTERN = Pattern.compile(\"minecraft-heads:(\\\\d+)\");\n    private static final int EXPECTED_HEADS_SIZE = 50_000;\n    private static final String MINECRAFT_HEADS_DATABASE_URL = \"https://minecraft-heads.com/csv/2020-01-31-IUgRbJoHRbVhjKnOlkmH/Custom-Head-DB.csv\";\n\n    public static Optional<Integer> getMinecraftHeadsTextureId(String texture) {\n        Matcher matcher = MINECRAFT_HEADS_PATTERN.matcher(texture);\n        return matcher.matches() ? Optional.of(Integer.parseInt(matcher.group(1))) : Optional.empty();\n    }\n\n    private final List<String> cachedHeads;\n\n    public MinecraftHeadsClient() {\n        this.cachedHeads = fetchHeadsDatabase();\n    }\n\n    @Nullable\n    public String getTexture(int id) {\n        int index = id - 1;\n        return index < cachedHeads.size() ? cachedHeads.get(index) : null;\n    }\n\n    private static List<String> fetchHeadsDatabase() {\n        DynamicArray<String> heads = new DynamicArray<>(EXPECTED_HEADS_SIZE);\n        boolean addedAnyHead = false;\n\n        try {\n            URLConnection connection = new URL(MINECRAFT_HEADS_DATABASE_URL).openConnection();\n            try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {\n                String texture;\n                while ((texture = reader.readLine()) != null) {\n                    String[] textureSegments = texture.split(\";\");\n                    if (textureSegments.length >= 4) {\n                        int id;\n                        try {\n                            id = Integer.parseInt(textureSegments[1]);\n                        } catch (NumberFormatException ignored) {\n                            continue;\n                        }\n                        String textureValue = textureSegments[3];\n                        String textureUrl = \"{\\\"textures\\\":{\\\"SKIN\\\":{\\\"url\\\":\\\"http://textures.minecraft.net/texture/\" + textureValue + \"\\\"}}}\";\n                        heads.set(id - 1, Base64.getEncoder().encodeToString(textureUrl.getBytes(StandardCharsets.UTF_8)));\n                        addedAnyHead = true;\n                    }\n                }\n            }\n        } catch (Exception error) {\n            Log.error(error, \"Failed to obtain heads from minecraft-heads:\");\n        }\n\n        return addedAnyHead ? heads.toList() : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\n\npublic abstract class BaseKey<T extends Key> implements Key {\n\n    protected final LazyReference<String> toStringCache = new LazyReference<String>() {\n        @Override\n        protected String create() {\n            return toStringInternal();\n        }\n    };\n    protected final LazyReference<Integer> hashCodeCache = new LazyReference<Integer>() {\n        @Override\n        protected Integer create() {\n            return hashCodeInternal();\n        }\n    };\n\n    private final Class<T> baseKeyClass;\n    private final boolean apiKey;\n\n    protected BaseKey(Class<T> baseKeyClass, boolean apiKey) {\n        this.baseKeyClass = baseKeyClass;\n        this.apiKey = apiKey;\n    }\n\n    @Override\n    public abstract String getGlobalKey();\n\n    public abstract T toGlobalKey();\n\n    @Override\n    public abstract String getSubKey();\n\n    protected abstract String toStringInternal();\n\n    protected abstract int hashCodeInternal();\n\n    protected abstract boolean equalsInternal(T other);\n\n    protected abstract int compareToInternal(T other);\n\n    public abstract T createAPIKeyInternal();\n\n    public final T markAPIKey() {\n        if (this.apiKey)\n            return (T) this;\n\n        return createAPIKeyInternal();\n    }\n\n    public boolean isAPIKey() {\n        return this.apiKey;\n    }\n\n    @Override\n    public final String toString() {\n        return this.toStringCache.get();\n    }\n\n    @Override\n    public final int hashCode() {\n        return this.hashCodeCache.get();\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n        if (this == o)\n            return true;\n\n        if (o == null)\n            return false;\n\n        if (getClass() != o.getClass()) {\n            if (o instanceof LazyKey) {\n                LazyKey<T> lazyKey = (LazyKey<T>) o;\n                return this.equalsInternal(lazyKey.getBaseKey());\n            }\n\n            if (!this.baseKeyClass.isAssignableFrom(o.getClass()))\n                return false;\n        }\n\n        return this.equalsInternal((T) o);\n    }\n\n    @Override\n    public final int compareTo(@NotNull Key o) {\n        if (this == o)\n            return 0;\n\n        if (getClass() != o.getClass()) {\n            if (o instanceof LazyKey) {\n                LazyKey<T> lazyKey = (LazyKey<T>) o;\n                return this.compareToInternal(lazyKey.getBaseKey());\n            }\n\n            if (!this.baseKeyClass.isAssignableFrom(o.getClass()))\n                return toString().compareTo(o.toString());\n        }\n\n        return this.compareToInternal((T) o);\n    }\n\n    protected final void loadLazyCaches() {\n        toStringCache.get();\n        hashCodeCache.get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.Optional;\n\npublic class ConstantKeys {\n\n    public static final Key AIR = Keys.of(Material.AIR);\n    @Nullable\n    public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, \"BASALT\"))\n            .map(Keys::of).orElse(null);\n    public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, \"CARVED_PUMPKIN\", \"PUMPKIN\"));\n    public static final Key CAULDRON = Keys.of(Material.CAULDRON);\n    public static final Key CHEST = Keys.of(Material.CHEST);\n    @Nullable\n    public static final Key CHORUS_PLANT = Optional.ofNullable(EnumHelper.getEnum(Material.class, \"CHORUS_PLANT\"))\n            .map(Keys::of).orElse(null);\n    @Nullable\n    public static final Key CLOSED_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, \"CLOSED_EYEBLOSSOM\"))\n            .map(Keys::of).orElse(null);\n    public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE);\n    public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, \"COMMAND_BLOCK\", \"COMMAND\"));\n    public static final Key EGG_MOB_SPAWNER = Keys.ofSpawner(\"EGG\");\n    public static final Key END_PORTAL_FRAME = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType());\n    public static final Key END_PORTAL_FRAME_WITH_EYE = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType(), (short) 7);\n    public static final Key FURNACE = Keys.of(Material.FURNACE);\n    public static final Key HOPPER = Keys.of(Material.HOPPER);\n    @Nullable\n    public static final Key IRON_BLOCK = Keys.of(Material.IRON_BLOCK);\n    public static final Key LAVA = Keys.of(Material.LAVA);\n    public static final Key MOB_SPAWNER = Keys.of(Materials.SPAWNER.toBukkitType());\n    public static final Key OBSIDIAN = Keys.of(Material.OBSIDIAN);\n    @Nullable\n    public static final Key OPEN_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, \"OPEN_EYEBLOSSOM\"))\n            .map(Keys::of).orElse(null);\n    public static final Key SNOW_BLOCK = Keys.of(Material.SNOW_BLOCK);\n    public static final Key SOUL_SAND = Keys.of(Material.SOUL_SAND);\n    @Nullable\n    public static final Key TARGET = Optional.ofNullable(EnumHelper.getEnum(Material.class, \"TARGET\"))\n            .map(Keys::of).orElse(null);\n    public static final Key TNT = Keys.of(Material.TNT);\n    public static final Key WATER = Keys.of(Material.WATER);\n    public static final Key WET_SPONGE = Keys.of(EnumHelper.getEnum(Material.class, \"WET_SPONGE\", \"SPONGE\"));\n    public static final Key WITHER_SKELETON_SKULL = initializeWitherSkeletonSkullKey();\n\n    public static final Key ENTITY_MINECART_COMMAND = Keys.of(EntityType.MINECART_COMMAND);\n    public static final Key ENTITY_MINECART_CHEST = Keys.of(EntityType.MINECART_CHEST);\n    public static final Key ENTITY_MINECART_FURNACE = Keys.of(EntityType.MINECART_FURNACE);\n    public static final Key ENTITY_MINECART_TNT = Keys.of(EntityType.MINECART_TNT);\n    public static final Key ENTITY_MINECART_HOPPER = Keys.of(EntityType.MINECART_HOPPER);\n    public static final Key ENTITY_MINECART_MOB_SPAWNER = Keys.of(EntityType.MINECART_MOB_SPAWNER);\n\n    private ConstantKeys() {\n\n    }\n\n    private static Key initializeWitherSkeletonSkullKey() {\n        Material newSkullMaterial = EnumHelper.getEnum(Material.class, \"WITHER_SKELETON_SKULL\");\n        if (newSkullMaterial != null)\n            return Keys.of(newSkullMaterial);\n\n        return Keys.of(Material.SKULL_ITEM, (byte) 1);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/KeyIndicator.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\npublic enum KeyIndicator {\n\n    MATERIAL,\n    ENTITY_TYPE,\n    CUSTOM\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.key.types.CustomKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.CreatureSpawner;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.regex.Pattern;\n\npublic class Keys {\n\n    public static final Key EMPTY = CustomKey.of(\"\", null, KeyIndicator.CUSTOM);\n\n    private static final Pattern KEY_SPLITTER_PATTERN = Pattern.compile(\"[:;]\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private Keys() {\n\n    }\n\n    /* Entity keys */\n\n    public static Key of(EntityType entityType) {\n        return EntityTypeKey.of(entityType);\n    }\n\n    public static Key ofEntityType(String customType) {\n        try {\n            return EntityTypeKey.of(EntityType.valueOf(customType.toUpperCase(Locale.ENGLISH)));\n        } catch (IllegalArgumentException error) {\n            return CustomKey.of(customType, null, KeyIndicator.ENTITY_TYPE);\n        }\n    }\n\n    public static Key of(Entity entity) {\n        Key baseKey = BukkitEntities.getLimitEntityType(entity);\n        return plugin.getBlockValues().convertKey(baseKey, entity);\n    }\n\n    /* Block keys */\n\n    public static Key of(Block block) {\n        Material blockType = block.getType();\n\n        Key baseKey;\n        if (blockType == Materials.SPAWNER.toBukkitType()) {\n            CreatureSpawner creatureSpawner = (CreatureSpawner) block.getState();\n            baseKey = getSpawnerKeyFromCreatureSpawner(creatureSpawner);\n        } else {\n            short data = plugin.getNMSAlgorithms().getBlockDataValue(block);\n            baseKey = MaterialKey.of(blockType, data, MaterialKeySource.BLOCK);\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return plugin.getBlockValues().convertKey(baseKey, block.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    public static Key of(BlockState blockState) {\n        Key baseKey;\n        if (blockState instanceof CreatureSpawner) {\n            baseKey = getSpawnerKeyFromCreatureSpawner((CreatureSpawner) blockState);\n        } else {\n            short data = plugin.getNMSAlgorithms().getBlockDataValue(blockState);\n            baseKey = MaterialKey.of(blockState.getType(), data, MaterialKeySource.BLOCK);\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return plugin.getBlockValues().convertKey(baseKey, blockState.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    public static Key of(Key baseKey, Location location) {\n        Preconditions.checkArgument(baseKey instanceof MaterialKey);\n        return plugin.getBlockValues().convertKey(baseKey, location);\n    }\n\n    /* Item keys */\n\n    public static Key of(ItemStack itemStack) {\n        Material itemType = itemStack.getType();\n        Key baseKey = (itemType == Materials.SPAWNER.toBukkitType()) ?\n                plugin.getProviders().getSpawnerKey(itemStack) :\n                MaterialKey.of(itemType, itemStack.getDurability(), MaterialKeySource.ITEM);\n        return plugin.getBlockValues().convertKey(baseKey, itemStack);\n    }\n\n    public static Key of(Material type, short data) {\n        if (ServerVersion.isLessThan(ServerVersion.v1_21) || type == Materials.SPAWNER.toBukkitType()) {\n            return of(new ItemStack(type, 1, data));\n        }\n\n        // In 1.21, we cannot set invalid durability for ItemStacks.\n        // Therefore, this code is duplicated from the above method, but\n        // creates the baseKey directly, not from ItemStack.\n        Key baseKey = MaterialKey.of(type, data, MaterialKeySource.ITEM);\n\n        try {\n            // Now we try to convert the key.\n            // This may throw an exception that is handled below.\n            ItemStack itemStack = new ItemStack(type, 1, data);\n            return plugin.getBlockValues().convertKey(baseKey, itemStack);\n        } catch (IllegalArgumentException error) {\n            // In 1.21, you cannot create ItemStack out of Material types that are not an item\n            // If this occurs, we simply return the base key.\n            return baseKey;\n        }\n    }\n\n    public static Key of(Material type) {\n        return type == Materials.SPAWNER.toBukkitType() ? SpawnerKey.GLOBAL_KEY : MaterialKey.of(type);\n    }\n\n    public static Key ofMaterialAndData(String material, @Nullable String data) {\n        try {\n            Material blockType = Material.valueOf(material);\n            if (Text.isBlank(data)) {\n                return Keys.of(blockType);\n            }\n            if (blockType == Materials.SPAWNER.toBukkitType()) {\n                return ofSpawner(data);\n            }\n            short blockData = Short.parseShort(data);\n            return Keys.of(blockType, blockData);\n        } catch (Exception error) {\n            return Keys.of(material, data, KeyIndicator.MATERIAL);\n        }\n    }\n\n    public static Key ofMaterialAndData(String key) {\n        String[] keySections = KEY_SPLITTER_PATTERN.split(key.toUpperCase(Locale.ENGLISH));\n        return ofMaterialAndData(keySections[0], keySections.length >= 2 ? keySections[1] : null);\n    }\n\n    /* Spawner keys */\n\n    public static Key ofSpawner(EntityType entityType) {\n        return SpawnerKey.of(of(entityType));\n    }\n\n    public static Key ofSpawner(EntityType entityType, Location location) {\n        return plugin.getBlockValues().convertKey(ofSpawner(entityType), location);\n    }\n\n    public static Key ofSpawner(String customType) {\n        return SpawnerKey.of(ofEntityType(customType));\n    }\n\n    public static Key ofSpawner(String customType, Location location) {\n        return plugin.getBlockValues().convertKey(ofSpawner(customType), location);\n    }\n\n    /* Custom keys */\n\n    public static Key of(String globalKey, @Nullable String subKey, KeyIndicator keyType) {\n        return CustomKey.of(globalKey, subKey, keyType);\n    }\n\n    public static Key ofCustom(String key) {\n        String[] sections = KEY_SPLITTER_PATTERN.split(key);\n        return of(sections[0], sections.length > 2 ? sections[1] : null, KeyIndicator.CUSTOM);\n    }\n\n    public static <T extends Key> Key of(Class<T> baseKeyClass, LazyReference<T> keyLoader) {\n        return new LazyKey<>(baseKeyClass, keyLoader);\n    }\n\n    private static SpawnerKey getSpawnerKeyFromCreatureSpawner(CreatureSpawner creatureSpawner) {\n        EntityTypeKey entityTypeKey = Optional.ofNullable(creatureSpawner.getSpawnedType())\n                .map(EntityTypeKey::of).orElse(null);\n        return SpawnerKey.of(entityTypeKey);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.KeysManager;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMapStrategy;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySetStrategy;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class KeysManagerImpl extends Manager implements KeysManager {\n\n    public KeysManagerImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadData() {\n        // No data to be loaded.\n    }\n\n    @Override\n    public Key getKey(EntityType entityType) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(entityType)).markAPIKey();\n    }\n\n    @Override\n    public Key getEntityTypeKey(String entityTypeName) {\n        Preconditions.checkNotNull(entityTypeName, \"entityTypeName parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.ofEntityType(entityTypeName)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(Entity entity) {\n        Preconditions.checkNotNull(entity, \"entity parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(entity)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(Block block) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(block)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(BlockState blockState) {\n        Preconditions.checkNotNull(blockState, \"blockState parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(blockState)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"material parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(itemStack)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(Material material, short data) {\n        Preconditions.checkNotNull(material, \"material parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(material, data)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(Material material) {\n        Preconditions.checkNotNull(material, \"material parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(material)).markAPIKey();\n    }\n\n    @Override\n    public Key getMaterialAndDataKey(String type) {\n        Preconditions.checkNotNull(type, \"type parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.ofMaterialAndData(type)).markAPIKey();\n    }\n\n    @Override\n    public Key getSpawnerKey(EntityType entityType) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.ofSpawner(entityType)).markAPIKey();\n    }\n\n    @Override\n    public Key getSpawnerKey(String entityTypeName) {\n        Preconditions.checkNotNull(entityTypeName, \"entityTypeName parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.ofSpawner(entityTypeName)).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(String key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        // Due to backwards compatibility, we want to try and check if this is either a MaterialKey or EntityTypeKey.\n        Key materialKey = Key.ofMaterialAndData(key);\n        if (materialKey instanceof MaterialKey)\n            return materialKey;\n\n        Key entityTypeKey = Key.ofEntityType(key);\n        if (entityTypeKey instanceof EntityTypeKey)\n            return entityTypeKey;\n\n        // This key does not fit MaterialKey nor EntityTypeKey, therefore we'll create a CustomKey.\n\n        String[] keySections = key.split(\":\");\n        Key customKey = Keys.of(keySections[0], keySections.length >= 2 ? keySections[1] : null, KeyIndicator.CUSTOM);\n        return ((BaseKey<? extends Key>) customKey).markAPIKey();\n    }\n\n    @Override\n    public Key getKey(String globalKey, String subKey) {\n        Preconditions.checkNotNull(globalKey, \"globalKey parameter cannot be null.\");\n        Preconditions.checkNotNull(subKey, \"subKey parameter cannot be null.\");\n        return ((BaseKey<? extends Key>) Keys.of(globalKey, subKey, KeyIndicator.CUSTOM)).markAPIKey();\n    }\n\n    @Override\n    public KeySet createKeySet(Supplier<Set<String>> setCreator) {\n        return KeySets.createSet(KeyIndicator.CUSTOM, KeySetStrategy.custom(setCreator));\n    }\n\n    @Override\n    public KeySet createKeySet(Supplier<Set<String>> setCreator, Collection<Key> collection) {\n        if (collection instanceof KeySet) return (KeySet) collection;\n        KeySet keySet = KeySets.createSet(KeyIndicator.CUSTOM, KeySetStrategy.custom(setCreator));\n        keySet.addAll(collection);\n        return keySet;\n    }\n\n    @Override\n    public <V> KeyMap<V> createKeyMap(Supplier<Map<String, V>> mapCreator) {\n        return KeyMaps.createMap(KeyIndicator.CUSTOM, KeyMapStrategy.custom(mapCreator));\n    }\n\n    @Override\n    public <V> KeyMap<V> createKeyMap(Supplier<Map<String, V>> mapCreator, Map<Key, V> map) {\n        if (map instanceof KeyMap) return (KeyMap<V>) map;\n        KeyMap<V> keyMap = KeyMaps.createMap(KeyIndicator.CUSTOM, KeyMapStrategy.custom(mapCreator));\n        keyMap.putAll(map);\n        return keyMap;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/MaterialKeySource.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key;\n\npublic enum MaterialKeySource {\n\n    ITEM,\n    BLOCK\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.CustomKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.google.common.base.Preconditions;\n\nimport java.util.AbstractMap;\nimport java.util.AbstractSet;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic class AbstractKeyMap<K extends Key, V> extends AbstractMap<Key, V> implements KeyMap<V> {\n\n    private final LazyReference<Map<K, V>> innerMap;\n    private final LazyReference<Map<CustomKey, V>> customInnerMap;\n    private final Class<K> keyType;\n\n    private EntrySet entrySet;\n    private int size;\n\n    protected AbstractKeyMap(KeyMapStrategy strategy, Class<K> keyType) {\n        this.innerMap = new LazyReference<Map<K, V>>() {\n            @Override\n            protected Map<K, V> create() {\n                return strategy.create(false);\n            }\n        };\n        this.customInnerMap = new LazyReference<Map<CustomKey, V>>() {\n            @Override\n            protected Map<CustomKey, V> create() {\n                return strategy.create(true);\n            }\n        };\n        this.keyType = keyType;\n    }\n\n    @Override\n    public int size() {\n        return this.size;\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return this.get(key) != null;\n    }\n\n    @Override\n    public V get(Object obj) {\n        if (size() == 0)\n            return null;\n\n        if (obj instanceof LazyKey) {\n            return get(((LazyKey<?>) obj).getBaseKey());\n        }\n\n        return getInternal((Key) obj, true);\n    }\n\n    private V getInternal(Key key, boolean tryGlobal) {\n        Preconditions.checkArgument(!(key instanceof LazyKey), \"Cannot call getInternal on LazyKey directly.\");\n\n        V value;\n\n        if (this.keyType.isInstance(key)) {\n            value = this.innerMap.getIfPresent().map(m -> m.get(key)).orElse(null);\n        } else if (key instanceof CustomKey) {\n            value = this.customInnerMap.getIfPresent().map(m -> m.get(key)).orElse(null);\n        } else {\n            value = null;\n        }\n\n        if (!tryGlobal || value != null)\n            return value;\n\n        Key globalKey = ((BaseKey<?>) key).toGlobalKey();\n\n        return globalKey == key ? null : getInternal(globalKey, false);\n    }\n\n    @Override\n    public V put(Key key, V value) {\n        if (key instanceof LazyKey) {\n            return put(((LazyKey<?>) key).getBaseKey(), value);\n        }\n\n        V oldValue;\n\n        if (this.keyType.isInstance(key)) {\n            oldValue = this.innerMap.get().put(this.keyType.cast(key), value);\n        } else if (key instanceof CustomKey) {\n            oldValue = this.customInnerMap.get().put((CustomKey) key, value);\n        } else {\n            throw new IllegalArgumentException(\"key \" + key.getClass() + \" is not of type \" + this.keyType);\n        }\n\n        if (oldValue == null)\n            ++this.size;\n\n        return oldValue;\n    }\n\n    @Override\n    public V remove(Object key) {\n        return size() == 0 ? null : removeNoSizeCheck(key);\n    }\n\n    private V removeNoSizeCheck(Object key) {\n        if (key instanceof LazyKey) {\n            return removeNoSizeCheck(((LazyKey<?>) key).getBaseKey());\n        }\n\n        V oldValue;\n\n        if (this.keyType.isInstance(key)) {\n            oldValue = this.innerMap.getIfPresent().map(m -> m.remove(key)).orElse(null);\n        } else if (key instanceof CustomKey) {\n            oldValue = this.customInnerMap.getIfPresent().map(m -> m.remove(key)).orElse(null);\n        } else {\n            return null;\n        }\n\n        if (oldValue != null)\n            --this.size;\n\n        return oldValue;\n    }\n\n    @Override\n    public void clear() {\n        this.innerMap.getIfPresent().ifPresent(Map::clear);\n        this.customInnerMap.getIfPresent().ifPresent(Map::clear);\n        this.size = 0;\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<Key, V>> entrySet() {\n        return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet;\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return this.getKey(original, null);\n    }\n\n    @Override\n    public Key getKey(Key original, @Nullable Key def) {\n        if (size() == 0)\n            return def;\n\n        if (original instanceof LazyKey) {\n            return getKey(((LazyKey<?>) original).getBaseKey());\n        }\n\n        Map<? extends Key, V> map;\n\n        if (this.keyType.isInstance(original)) {\n            map = this.innerMap.getIfPresent().orElse(null);\n        } else if (original instanceof CustomKey) {\n            map = this.customInnerMap.getIfPresent().orElse(null);\n        } else {\n            map = null;\n        }\n\n        if (map != null) {\n            if (map.containsKey(original))\n                return original;\n            Key globalKey = ((BaseKey<?>) original).toGlobalKey();\n            if (globalKey != original && map.containsKey(globalKey))\n                return globalKey;\n        }\n\n        return def;\n    }\n\n    @Override\n    public boolean removeIf(Predicate<Key> predicate) {\n        if (isEmpty())\n            return false;\n\n        boolean removed = false;\n\n        {\n            Map<K, V> innerMap = this.innerMap.getIfPresent().orElse(null);\n            if (innerMap != null) {\n                int originalSize = innerMap.size();\n                removed |= innerMap.entrySet().removeIf(entry -> predicate.test(entry.getKey()));\n                int delta = innerMap.size() - originalSize;\n                this.size -= delta;\n            }\n        }\n\n        {\n            Map<CustomKey, V> customInnerMap = this.customInnerMap.getIfPresent().orElse(null);\n            if (customInnerMap != null) {\n                int originalSize = customInnerMap.size();\n                removed |= customInnerMap.entrySet().removeIf(entry -> predicate.test(entry.getKey()));\n                int delta = customInnerMap.size() - originalSize;\n                this.size -= delta;\n            }\n        }\n\n        return removed;\n    }\n\n    @Override\n    public V getRaw(Key key, V def) {\n        if (size() == 0)\n            return def;\n\n        return getRawNoSizeCheck(key, def);\n    }\n\n    private V getRawNoSizeCheck(Key key, V def) {\n        if (key instanceof LazyKey) {\n            return getRawNoSizeCheck(((LazyKey<?>) key).getBaseKey(), def);\n        }\n\n        return Optional.ofNullable(getInternal(key, false)).orElse(def);\n    }\n\n    @Override\n    public V getOrDefault(Object key, V defaultValue) {\n        V value = get(key);\n        return value == null ? defaultValue : value;\n    }\n\n    @Override\n    public Map<Key, V> asMap() {\n        return this;\n    }\n\n    private class EntrySet extends AbstractSet<Entry<Key, V>> {\n\n        @Override\n        public int size() {\n            return AbstractKeyMap.this.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return AbstractKeyMap.this.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            Object key;\n            Object value;\n\n            if (o instanceof Entry) {\n                Entry<?, ?> entry = (Entry<?, ?>) o;\n                key = entry.getKey();\n                value = entry.getValue();\n            } else {\n                key = o;\n                value = null;\n            }\n\n            V realValue = AbstractKeyMap.this.get(key);\n            return realValue != null && (value == null || Objects.equals(realValue, value));\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Entry<Key, V>> iterator() {\n            return new EntryIterator();\n        }\n\n        @Override\n        public void clear() {\n            AbstractKeyMap.this.clear();\n        }\n\n    }\n\n    private class EntryIterator implements Iterator<Entry<Key, V>> {\n\n        private Iterator<Entry> currIterator;\n        private boolean isInnerMapIterator;\n        private final boolean shouldRunCustomIterator;\n\n        EntryIterator() {\n            Map innerMap = AbstractKeyMap.this.innerMap.getIfPresent().orElse(null);\n            Map customInnerMap = AbstractKeyMap.this.customInnerMap.getIfPresent().orElse(null);\n            this.shouldRunCustomIterator = customInnerMap != null && !customInnerMap.isEmpty();\n            if (innerMap != null) {\n                this.currIterator = innerMap.entrySet().iterator();\n                this.isInnerMapIterator = true;\n            } else {\n                this.currIterator = customInnerMap == null ? Collections.emptyIterator() : customInnerMap.entrySet().iterator();\n                this.isInnerMapIterator = false;\n            }\n        }\n\n        @Override\n        public boolean hasNext() {\n            if (this.isInnerMapIterator) {\n                return this.shouldRunCustomIterator || this.currIterator.hasNext();\n            }\n\n            return this.currIterator.hasNext();\n        }\n\n        @Override\n        public Entry<Key, V> next() {\n            if (!this.currIterator.hasNext()) {\n                if (!this.isInnerMapIterator || !this.shouldRunCustomIterator) {\n                    throw new NoSuchElementException();\n                }\n\n                Map customInnerMap = AbstractKeyMap.this.customInnerMap.getIfPresent().orElse(null);\n                // Should never occur as `shouldRunCustomIterator` would be false\n                if (customInnerMap == null || customInnerMap.isEmpty())\n                    throw new NoSuchElementException();\n\n                this.currIterator = customInnerMap.entrySet().iterator();\n                this.isInnerMapIterator = false;\n            }\n\n            return this.currIterator.next();\n        }\n\n        @Override\n        public void remove() {\n            this.currIterator.remove();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/CustomKeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.google.common.base.Preconditions;\n\nimport java.util.AbstractMap;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic class CustomKeyMap<V> extends AbstractMap<Key, V> implements KeyMap<V> {\n\n    private final LazyReference<Map<Key, V>> innerMap;\n\n    protected CustomKeyMap(KeyMapStrategy strategy) {\n        this.innerMap = new LazyReference<Map<Key, V>>() {\n            @Override\n            protected Map<Key, V> create() {\n                return strategy.create(false);\n            }\n        };\n    }\n\n    @Override\n    public int size() {\n        return this.innerMap.getIfPresent().map(Map::size).orElse(0);\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        return this.get(key) != null;\n    }\n\n    @Override\n    public V get(Object obj) {\n        if (size() == 0)\n            return null;\n\n        if (obj instanceof LazyKey) {\n            return get(((LazyKey<?>) obj).getBaseKey());\n        }\n\n        return getInternal((Key) obj, true);\n    }\n\n    private V getInternal(Key key, boolean tryGlobal) {\n        Preconditions.checkArgument(!(key instanceof LazyKey), \"Cannot call getInternal on LazyKey directly.\");\n\n        V value = this.innerMap.getIfPresent().map(m -> m.get(key)).orElse(null);\n\n        if (!tryGlobal || value != null)\n            return value;\n\n        Key globalKey = ((BaseKey<?>) key).toGlobalKey();\n\n        return globalKey == key ? null : getInternal(globalKey, false);\n    }\n\n    @Override\n    public V put(Key key, V value) {\n        if (key instanceof LazyKey) {\n            return put(((LazyKey<?>) key).getBaseKey(), value);\n        }\n\n        return this.innerMap.get().put(key, value);\n    }\n\n    @Override\n    public V remove(Object key) {\n        return size() == 0 ? null : removeNoSizeCheck(key);\n    }\n\n    private V removeNoSizeCheck(Object key) {\n        if (key instanceof LazyKey) {\n            return removeNoSizeCheck(((LazyKey<?>) key).getBaseKey());\n        }\n\n        return this.innerMap.getIfPresent().map(m -> m.remove(key)).orElse(null);\n    }\n\n    @Override\n    public void clear() {\n        this.innerMap.getIfPresent().ifPresent(Map::clear);\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<Key, V>> entrySet() {\n        return this.innerMap.getIfPresent().map(Map::entrySet).orElse(Collections.emptySet());\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return this.getKey(original, null);\n    }\n\n    @Override\n    public Key getKey(Key original, @Nullable Key def) {\n        if (size() == 0)\n            return def;\n\n        if (original instanceof LazyKey) {\n            return getKey(((LazyKey<?>) original).getBaseKey());\n        }\n\n        Map<Key, V> map = this.innerMap.getIfPresent().orElse(null);\n\n        if (map != null) {\n            if (map.containsKey(original))\n                return original;\n            Key globalKey = ((BaseKey<?>) original).toGlobalKey();\n            if (globalKey != original && map.containsKey(globalKey))\n                return globalKey;\n        }\n\n        return def;\n    }\n\n    @Override\n    public boolean removeIf(Predicate<Key> predicate) {\n        if (isEmpty())\n            return false;\n\n        return this.innerMap.getIfPresent().map(m ->\n                        m.entrySet().removeIf(entry -> predicate.test(entry.getKey())))\n                .orElse(false);\n    }\n\n    @Override\n    public V getRaw(Key key, V def) {\n        if (size() == 0)\n            return def;\n\n        return getRawNoSizeCheck(key, def);\n    }\n\n    private V getRawNoSizeCheck(Key key, V def) {\n        if (key instanceof LazyKey) {\n            return getRawNoSizeCheck(((LazyKey<?>) key).getBaseKey(), def);\n        }\n\n        return Optional.ofNullable(getInternal(key, false)).orElse(def);\n    }\n\n    @Override\n    public V getOrDefault(Object key, V defaultValue) {\n        V value = get(key);\n        return value == null ? defaultValue : value;\n    }\n\n    @Override\n    public Map<Key, V> asMap() {\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/EntityTypeKeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\n\npublic class EntityTypeKeyMap<V> extends AbstractKeyMap<EntityTypeKey, V> {\n\n    public EntityTypeKeyMap(KeyMapStrategy strategy) {\n        super(strategy, EntityTypeKey.class);\n    }\n\n    @Override\n    public String toString() {\n        return \"EntityTypeKeyMap\" + super.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMapStrategy.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Supplier;\n\npublic abstract class KeyMapStrategy {\n\n    public static final KeyMapStrategy ARRAY_MAP = new KeyMapStrategy() {\n        @Override\n        public <K, V> Map<K, V> create(boolean isCustomKeyMap) {\n            return new ArrayMap<>();\n        }\n    };\n\n    public static final KeyMapStrategy CONCURRENT_HASH_MAP = new KeyMapStrategy() {\n        @Override\n        public <K, V> Map<K, V> create(boolean isCustomKeyMap) {\n            return new ConcurrentHashMap<>();\n        }\n    };\n\n    public static final KeyMapStrategy HASH_MAP = new KeyMapStrategy() {\n        @Override\n        public <K, V> Map<K, V> create(boolean isCustomKeyMap) {\n            return new HashMap<>();\n        }\n    };\n\n    public static <K, V> KeyMapStrategy custom(Supplier<Map<K, V>> supplier) {\n        return new KeyMapStrategy() {\n            @Override\n            public <K, V> Map<K, V> create(boolean isCustomKeyMap) {\n                return (Map<K, V>) supplier.get();\n            }\n        };\n    }\n\n    private KeyMapStrategy() {\n\n    }\n\n    public abstract <K, V> Map<K, V> create(boolean isCustomKeyMap);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMaps.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\npublic class KeyMaps {\n\n    @SuppressWarnings(\"rawtypes\")\n    private static final KeyMap EMPTY_MAP = new EmptyKeyMap();\n\n    private KeyMaps() {\n\n    }\n\n    public static <V> KeyMap<V> createEmptyMap() {\n        return (KeyMap<V>) EMPTY_MAP;\n    }\n\n    public static <V> KeyMap<V> unmodifiableKeyMap(KeyMap<V> delegate) {\n        return delegate == EMPTY_MAP ? createEmptyMap() : new UnmodifiableKeyMap<>(delegate);\n    }\n\n    public static <V> KeyMap<V> createHashMap(KeyIndicator keyIndicator) {\n        return createMap(keyIndicator, KeyMapStrategy.HASH_MAP);\n    }\n\n    public static <V> KeyMap<V> createConcurrentHashMap(KeyIndicator keyIndicator) {\n        return createMap(keyIndicator, KeyMapStrategy.CONCURRENT_HASH_MAP);\n    }\n\n    public static <V> KeyMap<V> createArrayMap(KeyIndicator keyIndicator) {\n        return createMap(keyIndicator, KeyMapStrategy.ARRAY_MAP);\n    }\n\n    public static <V> KeyMap<V> createMap(KeyIndicator keyIndicator, KeyMapStrategy strategy) {\n        switch (keyIndicator) {\n            case MATERIAL:\n                return new MaterialKeyMap<>(strategy);\n            case ENTITY_TYPE:\n                return new EntityTypeKeyMap<>(strategy);\n        }\n\n        return new LazyLoadedKeyMap<>(strategy);\n    }\n\n    private static class EmptyKeyMap<V> implements KeyMap<V> {\n\n        @Nullable\n        @Override\n        public Key getKey(Key original) {\n            return null;\n        }\n\n        @Override\n        public Key getKey(Key original, @Nullable Key def) {\n            return def;\n        }\n\n        @Override\n        public V getRaw(Key key, V def) {\n            return def;\n        }\n\n        @Override\n        public Map<Key, V> asMap() {\n            return this;\n        }\n\n        @Override\n        public int size() {\n            return 0;\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return true;\n        }\n\n        @Override\n        public boolean containsKey(Object key) {\n            return false;\n        }\n\n        @Override\n        public boolean containsValue(Object value) {\n            return false;\n        }\n\n        @Override\n        public V get(Object key) {\n            return null;\n        }\n\n        @NotNull\n        @Override\n        public Set<Key> keySet() {\n            return Collections.emptySet();\n        }\n\n        @NotNull\n        @Override\n        public Collection<V> values() {\n            return Collections.emptyList();\n        }\n\n        @NotNull\n        @Override\n        public Set<Entry<Key, V>> entrySet() {\n            return Collections.emptySet();\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return obj instanceof Map && ((Map<?, ?>) obj).isEmpty();\n        }\n\n        @Override\n        public int hashCode() {\n            return 0;\n        }\n\n        @Override\n        public V getOrDefault(Object key, V defaultValue) {\n            return defaultValue;\n        }\n\n        @Override\n        public void forEach(BiConsumer<? super Key, ? super V> action) {\n            // Do nothing.\n        }\n\n        @Override\n        public void replaceAll(BiFunction<? super Key, ? super V, ? extends V> function) {\n            // Do nothing.\n        }\n\n        @Nullable\n        @Override\n        public V putIfAbsent(Key key, V value) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public V remove(Object key) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public boolean replace(Key key, V oldValue, V newValue) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Nullable\n        @Override\n        public V replace(Key key, V value) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public V computeIfAbsent(Key key, @NotNull Function<? super Key, ? extends V> mappingFunction) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public V computeIfPresent(Key key, @NotNull BiFunction<? super Key, ? super V, ? extends V> remappingFunction) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public V compute(Key key, @NotNull BiFunction<? super Key, ? super V, ? extends V> remappingFunction) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public V merge(Key key, @NotNull V value, @NotNull BiFunction<? super V, ? super V, ? extends V> remappingFunction) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Nullable\n        @Override\n        public V put(Key key, V value) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public void putAll(@NotNull Map<? extends Key, ? extends V> m) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public void clear() {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n        @Override\n        public boolean removeIf(Predicate<Key> predicate) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeyMap\");\n        }\n\n    }\n\n    private static class UnmodifiableKeyMap<V> implements KeyMap<V> {\n\n        private final KeyMap<V> delegate;\n\n        UnmodifiableKeyMap(KeyMap<V> delegate) {\n            this.delegate = delegate;\n        }\n\n        @Nullable\n        @Override\n        public Key getKey(Key original) {\n            return this.delegate.getKey(original);\n        }\n\n        @Override\n        public Key getKey(Key original, @Nullable Key def) {\n            return this.delegate.getKey(original, def);\n        }\n\n        @Override\n        public V getRaw(Key key, V def) {\n            return this.delegate.getRaw(key, def);\n        }\n\n        @Override\n        public Map<Key, V> asMap() {\n            return this;\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return this.delegate.isEmpty();\n        }\n\n        @Override\n        public boolean containsKey(Object key) {\n            return this.delegate.containsKey(key);\n        }\n\n        @Override\n        public boolean containsValue(Object value) {\n            return this.delegate.containsValue(value);\n        }\n\n        @Override\n        public V get(Object key) {\n            return this.delegate.get(key);\n        }\n\n        @NotNull\n        @Override\n        public Set<Key> keySet() {\n            return this.delegate.keySet();\n        }\n\n        @NotNull\n        @Override\n        public Collection<V> values() {\n            return this.delegate.values();\n        }\n\n        @NotNull\n        @Override\n        public Set<Entry<Key, V>> entrySet() {\n            return this.delegate.entrySet();\n        }\n\n        @Override\n        public boolean removeIf(Predicate<Key> predicate) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeyMap\");\n        }\n\n        @Nullable\n        @Override\n        public V put(Key key, V value) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeyMap\");\n        }\n\n        @Override\n        public V remove(Object key) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeyMap\");\n        }\n\n        @Override\n        public void putAll(@NotNull Map<? extends Key, ? extends V> m) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeyMap\");\n        }\n\n        @Override\n        public void clear() {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeyMap\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\n\nimport java.util.AbstractMap;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\npublic class LazyLoadedKeyMap<V> extends AbstractMap<Key, V> implements KeyMap<V> {\n\n    private final KeyMapStrategy strategy;\n    @Nullable\n    private KeyMap<V> delegate;\n    @Nullable\n    private KeyMap<V> pendingCustomKeys;\n\n    public LazyLoadedKeyMap(KeyMapStrategy strategy) {\n        this.strategy = strategy;\n    }\n\n    @Override\n    public int size() {\n        return runOnMap(KeyMap::size, 0);\n    }\n\n    @Override\n    public boolean containsKey(Object o) {\n        return runOnMap(m -> m.containsKey(o), false);\n    }\n\n    @Override\n    public V get(Object obj) {\n        return runOnMap(m -> m.get(obj), null);\n    }\n\n    @Override\n    public V put(Key key, V value) {\n        if (this.delegate != null)\n            return this.delegate.put(key, value);\n\n        return putNoDelegate(key, value);\n    }\n\n    private V putNoDelegate(Key key, V value) {\n        if (key instanceof LazyKey) {\n            return putNoDelegate(((LazyKey<?>) key).getBaseKey(), value);\n        }\n\n        if (key instanceof EntityTypeKey) {\n            this.delegate = new EntityTypeKeyMap<>(this.strategy);\n            addPendingCustomKeys();\n        } else if (key instanceof MaterialKey) {\n            this.delegate = new MaterialKeyMap<>(this.strategy);\n            addPendingCustomKeys();\n        } else {\n            if (this.pendingCustomKeys == null)\n                this.pendingCustomKeys = new CustomKeyMap<>(this.strategy);\n\n            return this.pendingCustomKeys.put(key, value);\n        }\n\n        return this.delegate.put(key, value);\n    }\n\n    @Override\n    public V remove(Object key) {\n        return runOnMap(m -> m.remove(key), null);\n    }\n\n    @Override\n    public void clear() {\n        runOnMap(KeyMap::clear);\n    }\n\n    @NotNull\n    @Override\n    public Set<Entry<Key, V>> entrySet() {\n        return runOnMap(KeyMap::entrySet, Collections.emptySet());\n    }\n\n    @Override\n    public String toString() {\n        return runOnMap(KeyMap::toString, \"LazyLoadedKeyMap{}\");\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return runOnMap(m -> m.getKey(original), null);\n    }\n\n    @Override\n    public Key getKey(Key original, @Nullable Key def) {\n        return runOnMap(m -> m.getKey(original, def), def);\n    }\n\n\n    @Override\n    public boolean removeIf(Predicate<Key> predicate) {\n        return runOnMap(m -> m.removeIf(predicate), false);\n    }\n\n    @Override\n    public V getRaw(Key key, V def) {\n        return runOnMap(m -> m.getRaw(key, def), def);\n    }\n\n    @Override\n    public V getOrDefault(Object key, V defaultValue) {\n        return runOnMap(m -> m.getOrDefault(key, defaultValue), defaultValue);\n    }\n\n    @Override\n    public Map<Key, V> asMap() {\n        return runOnMap(KeyMap::asMap, this);\n    }\n\n    private <T> T runOnMap(Function<KeyMap<V>, T> function, T def) {\n        if (this.delegate != null)\n            return function.apply(this.delegate);\n\n        else if (this.pendingCustomKeys != null)\n            return function.apply(this.pendingCustomKeys);\n\n        else\n            return def;\n    }\n\n    private void runOnMap(Consumer<KeyMap<V>> consumer) {\n        if (this.delegate != null)\n            consumer.accept(this.delegate);\n\n        else if (this.pendingCustomKeys != null)\n            consumer.accept(this.pendingCustomKeys);\n    }\n\n    private void addPendingCustomKeys() {\n        if (this.pendingCustomKeys == null)\n            return;\n\n        this.delegate.putAll(this.pendingCustomKeys);\n        this.pendingCustomKeys = null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/map/MaterialKeyMap.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.map;\n\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\n\npublic class MaterialKeyMap<V> extends AbstractKeyMap<MaterialKey, V> {\n\n    public MaterialKeyMap(KeyMapStrategy strategy) {\n        super(strategy, MaterialKey.class);\n    }\n\n    @Override\n    public String toString() {\n        return \"MaterialKeyMap\" + super.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/AbstractKeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.CustomKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.google.common.base.Preconditions;\n\nimport java.util.AbstractSet;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\nimport java.util.Set;\n\npublic class AbstractKeySet<K extends Key> extends AbstractSet<Key> implements KeySet {\n\n    private final LazyReference<Set<K>> innerSet;\n    private final LazyReference<Set<CustomKey>> customInnerSet;\n    private final Class<K> keyType;\n\n    private int size;\n\n    protected AbstractKeySet(KeySetStrategy strategy, Class<K> keyType) {\n        this.innerSet = new LazyReference<Set<K>>() {\n            @Override\n            protected Set<K> create() {\n                return strategy.create(false);\n            }\n        };\n        this.customInnerSet = new LazyReference<Set<CustomKey>>() {\n            @Override\n            protected Set<CustomKey> create() {\n                return strategy.create(true);\n            }\n        };\n        this.keyType = keyType;\n    }\n\n    @Override\n    public int size() {\n        return this.size;\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        if (size() == 0)\n            return false;\n\n        if (o instanceof LazyKey) {\n            return contains(((LazyKey<?>) o).getBaseKey());\n        }\n\n        return containsInternal((Key) o, true);\n    }\n\n    private boolean containsInternal(Key key, boolean tryGlobal) {\n        Preconditions.checkArgument(!(key instanceof LazyKey), \"Cannot call getInternal on LazyKey directly.\");\n\n        boolean contained;\n\n        if (this.keyType.isInstance(key)) {\n            contained = this.innerSet.getIfPresent().map(s -> s.contains(key)).orElse(false);\n        } else if (key instanceof CustomKey) {\n            contained = this.customInnerSet.getIfPresent().map(s -> s.contains(key)).orElse(false);\n        } else {\n            contained = false;\n        }\n\n        if (!tryGlobal || contained)\n            return contained;\n\n        Key globalKey = ((BaseKey<?>) key).toGlobalKey();\n\n        return globalKey != key && containsInternal(globalKey, false);\n    }\n\n    @Override\n    public boolean add(Key key) {\n        if (key instanceof LazyKey) {\n            return add(((LazyKey<?>) key).getBaseKey());\n        }\n\n        boolean modified;\n\n        if (this.keyType.isInstance(key)) {\n            modified = this.innerSet.get().add(this.keyType.cast(key));\n        } else if (key instanceof CustomKey) {\n            modified = this.customInnerSet.get().add((CustomKey) key);\n        } else {\n            throw new IllegalArgumentException(\"key \" + key.getClass() + \" is not of type \" + this.keyType);\n        }\n\n        if (modified)\n            ++this.size;\n\n        return modified;\n    }\n\n    @Override\n    public boolean remove(Object key) {\n        return size() != 0 && removeNoSizeCheck(key);\n    }\n\n    private boolean removeNoSizeCheck(Object key) {\n        if (key instanceof LazyKey) {\n            return remove(((LazyKey<?>) key).getBaseKey());\n        }\n\n        boolean contained;\n\n        if (this.keyType.isInstance(key)) {\n            contained = this.innerSet.getIfPresent().map(s -> s.remove(key)).orElse(false);\n        } else if (key instanceof CustomKey) {\n            contained = this.customInnerSet.getIfPresent().map(s -> s.remove(key)).orElse(false);\n        } else {\n            return false;\n        }\n\n        if (contained)\n            --this.size;\n\n        return contained;\n    }\n\n    @Override\n    public void clear() {\n        this.innerSet.getIfPresent().ifPresent(Set::clear);\n        this.customInnerSet.getIfPresent().ifPresent(Set::clear);\n        this.size = 0;\n    }\n\n    @Override\n    public Iterator<Key> iterator() {\n        return new SetIterator();\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return this.getKey(original, null);\n    }\n\n    @Override\n    public Key getKey(Key original, @Nullable Key def) {\n        if (size() == 0)\n            return def;\n\n        if (original instanceof LazyKey) {\n            return getKey(((LazyKey<?>) original).getBaseKey());\n        }\n\n        Set set;\n\n        if (this.keyType.isInstance(original)) {\n            set = this.innerSet.getIfPresent().orElse(null);\n        } else if (original instanceof CustomKey) {\n            set = this.customInnerSet.getIfPresent().orElse(null);\n        } else {\n            set = null;\n        }\n\n        if (set != null) {\n            if (set.contains(original))\n                return original;\n            Key globalKey = ((BaseKey<?>) original).toGlobalKey();\n            if (globalKey != original && set.contains(globalKey))\n                return globalKey;\n        }\n\n        return def;\n    }\n\n    @Override\n    public Set<Key> asSet() {\n        return this;\n    }\n\n    private class SetIterator implements Iterator<Key> {\n\n        private Iterator<Key> currIterator;\n        private boolean isInnerSetIterator;\n        private final boolean shouldRunCustomIterator;\n\n        SetIterator() {\n            Set innerSet = AbstractKeySet.this.innerSet.getIfPresent().orElse(null);\n            Set customInnerSet = AbstractKeySet.this.customInnerSet.getIfPresent().orElse(null);\n            this.shouldRunCustomIterator = customInnerSet != null && !customInnerSet.isEmpty();\n            if (innerSet != null) {\n                this.currIterator = innerSet.iterator();\n                this.isInnerSetIterator = true;\n            } else {\n                this.currIterator = customInnerSet == null ? Collections.emptyIterator() : customInnerSet.iterator();\n                this.isInnerSetIterator = false;\n            }\n        }\n\n        @Override\n        public boolean hasNext() {\n            if (this.isInnerSetIterator) {\n                return this.shouldRunCustomIterator || this.currIterator.hasNext();\n            }\n\n            return this.currIterator.hasNext();\n        }\n\n        @Override\n        public Key next() {\n            if (!this.currIterator.hasNext()) {\n                if (!this.isInnerSetIterator || !this.shouldRunCustomIterator) {\n                    throw new NoSuchElementException();\n                }\n\n                Set customInnerSet = AbstractKeySet.this.customInnerSet.getIfPresent().orElse(null);\n                // Should never occur as `shouldRunCustomIterator` would be false\n                if (customInnerSet == null || customInnerSet.isEmpty())\n                    throw new NoSuchElementException();\n\n                this.currIterator = customInnerSet.iterator();\n                this.isInnerSetIterator = false;\n            }\n\n            return this.currIterator.next();\n        }\n\n        @Override\n        public void remove() {\n            this.currIterator.remove();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.google.common.base.Preconditions;\n\nimport java.util.AbstractSet;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Set;\n\npublic class CustomKeySet extends AbstractSet<Key> implements KeySet {\n\n    private final LazyReference<Set<Key>> innerSet;\n\n    public CustomKeySet(KeySetStrategy strategy) {\n        this.innerSet = new LazyReference<Set<Key>>() {\n            @Override\n            protected Set<Key> create() {\n                return strategy.create(true);\n            }\n        };\n    }\n\n    @Override\n    public int size() {\n        return this.innerSet.getIfPresent().map(Set::size).orElse(0);\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        if (size() == 0)\n            return false;\n\n        if (o instanceof LazyKey) {\n            return contains(((LazyKey<?>) o).getBaseKey());\n        }\n\n        return containsInternal((Key) o, true);\n    }\n\n    private boolean containsInternal(Key key, boolean tryGlobal) {\n        Preconditions.checkArgument(!(key instanceof LazyKey), \"Cannot call getInternal on LazyKey directly.\");\n\n        boolean contained = this.innerSet.getIfPresent().map(s -> s.contains(key)).orElse(false);\n\n        if (!tryGlobal || contained)\n            return contained;\n\n        Key globalKey = ((BaseKey<?>) key).toGlobalKey();\n\n        return globalKey != key && containsInternal(globalKey, false);\n    }\n\n    @Override\n    public boolean add(Key key) {\n        if (key instanceof LazyKey) {\n            return add(((LazyKey<?>) key).getBaseKey());\n        }\n\n        return this.innerSet.get().add(key);\n    }\n\n    @Override\n    public boolean remove(Object key) {\n        return size() != 0 && removeNoSizeCheck(key);\n    }\n\n    private boolean removeNoSizeCheck(Object key) {\n        if (key instanceof LazyKey) {\n            return remove(((LazyKey<?>) key).getBaseKey());\n        }\n\n        return this.innerSet.getIfPresent().map(s -> s.remove(key)).orElse(false);\n    }\n\n    @Override\n    public void clear() {\n        this.innerSet.getIfPresent().ifPresent(Set::clear);\n    }\n\n    @Override\n    public Iterator<Key> iterator() {\n        return this.innerSet.getIfPresent().map(Set::iterator).orElse(Collections.emptyIterator());\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return this.getKey(original, null);\n    }\n\n    @Override\n    public Key getKey(Key original, @Nullable Key def) {\n        if (size() == 0)\n            return def;\n\n        if (original instanceof LazyKey) {\n            return getKey(((LazyKey<?>) original).getBaseKey());\n        }\n\n        Set<Key> set = this.innerSet.getIfPresent().orElse(null);\n\n        if (set != null) {\n            if (set.contains(original))\n                return original;\n            Key globalKey = ((BaseKey<?>) original).toGlobalKey();\n            if (globalKey != original && set.contains(globalKey))\n                return globalKey;\n        }\n\n        return def;\n    }\n\n    @Override\n    public Set<Key> asSet() {\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/EntityTypeKeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\n\npublic class EntityTypeKeySet extends AbstractKeySet<EntityTypeKey> {\n\n    public EntityTypeKeySet(KeySetStrategy strategy) {\n        super(strategy, EntityTypeKey.class);\n    }\n\n    @Override\n    public String toString() {\n        return \"EntityTypeKeySet\" + super.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySetStrategy.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic abstract class KeySetStrategy {\n\n    public static final KeySetStrategy HASH_SET = new KeySetStrategy() {\n        @Override\n        public <K> Set<K> create(boolean isCustomKeySet) {\n            return new HashSet<>();\n        }\n    };\n\n    public static <K> KeySetStrategy custom(Supplier<Set<K>> supplier) {\n        return new KeySetStrategy() {\n            @Override\n            public <K> Set<K> create(boolean isCustomKeyMap) {\n                return (Set<K>) supplier.get();\n            }\n        };\n    }\n\n    private KeySetStrategy() {\n\n    }\n\n    public abstract <K> Set<K> create(boolean isCustomKeySet);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\npublic class KeySets {\n\n    private static final KeySet EMPTY_SET = new EmptyKeySet();\n\n    private KeySets() {\n\n    }\n\n    public static KeySet createEmptySet() {\n        return EMPTY_SET;\n    }\n\n    public static KeySet unmodifiableKeySet(KeySet delegate) {\n        return delegate == EMPTY_SET ? createEmptySet() : new UnmodifiableKeySet(delegate);\n    }\n\n    public static KeySet createHashSet(KeyIndicator keyIndicator) {\n        return createSet(keyIndicator, KeySetStrategy.HASH_SET);\n    }\n\n    public static KeySet createSet(KeyIndicator keyIndicator, KeySetStrategy strategy) {\n        switch (keyIndicator) {\n            case MATERIAL:\n                return new MaterialKeySet(strategy);\n            case ENTITY_TYPE:\n                return new EntityTypeKeySet(strategy);\n        }\n\n        return new LazyLoadedKeySet(strategy);\n    }\n\n    public static KeySet createHashSet(KeyIndicator keyIndicator, Collection<String> rawKeys) {\n        KeySet keySet = createHashSet(keyIndicator);\n\n        Function<String, Key> keyCreator;\n        switch (keyIndicator) {\n            case MATERIAL:\n                keyCreator = Keys::ofMaterialAndData;\n                break;\n            case ENTITY_TYPE:\n                keyCreator = Keys::ofEntityType;\n                break;\n            default:\n                keyCreator = Keys::ofCustom;\n                break;\n        }\n\n        rawKeys.forEach(key -> keySet.add(keyCreator.apply(key)));\n\n        return keySet;\n    }\n\n    private static class EmptyKeySet implements KeySet {\n\n        @Nullable\n        @Override\n        public Key getKey(Key original) {\n            return null;\n        }\n\n        @Override\n        public Key getKey(Key original, Key def) {\n            return def;\n        }\n\n        @Override\n        public Set<Key> asSet() {\n            return this;\n        }\n\n        @Override\n        public int size() {\n            return 0;\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return true;\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return false;\n        }\n\n        @Override\n        public boolean containsAll(@NotNull Collection<?> c) {\n            return c.isEmpty();\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Key> iterator() {\n            return Collections.emptyIterator();\n        }\n\n        @NotNull\n        @Override\n        public Object[] toArray() {\n            return new Object[0];\n        }\n\n        @NotNull\n        @Override\n        public <T> T[] toArray(@NotNull T[] a) {\n            if (a.length > 0)\n                a[0] = null;\n            return a;\n        }\n\n        @Override\n        public void forEach(Consumer<? super Key> action) {\n            // Do nothing.\n        }\n\n        @Override\n        public boolean removeIf(Predicate<? super Key> filter) {\n            return false;\n        }\n\n        @Override\n        public Spliterator<Key> spliterator() {\n            return Spliterators.emptySpliterator();\n        }\n\n        @Override\n        public boolean add(Key key) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n        @Override\n        public boolean remove(Object o) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n        @Override\n        public boolean addAll(@NotNull Collection<? extends Key> c) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n        @Override\n        public boolean retainAll(@NotNull Collection<?> c) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n        @Override\n        public boolean removeAll(@NotNull Collection<?> c) {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n        @Override\n        public void clear() {\n            throw new UnsupportedOperationException(\"Cannot modify EmptyKeySet\");\n        }\n\n    }\n\n    private static class UnmodifiableKeySet implements KeySet {\n\n        private final KeySet delegate;\n\n        UnmodifiableKeySet(KeySet delegate) {\n            this.delegate = delegate;\n        }\n\n        @Nullable\n        @Override\n        public Key getKey(Key original) {\n            return this.delegate.getKey(original);\n        }\n\n        @Override\n        public Key getKey(Key original, Key def) {\n            return this.delegate.getKey(original, def);\n        }\n\n        @Override\n        public Set<Key> asSet() {\n            return this;\n        }\n\n        @Override\n        public int size() {\n            return this.delegate.size();\n        }\n\n        @Override\n        public boolean isEmpty() {\n            return this.delegate.isEmpty();\n        }\n\n        @Override\n        public boolean contains(Object o) {\n            return this.delegate.contains(o);\n        }\n\n        @NotNull\n        @Override\n        public Iterator<Key> iterator() {\n            return this.delegate.iterator();\n        }\n\n        @NotNull\n        @Override\n        public Object[] toArray() {\n            return this.delegate.toArray();\n        }\n\n        @NotNull\n        @Override\n        public <T> T[] toArray(@NotNull T[] a) {\n            return this.delegate.toArray(a);\n        }\n\n        @Override\n        public boolean containsAll(@NotNull Collection<?> c) {\n            return this.delegate.containsAll(c);\n        }\n\n        @Override\n        public boolean add(Key key) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n        @Override\n        public boolean remove(Object o) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n        @Override\n        public boolean addAll(@NotNull Collection<? extends Key> c) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n        @Override\n        public boolean retainAll(@NotNull Collection<?> c) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n        @Override\n        public boolean removeAll(@NotNull Collection<?> c) {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n        @Override\n        public void clear() {\n            throw new UnsupportedOperationException(\"Cannot modify UnmodifiableKeySet\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.LazyKey;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\n\nimport java.util.AbstractSet;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class LazyLoadedKeySet extends AbstractSet<Key> implements KeySet {\n\n    private final KeySetStrategy strategy;\n    @Nullable\n    private KeySet delegate;\n    @Nullable\n    private KeySet pendingCustomKeys;\n\n    public LazyLoadedKeySet(KeySetStrategy strategy) {\n        this.strategy = strategy;\n    }\n\n    @Override\n    public int size() {\n        return runOnSet(KeySet::size, 0);\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        return runOnSet(s -> s.contains(o), false);\n    }\n\n    @Override\n    public boolean add(Key key) {\n        if (this.delegate != null)\n            return this.delegate.add(key);\n\n        return addNoDelegate(key);\n    }\n\n    public boolean addNoDelegate(Key key) {\n        if (key instanceof LazyKey) {\n            return addNoDelegate(((LazyKey<?>) key).getBaseKey());\n        }\n\n        if (key instanceof EntityTypeKey) {\n            this.delegate = new EntityTypeKeySet(this.strategy);\n            addPendingCustomKeys();\n        } else if (key instanceof MaterialKey) {\n            this.delegate = new MaterialKeySet(this.strategy);\n            addPendingCustomKeys();\n        } else {\n            if (this.pendingCustomKeys == null)\n                this.pendingCustomKeys = new CustomKeySet(this.strategy);\n\n            return this.pendingCustomKeys.add(key);\n        }\n\n        return this.delegate.add(key);\n    }\n\n    @Override\n    public boolean remove(Object key) {\n        return runOnSet(s -> s.remove(key), false);\n    }\n\n    @Override\n    public void clear() {\n        runOnSet(Set::clear);\n    }\n\n    @Override\n    public Iterator<Key> iterator() {\n        return runOnSet(Set::iterator, Collections.emptyIterator());\n    }\n\n    @Nullable\n    @Override\n    public Key getKey(Key original) {\n        return runOnSet(s -> s.getKey(original), null);\n    }\n\n    @Override\n    public Key getKey(Key original, Key def) {\n        return runOnSet(s -> s.getKey(original, def), def);\n    }\n\n    @Override\n    public String toString() {\n        return runOnSet(Object::toString, \"LazyLoadedKeySet[]\");\n    }\n\n    @Override\n    public Set<Key> asSet() {\n        return runOnSet(KeySet::asSet, this);\n    }\n\n    private <T> T runOnSet(Function<KeySet, T> function, T def) {\n        if (this.delegate != null)\n            return function.apply(this.delegate);\n\n        else if (this.pendingCustomKeys != null)\n            return function.apply(this.pendingCustomKeys);\n\n        else\n            return def;\n    }\n\n    private void runOnSet(Consumer<KeySet> consumer) {\n        if (this.delegate != null)\n            consumer.accept(this.delegate);\n\n        else if (this.pendingCustomKeys != null)\n            consumer.accept(this.pendingCustomKeys);\n    }\n\n    private void addPendingCustomKeys() {\n        if (this.pendingCustomKeys == null)\n            return;\n\n        this.delegate.addAll(this.pendingCustomKeys);\n        this.pendingCustomKeys = null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/set/MaterialKeySet.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.set;\n\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\n\npublic class MaterialKeySet extends AbstractKeySet<MaterialKey> {\n\n    public MaterialKeySet(KeySetStrategy strategy) {\n        super(strategy, MaterialKey.class);\n    }\n\n    @Override\n    public String toString() {\n        return \"MaterialKeySet\" + super.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.types;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.Locale;\nimport java.util.Objects;\n\npublic class CustomKey extends BaseKey<CustomKey> {\n\n    private final LazyReference<CustomKey> apiKeyCache = new LazyReference<CustomKey>() {\n        @Override\n        protected CustomKey create() {\n            if (CustomKey.this.isAPIKey())\n                throw new UnsupportedOperationException();\n\n            return new CustomKey(CustomKey.this.globalKey, CustomKey.this.subKey, true);\n        }\n    };\n\n    private final String globalKey;\n    private final String subKey;\n\n    public static CustomKey of(String globalKey, @Nullable String subKey, KeyIndicator keyType) {\n        switch (keyType) {\n            case ENTITY_TYPE:\n                Preconditions.checkArgument(EnumHelper.getEnum(EntityType.class, globalKey) == null,\n                        \"CustomKey received a valid EntityType type: \" + globalKey);\n                break;\n            case MATERIAL:\n                Preconditions.checkArgument(EnumHelper.getEnum(Material.class, globalKey) == null,\n                        \"CustomKey received a valid Material type: \" + globalKey);\n                break;\n        }\n\n        return new CustomKey(globalKey, subKey, false);\n    }\n\n    private CustomKey(String globalKey, @Nullable String subKey, boolean apiKey) {\n        super(CustomKey.class, apiKey);\n        this.globalKey = Preconditions.checkNotNull(globalKey, \"globalKey cannot be null\").toUpperCase(Locale.ENGLISH);\n        this.subKey = Text.isBlank(subKey) ? null : subKey.toUpperCase(Locale.ENGLISH);\n    }\n\n    @Override\n    public String getGlobalKey() {\n        return this.globalKey;\n    }\n\n    @Override\n    public CustomKey toGlobalKey() {\n        return this.subKey == null ? this : CustomKey.of(this.globalKey, null, KeyIndicator.CUSTOM);\n    }\n\n    @Override\n    public String getSubKey() {\n        return this.subKey;\n    }\n\n    @Override\n    protected String toStringInternal() {\n        return this.subKey == null ? this.globalKey : this.globalKey + \":\" + this.subKey;\n    }\n\n    @Override\n    protected int hashCodeInternal() {\n        return Objects.hash(this.globalKey, this.subKey);\n    }\n\n    @Override\n    protected boolean equalsInternal(CustomKey other) {\n        return this.globalKey.equals(other.globalKey) && Objects.equals(this.subKey, other.subKey);\n    }\n\n    @Override\n    protected int compareToInternal(CustomKey other) {\n        return toString().compareTo(other.toString());\n    }\n\n    @Override\n    public CustomKey createAPIKeyInternal() {\n        return this.apiKeyCache.get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.types;\n\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.EnumMap;\n\npublic class EntityTypeKey extends BaseKey<EntityTypeKey> {\n\n    private static final EnumMap<EntityType, EntityTypeKey> ENTITY_TYPE_KEYS_CACHE = new EnumMap<>(EntityType.class);\n\n    static {\n        // Load all entity type keys\n        for (EntityType entityType : EntityType.values()) {\n            EntityTypeKey entityTypeKey = of(entityType);\n            entityTypeKey.loadLazyCaches();\n        }\n    }\n\n    private final LazyReference<EntityTypeKey> apiKeyCache = new LazyReference<EntityTypeKey>() {\n        @Override\n        protected EntityTypeKey create() {\n            if (EntityTypeKey.this.isAPIKey())\n                throw new UnsupportedOperationException();\n\n            return new EntityTypeKey(EntityTypeKey.this.entityType, true);\n        }\n    };\n\n    private final EntityType entityType;\n\n    public static EntityTypeKey of(EntityType entityType) {\n        return ENTITY_TYPE_KEYS_CACHE.computeIfAbsent(entityType, EntityTypeKey::new);\n    }\n\n    private EntityTypeKey(EntityType entityType) {\n        this(entityType, false);\n    }\n\n    private EntityTypeKey(EntityType entityType, boolean apiKey) {\n        super(EntityTypeKey.class, apiKey);\n        this.entityType = Preconditions.checkNotNull(entityType, \"entityType cannot be null\");\n    }\n\n    @Override\n    public String getGlobalKey() {\n        return this.entityType.name();\n    }\n\n    @Override\n    public EntityTypeKey toGlobalKey() {\n        return this;\n    }\n\n    @Override\n    public String getSubKey() {\n        return \"\";\n    }\n\n    @Override\n    protected int compareToInternal(EntityTypeKey other) {\n        return Integer.compare(this.entityType.ordinal(), other.entityType.ordinal());\n    }\n\n    @Override\n    protected String toStringInternal() {\n        return this.getGlobalKey();\n    }\n\n    @Override\n    protected int hashCodeInternal() {\n        return this.entityType.hashCode();\n    }\n\n    @Override\n    protected boolean equalsInternal(EntityTypeKey other) {\n        return this.entityType == other.entityType;\n    }\n\n    @Override\n    public EntityTypeKey createAPIKeyInternal() {\n        return this.apiKeyCache.get();\n    }\n\n    public EntityType getEntityType() {\n        return entityType;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.types;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.google.common.base.Preconditions;\n\npublic class LazyKey<T extends Key> extends BaseKey<T> {\n\n    private final LazyReference<T> baseKeyLoader;\n\n    public LazyKey(Class<T> baseKeyClass, LazyReference<T> baseKeyLoader) {\n        super(baseKeyClass, false);\n        Preconditions.checkArgument(baseKeyClass != BaseKey.class);\n        this.baseKeyLoader = baseKeyLoader;\n    }\n\n    public T getBaseKey() {\n        return this.baseKeyLoader.get();\n    }\n\n    @Override\n    public final String getGlobalKey() {\n        return getBaseKey().getGlobalKey();\n    }\n\n    @Override\n    public final T toGlobalKey() {\n        return ((BaseKey<T>) getBaseKey()).toGlobalKey();\n    }\n\n    @Override\n    public final String getSubKey() {\n        return getBaseKey().getSubKey();\n    }\n\n    @Override\n    protected final String toStringInternal() {\n        return getBaseKey().toString();\n    }\n\n    @Override\n    protected final int hashCodeInternal() {\n        return getBaseKey().hashCode();\n    }\n\n    @Override\n    protected final boolean equalsInternal(T other) {\n        return getBaseKey().equals(other);\n    }\n\n    @Override\n    protected final int compareToInternal(T other) {\n        return getBaseKey().compareTo(other);\n    }\n\n    @Override\n    public T createAPIKeyInternal() {\n        return ((BaseKey<T>) getBaseKey()).createAPIKeyInternal();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.types;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.MaterialKeySource;\nimport com.google.common.base.Objects;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Material;\n\nimport java.util.EnumMap;\n\npublic class MaterialKey extends BaseKey<MaterialKey> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final EnumMap<Material, MaterialKey> GLOBAL_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class);\n    private static final EnumMap<Material, MaterialKey[]> ID_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class);\n\n    static {\n        // Load all material type keys\n        for (Material material : Material.values()) {\n            if (material != Materials.SPAWNER.toBukkitType()) {\n                MaterialKey globalKey = of(material);\n                globalKey.loadLazyCaches();\n\n                int maxDataValue = plugin.getNMSAlgorithms().getMaxBlockDataValue(material) + 1;\n                for (int i = 0; i < maxDataValue; ++i) {\n                    MaterialKey materialKey = of(material, (short) i, MaterialKeySource.BLOCK);\n                    materialKey.loadLazyCaches();\n                }\n            }\n        }\n    }\n\n    private final LazyReference<MaterialKey> apiKeyCache = new LazyReference<MaterialKey>() {\n        @Override\n        protected MaterialKey create() {\n            if (MaterialKey.this.isAPIKey())\n                throw new UnsupportedOperationException();\n\n            return createAPIKeyForCacheInternal();\n        }\n    };\n\n    protected final Material type;\n    private final short durability;\n    private final String durabilityAsString;\n    protected final boolean isGlobalType;\n    private final MaterialKeySource materialKeySource;\n\n    public static MaterialKey of(Material type, short durability, MaterialKeySource materialKeySource) {\n        Preconditions.checkArgument(type != Materials.SPAWNER.toBukkitType());\n\n        if (materialKeySource == MaterialKeySource.BLOCK) {\n            MaterialKey[] cachedIds = ID_MATERIAL_KEYS_CACHE.computeIfAbsent(type, MaterialKey::createMaterialKeyCacheForType);\n            if (durability < cachedIds.length) {\n                return cachedIds[durability];\n            }\n        }\n\n        return new MaterialKey(type, durability, false, materialKeySource);\n    }\n\n    public static MaterialKey of(Material type) {\n        return GLOBAL_MATERIAL_KEYS_CACHE.computeIfAbsent(type, unused ->\n                new MaterialKey(type, (short) 0, true, MaterialKeySource.BLOCK));\n    }\n\n    protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource) {\n        this(type, durability, isGlobalType, materialKeySource, false);\n    }\n\n    protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource, boolean apiKey) {\n        super(MaterialKey.class, apiKey);\n        this.type = Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        this.durability = durability;\n        this.durabilityAsString = isGlobalType ? \"\" : String.valueOf(this.durability);\n        this.isGlobalType = isGlobalType;\n        this.materialKeySource = materialKeySource;\n    }\n\n    @Override\n    public String getGlobalKey() {\n        return this.type.name();\n    }\n\n    @Override\n    public MaterialKey toGlobalKey() {\n        return this.isGlobalType ? this : MaterialKey.of(this.type);\n    }\n\n    @Override\n    public String getSubKey() {\n        return this.durabilityAsString;\n    }\n\n    public MaterialKeySource getMaterialKeySource() {\n        return materialKeySource;\n    }\n\n    @Override\n    protected String toStringInternal() {\n        return this.isGlobalType ? this.getGlobalKey() : this.getGlobalKey() + \":\" + this.getSubKey();\n    }\n\n    @Override\n    protected int hashCodeInternal() {\n        return Objects.hashCode(this.type, this.durability);\n    }\n\n    @Override\n    protected boolean equalsInternal(MaterialKey other) {\n        return this.type == other.type && this.durability == other.durability && this.isGlobalType == other.isGlobalType;\n    }\n\n    @Override\n    protected int compareToInternal(MaterialKey other) {\n        return this.toString().compareTo(other.toString());\n    }\n\n    @Override\n    public MaterialKey createAPIKeyInternal() {\n        return this.apiKeyCache.get();\n    }\n\n    protected MaterialKey createAPIKeyForCacheInternal() {\n        return new MaterialKey(MaterialKey.this.type, MaterialKey.this.durability, MaterialKey.this.isGlobalType,\n                MaterialKey.this.materialKeySource, true);\n    }\n\n    public Material getMaterial() {\n        return this.type;\n    }\n\n    public short getDurability() {\n        return this.durability;\n    }\n\n    private static MaterialKey[] createMaterialKeyCacheForType(Material type) {\n        MaterialKey[] cache = new MaterialKey[plugin.getNMSAlgorithms().getMaxBlockDataValue(type) + 1];\n        for (int i = 0; i < cache.length; ++i)\n            cache[i] = new MaterialKey(type, (short) i, false, MaterialKeySource.BLOCK);\n        return cache;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java",
    "content": "package com.bgsoftware.superiorskyblock.core.key.types;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.MaterialKeySource;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.google.common.base.Objects;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\n\npublic class SpawnerKey extends MaterialKey {\n\n    private static final Material SPAWNER_TYPE = Materials.SPAWNER.toBukkitType();\n\n    private static final KeyMap<SpawnerKey> SPAWNER_KEYS_CACHE = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n    public static final SpawnerKey GLOBAL_KEY = new SpawnerKey(null);\n\n    static {\n        // Load all spawner type keys\n        for (EntityType entityType : EntityType.values()) {\n            SpawnerKey spawnerKey = of(Keys.of(entityType));\n            spawnerKey.loadLazyCaches();\n        }\n    }\n\n    private final Key spawnerTypeKey;\n\n    public static SpawnerKey of(@Nullable Key spawnerTypeKey) {\n        return spawnerTypeKey == null ? GLOBAL_KEY : SPAWNER_KEYS_CACHE.computeIfAbsent(spawnerTypeKey, SpawnerKey::new);\n    }\n\n    private SpawnerKey(@Nullable Key spawnerTypeKey) {\n        this(spawnerTypeKey, false);\n    }\n\n    private SpawnerKey(@Nullable Key spawnerTypeKey, boolean apiKey) {\n        super(SPAWNER_TYPE, (short) 0, spawnerTypeKey == null, MaterialKeySource.BLOCK, apiKey);\n        this.spawnerTypeKey = spawnerTypeKey;\n    }\n\n    @Override\n    public SpawnerKey toGlobalKey() {\n        return GLOBAL_KEY;\n    }\n\n    @Override\n    public String getSubKey() {\n        return this.isGlobalType ? \"\" : getSubKeyInternal();\n    }\n\n    @Override\n    protected MaterialKey createAPIKeyForCacheInternal() {\n        return new SpawnerKey(this.spawnerTypeKey, true);\n    }\n\n    private String getSubKeyInternal() {\n        assert this.spawnerTypeKey != null;\n        return this.spawnerTypeKey.toString();\n    }\n\n    @Override\n    protected String toStringInternal() {\n        return this.isGlobalType ? this.getGlobalKey() : this.getGlobalKey() + \":\" + this.getSubKeyInternal();\n    }\n\n    @Override\n    protected int hashCodeInternal() {\n        return Objects.hashCode(SPAWNER_TYPE, this.spawnerTypeKey);\n    }\n\n    @Override\n    protected boolean equalsInternal(MaterialKey other) {\n        if (other instanceof SpawnerKey) {\n            return Objects.equal(this.spawnerTypeKey, ((SpawnerKey) other).spawnerTypeKey);\n        }\n\n        return this.isGlobalType && other.isGlobalType && other.type == SPAWNER_TYPE;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java",
    "content": "package com.bgsoftware.superiorskyblock.core.logging;\n\nimport java.util.Locale;\n\npublic enum Debug {\n\n    ADD_COOP,\n    ADD_MEMBER,\n    BAN_PLAYER,\n    BLOCK_BREAK,\n    BLOCK_COUNT_DECREASE,\n    BLOCK_COUNT_INCREASE,\n    BLOCK_PLACE,\n    CALCULATE_ALL_ISLANDS,\n    CALCULATE_ISLAND,\n    CHUNK_CALCULATION_BLOCKS,\n    CHUNK_CALCULATION_ENTITIES,\n    CLEAR_BLOCK_LIMITS,\n    CLEAR_ENTITY_LIMITS,\n    CLEAR_GENERATOR_RATES,\n    CLEAR_ISLAND_EFFECTS,\n    CREATE_ISLAND,\n    CREATE_WARP,\n    CREATE_WARP_CATEGORY,\n    DATABASE_QUERY,\n    DELETE_ISLAND,\n    DELETE_WARP,\n    DELETE_WARP_CATEGORY,\n    DEPOSIT_MONEY,\n    DISABLE_ISLAND_FLAG,\n    DISABLE_REDSTONE,\n    ENABLE_ISLAND_FLAG,\n    ENTER_ISLAND,\n    ENTITY_DESPAWN,\n    ENTITY_SPAWN,\n    EXECUTE_COMMAND,\n    EXECUTE_ISLAND_COMMANDS,\n    FIND_SAFE_TELEPORT,\n    FIRE_EVENT,\n    GENERATE_BLOCK,\n    GET_VALUE,\n    GIVE_BANK_INTEREST,\n    INVITE_MEMBER,\n    ISLAND_ACTIVE,\n    KICK_MEMBER,\n    LEAVE_ISLAND,\n    LOAD_CHUNK,\n    MENU_CLICK,\n    OPEN_MENU,\n    PASTE_SCHEMATIC,\n    PERMISSION_LOOKUP,\n    PURGE_ISLAND,\n    REGISTER_SORTING_TYPE,\n    REMOVE_BLOCK_LIMIT,\n    REMOVE_COOP,\n    REMOVE_ENTITY_LIMIT,\n    REMOVE_GENERATOR_RATE,\n    REMOVE_ISLAND_EFFECT,\n    REMOVE_PLAYER_STATUS,\n    REMOVE_RATING,\n    REMOVE_RATINGS,\n    REMOVE_ROLE_LIMIT,\n    REPLACE_PLAYER,\n    RESET_ISLAND_FLAGS,\n    RESET_PERMISSIONS,\n    REVOKE_INVITE,\n    REWARD_MISSION,\n    SAVE_SCHEMATIC,\n    SEND_MESSAGE,\n    SEND_TITLE,\n    SET_ADMIN_BYPASS,\n    SET_ADMIN_SPY,\n    SET_BANK_LIMIT,\n    SET_BIOME,\n    SET_BLOCK_AMOUNT,\n    SET_BLOCK_LIMIT,\n    SET_BONUS_LEVEL,\n    SET_BONUS_WORTH,\n    SET_BORDER_COLOR,\n    SET_COOP_LIMIT,\n    SET_CROP_GROWTH,\n    SET_DESCRIPTION,\n    SET_DIMENSION_ENABLED,\n    SET_DISBANDS,\n    SET_DISCORD,\n    SET_ENTITY_LIMIT,\n    SET_GENERATOR_PERCENTAGE,\n    SET_GENERATOR_RATE,\n    SET_IGNORED,\n    SET_ISLAND_EFFECT,\n    SET_ISLAND_FLY,\n    SET_ISLAND_HOME,\n    SET_ISLAND_LAST_TIME_UPDATED,\n    SET_ISLAND_MISSION_COMPLETED,\n    SET_LANGUAGE,\n    SET_LAST_ISLAND,\n    SET_LOCKED,\n    SET_MOB_DROPS,\n    SET_NAME,\n    SET_PAYPAL,\n    SET_PERMISSION,\n    SET_PLAYER_ISLAND,\n    SET_PLAYER_LAST_TIME_UPDATED,\n    SET_PLAYER_MISSION_COMPLETED,\n    SET_PLAYER_ROLE,\n    SET_PLAYER_STATUS,\n    SET_RATING,\n    SET_ROLE_LIMIT,\n    SET_SCHEMATIC,\n    SET_SCHEMATIC_POSITION,\n    SET_SIZE,\n    SET_SPAWNER_RATES,\n    SET_TEAM_CHAT,\n    SET_TEAM_LIMIT,\n    SET_TEXTURE_VALUE,\n    SET_TOGGLED_BORDER,\n    SET_TOGGLED_PANEL,\n    SET_TOGGLED_SCHEMATIC,\n    SET_TOGGLED_STACKER,\n    SET_UPGRADE,\n    SET_VISITOR_HOME,\n    SET_WARPS_LIMIT,\n    SET_WARP_CATEGORY_ICON,\n    SET_WARP_CATEGORY_NAME,\n    SET_WARP_CATEGORY_SLOT,\n    SET_WARP_ICON,\n    SET_WARP_LOCATION,\n    SET_WARP_NAME,\n    SET_WARP_PRIVATE,\n    SORT_ISLANDS,\n    TELEPORT_PLAYER,\n    TRACK_TASK,\n    TRANSFER_ISLAND,\n    UNBAN_PLAYER,\n    UNPURGE_ISLAND,\n    UPDATE_BORDER,\n    VOID_TELEPORT,\n    WITHDRAW_MONEY,\n\n    SHOW_STACKTRACE,\n    PROFILER;\n\n    private static String[] DEBUG_NAMES = null;\n\n    public static String[] getDebugNames() {\n        if (DEBUG_NAMES == null) {\n            Debug[] debugs = Debug.values();\n            DEBUG_NAMES = new String[debugs.length];\n            for (int i = 0; i < debugs.length; ++i)\n                DEBUG_NAMES[i] = debugs[i].name().toLowerCase(Locale.ENGLISH);\n        }\n\n        return DEBUG_NAMES;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java",
    "content": "package com.bgsoftware.superiorskyblock.core.logging;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.EnumSet;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic class Log {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final Logger LOGGER = initializeLogger();\n\n    private static final EnumSet<Debug> DEBUG_FILTERS = EnumSet.noneOf(Debug.class);\n    private static boolean debugMode = false;\n\n    private static Logger initializeLogger() {\n        Logger logger = Logger.getLogger(\"SuperiorSkyblock2\");\n\n        logger.setParent(plugin.getLogger());\n        logger.setUseParentHandlers(true);\n\n        File logsFolder = new File(plugin.getDataFolder(), \"logs\");\n        File archiveLogsFile = new File(logsFolder, \"archive\");\n\n        ModuleLoggerFileHandler.addToLogger(logsFolder, archiveLogsFile, logger);\n\n        return logger;\n    }\n\n    private Log() {\n\n    }\n\n    public static void info(Object first, Object... parts) {\n        logInternal(Level.INFO, first, parts);\n    }\n\n    public static void warn(Object first, Object... parts) {\n        logInternal(Level.WARNING, first, parts);\n    }\n\n    public static void warnFromFile(String fileName, Object first, Object... parts) {\n        logInternalWithFile(Level.WARNING, fileName, first, parts);\n    }\n\n    public static void error(Object first, Object... parts) {\n        logInternal(Level.SEVERE, first, parts);\n    }\n\n    public static void error(Throwable error, Object first, Object... parts) {\n        error(first, parts);\n        printStackTrace(error);\n    }\n\n    public static void errorFromFile(String fileName, Object first, Object... parts) {\n        logInternalWithFile(Level.SEVERE, fileName, first, parts);\n    }\n\n    public static void errorFromFile(Throwable error, String fileName, Object first, Object... parts) {\n        errorFromFile(fileName, first, parts);\n        printStackTrace(error);\n    }\n\n    public static void profile(String[] profiledDataLines) {\n        if (!isDebugged(Debug.PROFILER))\n            return;\n\n        for (String line : profiledDataLines)\n            logInternal(Level.INFO, line);\n    }\n\n    public static void debug(Debug debug, Object... params) {\n        if (isDebugged(debug)) {\n            String[] classAndMethod = getClassAndMethodNames();\n            enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], null, params);\n            if (isDebugged(Debug.SHOW_STACKTRACE))\n                printStackTrace();\n        }\n    }\n\n    public static void debugResult(Debug debug, @Nullable String message, Object result) {\n        if (isDebugged(debug)) {\n            String[] classAndMethod = getClassAndMethodNames();\n            enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], message, result);\n            if (isDebugged(Debug.SHOW_STACKTRACE))\n                printStackTrace();\n        }\n    }\n\n    public static void entering(@Nullable String message, Object... params) {\n        String[] classAndMethod = getClassAndMethodNames();\n        enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], message, params);\n    }\n\n    public static boolean isDebugMode() {\n        return debugMode;\n    }\n\n    public static boolean isDebugged(Debug debug) {\n        return debugMode && DEBUG_FILTERS.contains(debug);\n    }\n\n    public static void toggleDebugMode() {\n        debugMode = !debugMode;\n    }\n\n    public static void setDebugFilter(@Nullable Debug debugFilter) {\n        if (debugFilter == null) {\n            DEBUG_FILTERS.clear();\n        } else if (DEBUG_FILTERS.contains(debugFilter)) {\n            DEBUG_FILTERS.remove(debugFilter);\n        } else {\n            DEBUG_FILTERS.add(debugFilter);\n        }\n    }\n\n    private static void enteringInternal(Level level, String clazz, String method, @Nullable String message, Object... params) {\n        StringBuilder paramsMessage = new StringBuilder();\n        for (Object param : params)\n            paramsMessage.append(\" {\").append(param).append(\"}\");\n        logInternal(level, clazz, \"::\", method, message == null ? \"\" : \" \" + message, paramsMessage.toString());\n    }\n\n    private static void logInternalWithFile(Level level, String fileName, Object first, Object... parts) {\n        LOGGER.log(level, buildFromPartsWithFile(fileName, first, parts));\n    }\n\n    private static void logInternal(Level level, Object first, Object... parts) {\n        LOGGER.log(level, buildFromParts(first, parts));\n    }\n\n    private static String buildFromParts(Object first, Object... parts) {\n        StringBuilder builder = new StringBuilder().append(first);\n        for (Object part : parts)\n            builder.append(part);\n        return builder.toString();\n    }\n\n    private static String buildFromPartsWithFile(String prefixFile, Object first, Object... parts) {\n        StringBuilder builder = new StringBuilder(\"[\").append(prefixFile).append(\"] \").append(first);\n        for (Object part : parts)\n            builder.append(part);\n        return builder.toString();\n    }\n\n    private static String[] getClassAndMethodNames() {\n        StackTraceElement currentElement = Thread.currentThread().getStackTrace()[3];\n\n        String methodName = currentElement.getMethodName();\n        if (methodName.contains(\"lambda\")) {\n            methodName = methodName.split(\"\\\\$\")[1];\n        }\n\n        String className = currentElement.getClassName();\n\n        return new String[]{className.substring(className.lastIndexOf(\".\") + 1), methodName};\n    }\n\n    private static void printStackTrace() {\n        printStackTrace(new Exception(\"Stack trace\"));\n    }\n\n    private static void printStackTrace(Throwable error) {\n        StringWriter buffer = new StringWriter();\n        PrintWriter pw = new PrintWriter(buffer);\n        error.printStackTrace(pw);\n        LOGGER.log(Level.SEVERE, buffer.toString());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/logging/StackTrace.java",
    "content": "package com.bgsoftware.superiorskyblock.core.logging;\n\npublic class StackTrace {\n\n    private final StackTraceHolder stackTrace = new StackTraceHolder();\n\n    public void dump() {\n        this.stackTrace.printStackTrace();\n    }\n\n    private static class StackTraceHolder extends Throwable {\n\n        @Override\n        public String toString() {\n            return \"Original Stacktrace:\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/AbstractMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.BaseMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\nimport org.bukkit.inventory.Inventory;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic abstract class AbstractMenu<V extends AbstractMenuView<V, A>, A extends ViewArgs> extends BaseMenu<V, A> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    protected AbstractMenu(String identifier, MenuParseResult<V> parseResult) {\n        super(identifier, parseResult.getLayoutBuilder().build(), parseResult.getOpeningSound(),\n                parseResult.isPreviousMoveAllowed(), parseResult.isSkipOneItem());\n    }\n\n    @Override\n    public final CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args) {\n        return super.createView(superiorPlayer, args);\n    }\n\n    @Override\n    public final CompletableFuture<V> createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView<?, ?> previousMenu) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkState(superiorPlayer.isOnline(), \"Cannot create view for offline player: \" + superiorPlayer.getName());\n        Preconditions.checkNotNull(args, \"args parameter cannot be null.\");\n        V view = createViewInternal(superiorPlayer, args, previousMenu);\n        addView(view);\n        return refreshView(view);\n    }\n\n    @Override\n    public void onClick(InventoryClickEvent clickEvent, V menuView) {\n        if (!menuView.isRefreshing())\n            super.onClick(clickEvent, menuView);\n    }\n\n    @Override\n    protected void onCloseInternal(InventoryCloseEvent closeEvent, V menuView) {\n        menuView.onClose();\n    }\n\n    protected abstract V createViewInternal(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView<?, ?> previousMenu);\n\n    public CompletableFuture<V> refreshView(V view) {\n        CompletableFuture<V> res = new CompletableFuture<>();\n        buildInventory(view).whenComplete((inventory, error) -> {\n            if (error != null) {\n                res.completeExceptionally(error);\n            } else {\n                BukkitExecutor.sync(() -> {\n                    view.setInventory(inventory);\n                    res.complete(view);\n                });\n            }\n        });\n        return res;\n    }\n\n    public CompletableFuture<Inventory> buildInventory(V menuView) {\n        if (!Bukkit.isPrimaryThread()) {\n            return CompletableFuture.completedFuture(this.menuLayout.buildInventory(menuView));\n        }\n\n        CompletableFuture<Inventory> inventoryFuture = new CompletableFuture<>();\n        BukkitExecutor.async(() -> inventoryFuture.complete(this.menuLayout.buildInventory(menuView)));\n        return inventoryFuture;\n    }\n\n    @Override\n    protected void onButtonClickLackPermission(MenuViewButton<V> menuButton, InventoryClickEvent clickEvent) {\n        if (menuButton instanceof AbstractMenuViewButton)\n            ((AbstractMenuViewButton<V>) menuButton).onButtonClickLackPermission(clickEvent);\n    }\n\n    protected boolean onPreButtonClick(MenuViewButton<V> menuButton, InventoryClickEvent clickEvent) {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/AbstractPagedMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.superiorskyblock.api.menu.PagedMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\n\npublic abstract class AbstractPagedMenu<V extends AbstractPagedMenuView<V, A, E>, A extends ViewArgs, E>\n        extends AbstractMenu<V, A> implements PagedMenu<V, A, E> {\n\n    private final boolean acceptNull;\n\n    protected AbstractPagedMenu(String identifier, MenuParseResult<V> parseResult, boolean acceptNull) {\n        super(identifier, parseResult);\n        Preconditions.checkState(parseResult.getLayoutBuilder() instanceof PagedMenuLayout.Builder, \"Paged menu \" + identifier + \" doesn't use the correct layout.\");\n        this.acceptNull = acceptNull;\n    }\n\n    @Override\n    public boolean onPreButtonClick(MenuViewButton<V> menuButton, InventoryClickEvent clickEvent) {\n        if (!(menuButton instanceof PagedMenuViewButton))\n            return true;\n\n        MenuLayout<V> menuLayout = getLayout();\n\n        if (!(menuLayout instanceof PagedMenuLayout))\n            return false;\n\n        PagedMenuViewButton<V, E> pagedMenuButton = (PagedMenuViewButton<V, E>) menuButton;\n\n        V menuView = menuButton.getView();\n\n        menuView.updatePagedObjects();\n        List<E> pagedObjects = menuView.getPagedObjects();\n\n        int objectsPerPage = ((PagedMenuLayout<V>) menuLayout).getObjectsPerPageCount();\n\n        int currentPage = menuView.getCurrentPage();\n\n        int objectIndex = ((PagedMenuTemplateButton<V, E>) pagedMenuButton.getTemplate()).getButtonIndex() + (objectsPerPage * (currentPage - 1));\n\n        if (objectIndex >= pagedObjects.size()) {\n            if (this.acceptNull)\n                pagedMenuButton.updateObject(null);\n            return this.acceptNull;\n        }\n\n        pagedMenuButton.updateObject(pagedObjects.get(objectIndex));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\nimport java.math.BigDecimal;\nimport java.util.Locale;\n\npublic class MenuActions {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static void handleDeposit(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction,\n                                     @Nullable GameSound successSound, @Nullable GameSound failSound, BigDecimal amount) {\n        if (bankTransaction.getFailureReason().isEmpty()) {\n            superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound));\n        } else {\n            superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound));\n\n            String failureReason = bankTransaction.getFailureReason();\n\n            if (!failureReason.isEmpty()) {\n                switch (failureReason) {\n                    case \"No permission\":\n                        Message.NO_DEPOSIT_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.DEPOSIT_MONEY));\n                        break;\n                    case \"Invalid amount\":\n                        Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount));\n                        break;\n                    case \"Not enough money\":\n                        Message.NOT_ENOUGH_MONEY_TO_DEPOSIT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount));\n                        break;\n                    case \"Exceed bank limit\":\n                        Message.BANK_LIMIT_EXCEED.send(superiorPlayer);\n                        break;\n                    case \"Vault is not installed\":\n                        Message.VAULT_NOT_INSTALLED.send(superiorPlayer);\n                        break;\n                    default:\n                        Message.DEPOSIT_ERROR.send(superiorPlayer, failureReason);\n                        break;\n                }\n            }\n        }\n    }\n\n    public static void handleWithdraw(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction,\n                                      GameSound successSound, GameSound failSound, BigDecimal amount) {\n        if (bankTransaction.getFailureReason().isEmpty()) {\n            superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound));\n        } else {\n            superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound));\n\n            String failureReason = bankTransaction.getFailureReason();\n\n            if (!failureReason.isEmpty()) {\n                switch (failureReason) {\n                    case \"No permission\":\n                        Message.NO_WITHDRAW_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.WITHDRAW_MONEY));\n                        break;\n                    case \"Invalid amount\":\n                        Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount));\n                        break;\n                    case \"Bank is empty\":\n                        Message.ISLAND_BANK_EMPTY.send(superiorPlayer);\n                        break;\n                    case \"Vault is not installed\":\n                        Message.VAULT_NOT_INSTALLED.send(superiorPlayer);\n                        break;\n                    default:\n                        Message.WITHDRAW_ERROR.send(superiorPlayer, failureReason);\n                        break;\n                }\n            }\n        }\n    }\n\n    public static void simulateIslandCreationClick(SuperiorPlayer clickedPlayer, String islandName,\n                                                   MenuIslandCreationConfig creationConfig, boolean isPreviewMode,\n                                                   @Nullable MenuView<?, ?> menuView) {\n        Schematic schematic = creationConfig.getSchematic();\n\n        // Checking for preview of islands.\n        if (isPreviewMode) {\n            Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH));\n            if (previewLocation != null) {\n                plugin.getGrid().startIslandPreview(clickedPlayer, schematic, islandName);\n                return;\n            }\n        }\n\n        Player whoClicked = clickedPlayer.asPlayer();\n\n        GameSoundImpl.playSound(whoClicked, creationConfig.getSound());\n\n        creationConfig.getCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", clickedPlayer.getName())));\n\n        Message.ISLAND_CREATE_PROCCESS_REQUEST.send(clickedPlayer);\n\n        if (menuView != null)\n            menuView.closeView();\n\n        Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n        boolean offset = creationConfig.shouldOffsetIslandValue() ||\n                plugin.getSettings().getWorlds().getDimensionConfig(dimension).isSchematicOffset();\n\n        BlockOffset spawnOffset = creationConfig.getSpawnOffset();\n\n        plugin.getGrid().createIsland(clickedPlayer, schematic.getName(), creationConfig.getBonusWorth(),\n                creationConfig.getBonusLevel(), creationConfig.getBiome(), islandName, offset, spawnOffset);\n    }\n\n    public static void simulateWarpsClick(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) {\n        BukkitExecutor.sync(() -> {\n            superiorPlayer.runIfOnline(player -> {\n                MenuView<?, ?> currentView = superiorPlayer.getOpenedView();\n                if (currentView == null) {\n                    player.closeInventory();\n                } else {\n                    currentView.closeView();\n                }\n                island.warpPlayer(superiorPlayer, islandWarp.getName());\n            });\n        }, 1L);\n    }\n\n    private MenuActions() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuCommands;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MenuCommandsImpl implements MenuCommands {\n\n    private static final MenuCommandsImpl INSTANCE = new MenuCommandsImpl();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private static final Pattern COMMAND_PATTERN_ARGS = Pattern.compile(\"\\\\[(.+)](.+)\");\n    private static final Pattern COMMAND_PATTERN = Pattern.compile(\"\\\\[(.+)]\");\n\n    public static MenuCommandsImpl getInstance() {\n        return INSTANCE;\n    }\n\n    private MenuCommandsImpl() {\n\n    }\n\n    @Override\n    public void runCommand(MenuView<?, ?> menuView, String command, InventoryClickEvent clickEvent) {\n        this.runCommand(menuView, command, clickEvent, Bukkit.getConsoleSender());\n    }\n\n    private void runCommand(MenuView<?, ?> menuView, String command, InventoryClickEvent clickEvent, CommandSender sender) {\n        Matcher matcher = COMMAND_PATTERN_ARGS.matcher(command);\n\n        if (matcher.matches()) {\n            String subCommand = matcher.group(1);\n            String args = matcher.group(2).trim();\n            handleSubCommand(menuView, subCommand, args, clickEvent, sender);\n        } else if ((matcher = COMMAND_PATTERN.matcher(command)).matches()) {\n            String subCommand = matcher.group(1);\n            handleSubCommand(menuView, subCommand, \"\", clickEvent, sender);\n        } else if (command.equalsIgnoreCase(\"close\")) {\n            setClickedCloseButton(menuView);\n            menuView.closeView();\n        } else if (command.equalsIgnoreCase(\"back\")) {\n            setClickedCloseButton(menuView);\n            clickEvent.getWhoClicked().closeInventory();\n        } else {\n            SuperiorPlayer targetPlayer = menuView instanceof IPlayerMenuView ?\n                    ((IPlayerMenuView) menuView).getSuperiorPlayer() : null;\n\n            if (targetPlayer != null)\n                command = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), command);\n            else if (sender instanceof Player)\n                command = placeholdersService.get().parsePlaceholders((Player) sender, command);\n\n            Bukkit.dispatchCommand(sender instanceof Player || command.startsWith(\"PLAYER:\") ? clickEvent.getWhoClicked() : Bukkit.getConsoleSender(),\n                    command.replace(\"PLAYER:\", \"\").replace(\"%player%\", clickEvent.getWhoClicked().getName()));\n        }\n    }\n\n    private void handleSubCommand(MenuView<?, ?> menuView, String subCommand, String args,\n                                  InventoryClickEvent clickEvent, CommandSender sender) {\n        switch (subCommand.toLowerCase(Locale.ENGLISH)) {\n            case \"player\":\n                runCommand(menuView, args, clickEvent, clickEvent.getWhoClicked());\n                break;\n            case \"admin\":\n                String commandLabel = plugin.getSettings().getIslandCommand().split(\",\")[0];\n                runCommand(menuView, commandLabel + \" admin \" + args, clickEvent, sender);\n                break;\n            case \"close\":\n                setClickedCloseButton(menuView);\n                menuView.closeView();\n                clickEvent.getWhoClicked().closeInventory();\n                break;\n            case \"back\":\n                setClickedCloseButton(menuView);\n                clickEvent.getWhoClicked().closeInventory();\n                break;\n            default:\n                plugin.getCommands().dispatchSubCommand(sender, subCommand, args);\n                break;\n        }\n    }\n\n    private static void setClickedCloseButton(MenuView<?, ?> menuView) {\n        if (menuView instanceof AbstractMenuView)\n            ((AbstractMenuView<?, ?>) menuView).setClickedCloseButton();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton;\nimport org.bukkit.block.Biome;\n\nimport java.math.BigDecimal;\nimport java.util.Collection;\nimport java.util.Collections;\n\npublic class MenuConfig {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private MenuConfig() {\n\n    }\n\n    public static class IslandCreation implements MenuIslandCreationConfig {\n\n        private final Schematic schematic;\n        @Nullable\n        private final IslandCreationButton.Template template;\n        private final Biome biome;\n\n        public IslandCreation(IslandCreationButton.Template template) {\n            this(template.getSchematic(), template);\n        }\n\n        public IslandCreation(Schematic schematic, IslandCreationButton.Template template) {\n            this.schematic = schematic;\n            this.template = template;\n            Biome biome = template == null ? null : template.getBiome();\n            this.biome = biome == null ? plugin.getNMSAlgorithms().getBiome(plugin.getSettings().getWorlds().getDimensionConfig(\n                    plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : biome;\n        }\n\n        @Override\n        public Schematic getSchematic() {\n            return this.schematic;\n        }\n\n        @Override\n        public GameSound getSound() {\n            return this.template == null ? null : this.template.getAccessSound();\n        }\n\n        @Override\n        public Collection<String> getCommands() {\n            return this.template == null ? Collections.emptyList() : this.template.getAccessCommands();\n        }\n\n        @Override\n        public boolean shouldOffsetIslandValue() {\n            return this.template != null && this.template.isOffset();\n        }\n\n        @Override\n        public BlockOffset getSpawnOffset() {\n            return this.template == null ? null : this.template.getSpawnOffset();\n        }\n\n        @Override\n        public BigDecimal getBonusWorth() {\n            return this.template == null ? BigDecimal.ZERO : this.template.getBonusWorth();\n        }\n\n        @Override\n        public BigDecimal getBonusLevel() {\n            return this.template == null ? BigDecimal.ZERO : this.template.getBonusLevel();\n        }\n\n        @Override\n        public Biome getBiome() {\n            return this.biome;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\npublic class MenuIdentifiers {\n\n    public static final String MENU_BANK_LOGS = \"MenuBankLogs\";\n    public static final String MENU_BIOMES = \"MenuBiomes\";\n    public static final String MENU_BLANK = \"MenuBlank\";\n    public static final String MENU_BORDER_COLOR = \"MenuBorderColor\";\n    public static final String MENU_CONFIG_EDITOR = \"MenuConfigEditor\";\n    public static final String MENU_CONFIRM_BAN = \"MenuConfirmBan\";\n    public static final String MENU_CONFIRM_DISBAND = \"MenuConfirmDisband\";\n    public static final String MENU_CONFIRM_KICK = \"MenuConfirmKick\";\n    public static final String MENU_CONFIRM_LEAVE = \"MenuConfirmLeave\";\n    public static final String MENU_CONFIRM_TRANSFER = \"MenuConfirmTransfer\";\n    public static final String MENU_CONTROL_PANEL = \"MenuControlPanel\";\n    public static final String MENU_COOPS = \"MenuCoops\";\n    public static final String MENU_COUNTS = \"MenuCounts\";\n    public static final String MENU_CUSTOM_PREFIX = \"MenuCustom_\";\n    public static final String MENU_GLOBAL_WARPS = \"MenuGlobalWarps\";\n    public static final String MENU_ISLAND_BANK = \"MenuIslandBank\";\n    public static final String MENU_ISLAND_BANNED_PLAYERS = \"MenuIslandBannedPlayers\";\n    public static final String MENU_ISLAND_CHEST = \"MenuIslandChest\";\n    public static final String MENU_ISLAND_CREATION = \"MenuIslandCreation\";\n    public static final String MENU_ISLAND_FLAGS = \"MenuIslandFlags\";\n    public static final String MENU_ISLAND_MEMBERS = \"MenuIslandMembers\";\n    public static final String MENU_ISLAND_PRIVILEGES = \"MenuIslandPrivileges\";\n    public static final String MENU_ISLAND_RATE = \"MenuIslandRate\";\n    public static final String MENU_ISLAND_RATINGS = \"MenuIslandRatings\";\n    public static final String MENU_ISLAND_UNIQUE_VISITORS = \"MenuUniqueVisitors\";\n    public static final String MENU_ISLAND_UPGRADES = \"MenuIslandUpgrades\";\n    public static final String MENU_ISLAND_VALUES = \"MenuIslandValues\";\n    public static final String MENU_ISLAND_VISITORS = \"MenuIslandVisitors\";\n    public static final String MENU_MEMBER_MANAGE = \"MenuMemberManage\";\n    public static final String MENU_MEMBER_ROLE = \"MenuMemberRole\";\n    public static final String MENU_MISSIONS = \"MenuMissions\";\n    public static final String MENU_MISSIONS_CATEGORY = \"MenuMissionsCategory\";\n    public static final String MENU_PLAYER_LANGUAGE = \"MenuPlayerLanguage\";\n    public static final String MENU_TOP_ISLANDS = \"MenuTopIslands\";\n    public static final String MENU_WARP_CATEGORIES = \"MenuWarpCategories\";\n    public static final String MENU_WARP_CATEGORIES_ICON_EDIT = \"MenuWarpCategoryIconEdit\";\n    public static final String MENU_WARP_CATEGORIES_MANAGE = \"MenuWarpCategoryManage\";\n    public static final String MENU_WARP_ICON_EDIT = \"MenuWarpIconEdit\";\n    public static final String MENU_WARP_MANAGE = \"MenuWarpManage\";\n    public static final String MENU_WARPS = \"MenuWarps\";\n\n    private MenuIdentifiers() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuParseResult.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.List;\n\npublic class MenuParseResult<V extends MenuView<V, ?>> implements MenuParser.ParseResult<V> {\n\n    private final MenuLayout.Builder<V> menuLayoutBuilder;\n    private final GameSound openingSound;\n    private final boolean isPreviousMoveAllowed;\n    private final boolean isSkipOneItem;\n    private final MenuPatternSlots patternSlots;\n    private final YamlConfiguration config;\n\n    public MenuParseResult(MenuLayout.Builder<V> menuLayoutBuilder) {\n        this(menuLayoutBuilder, null, true, false, null, null);\n    }\n\n    public MenuParseResult(MenuLayout.Builder<V> menuLayoutBuilder, @Nullable GameSound openingSound,\n                           boolean isPreviousMoveAllowed, boolean isSkipOneItem,\n                           MenuPatternSlots patternSlots, YamlConfiguration config) {\n        this.menuLayoutBuilder = menuLayoutBuilder;\n        this.openingSound = openingSound;\n        this.isPreviousMoveAllowed = isPreviousMoveAllowed;\n        this.isSkipOneItem = isSkipOneItem;\n        this.patternSlots = patternSlots;\n        this.config = config;\n    }\n\n    @Override\n    public MenuLayout.Builder<V> getLayoutBuilder() {\n        return menuLayoutBuilder;\n    }\n\n    @Nullable\n    public GameSound getOpeningSound() {\n        return openingSound;\n    }\n\n    @Override\n    public boolean isPreviousMoveAllowed() {\n        return isPreviousMoveAllowed;\n    }\n\n    @Override\n    public boolean isSkipOneItem() {\n        return isSkipOneItem;\n    }\n\n    @Override\n    public List<Integer> getSlotsForChar(char ch) {\n        return patternSlots.getSlots(ch);\n    }\n\n    public MenuPatternSlots getPatternSlots() {\n        return patternSlots;\n    }\n\n    public YamlConfiguration getConfig() {\n        return config;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuPatternSlots.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.collections.view.CharIterator;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class MenuPatternSlots {\n\n    private final Char2ObjectMapView<List<Integer>> charSlots = CollectionsFactory.createChar2ObjectArrayMap();\n\n    public MenuPatternSlots() {\n    }\n\n    public CharIterator getChars() {\n        return this.charSlots.keyIterator();\n    }\n\n    public void addSlot(char character, int slot) {\n        this.charSlots.computeIfAbsent(character, ch -> new LinkedList<>()).add(slot);\n    }\n\n    public List<Integer> getSlots(char character) {\n        List<Integer> slots = this.charSlots.get(character);\n        return slots == null ? Collections.emptyList() : slots;\n    }\n\n    public List<Integer> getSlots(String str) {\n        for (char ch : str.toCharArray()) {\n            List<Integer> slots = getSlots(ch);\n            if (!slots.isEmpty())\n                return slots;\n        }\n\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuBiomes;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuBorderColor;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmDisband;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmLeave;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuControlPanel;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuCoops;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuCounts;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBank;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBannedPlayers;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandChest;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandFlags;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRate;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRatings;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUniqueVisitors;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUpgrades;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandValues;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberManage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberRole;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissions;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuPlayerLanguage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategories;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryIconEdit;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpIconEdit;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuBlank;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\n\npublic class Menus {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static final MenuBlank MENU_BLANK = MenuBlank.createInstance();\n    public static final MenuConfigEditor MENU_CONFIG_EDITOR = MenuConfigEditor.createInstance();\n\n    public static MenuBankLogs MENU_BANK_LOGS;\n    public static MenuBiomes MENU_BIOMES;\n    public static MenuBorderColor MENU_BORDER_COLOR;\n    public static MenuConfirmBan MENU_CONFIRM_BAN;\n    public static MenuConfirmDisband MENU_CONFIRM_DISBAND;\n    public static MenuConfirmKick MENU_CONFIRM_KICK;\n    public static MenuConfirmLeave MENU_CONFIRM_LEAVE;\n    public static MenuConfirmTransfer MENU_CONFIRM_TRANSFER;\n    public static MenuControlPanel MENU_CONTROL_PANEL;\n    public static MenuCoops MENU_COOPS;\n    public static MenuCounts MENU_COUNTS;\n    public static MenuGlobalWarps MENU_GLOBAL_WARPS;\n    public static MenuIslandBank MENU_ISLAND_BANK;\n    public static MenuIslandBannedPlayers MENU_ISLAND_BANNED_PLAYERS;\n    public static MenuIslandChest MENU_ISLAND_CHEST;\n    public static MenuIslandCreation MENU_ISLAND_CREATION;\n    public static MenuIslandFlags MENU_ISLAND_FLAGS;\n    public static MenuIslandMembers MENU_ISLAND_MEMBERS;\n    public static MenuIslandPrivileges MENU_ISLAND_PRIVILEGES;\n    public static MenuIslandRate MENU_ISLAND_RATE;\n    public static MenuIslandRatings MENU_ISLAND_RATINGS;\n    public static MenuIslandUniqueVisitors MENU_ISLAND_UNIQUE_VISITORS;\n    public static MenuIslandUpgrades MENU_ISLAND_UPGRADES;\n    public static MenuIslandValues MENU_ISLAND_VALUES;\n    public static MenuIslandVisitors MENU_ISLAND_VISITORS;\n    public static MenuMemberManage MENU_MEMBER_MANAGE;\n    public static MenuMemberRole MENU_MEMBER_ROLE;\n    public static MenuMissions MENU_MISSIONS;\n    public static MenuMissionsCategory MENU_MISSIONS_CATEGORY;\n    public static MenuPlayerLanguage MENU_PLAYER_LANGUAGE;\n    public static MenuTopIslands MENU_TOP_ISLANDS;\n    public static MenuWarpCategories MENU_WARP_CATEGORIES;\n    public static MenuWarpCategoryIconEdit MENU_WARP_CATEGORY_ICON_EDIT;\n    public static MenuWarpCategoryManage MENU_WARP_CATEGORY_MANAGE;\n    public static MenuWarpIconEdit MENU_WARP_ICON_EDIT;\n    public static MenuWarpManage MENU_WARP_MANAGE;\n    public static MenuWarps MENU_WARPS;\n\n    private Menus() {\n\n    }\n\n    public static void registerMenus() {\n        // We register the internal menus\n        createMenu(MENU_BLANK);\n        createMenu(MENU_CONFIG_EDITOR);\n        // Load menus from files\n        MENU_BANK_LOGS = createMenu(MenuBankLogs.createInstance());\n        MENU_BIOMES = createMenu(MenuBiomes.createInstance());\n        MENU_BORDER_COLOR = createMenu(MenuBorderColor.createInstance());\n        MENU_CONFIRM_BAN = createMenu(MenuConfirmBan.createInstance());\n        MENU_CONFIRM_DISBAND = createMenu(MenuConfirmDisband.createInstance());\n        MENU_CONFIRM_KICK = createMenu(MenuConfirmKick.createInstance());\n        MENU_CONFIRM_LEAVE = createMenu(MenuConfirmLeave.createInstance());\n        MENU_CONFIRM_TRANSFER = createMenu(MenuConfirmTransfer.createInstance());\n        MENU_CONTROL_PANEL = createMenu(MenuControlPanel.createInstance());\n        MENU_COOPS = createMenu(MenuCoops.createInstance());\n        MENU_COUNTS = createMenu(MenuCounts.createInstance());\n        MENU_GLOBAL_WARPS = createMenu(MenuGlobalWarps.createInstance());\n        MENU_ISLAND_BANK = createMenu(MenuIslandBank.createInstance());\n        MENU_ISLAND_BANNED_PLAYERS = createMenu(MenuIslandBannedPlayers.createInstance());\n        MENU_ISLAND_CHEST = createMenu(MenuIslandChest.createInstance());\n        MENU_ISLAND_CREATION = createMenu(MenuIslandCreation.createInstance());\n        MENU_ISLAND_FLAGS = createMenu(MenuIslandFlags.createInstance());\n        MENU_ISLAND_MEMBERS = createMenu(MenuIslandMembers.createInstance());\n        MENU_ISLAND_PRIVILEGES = createMenu(MenuIslandPrivileges.createInstance());\n        MENU_ISLAND_RATE = createMenu(MenuIslandRate.createInstance());\n        MENU_ISLAND_RATINGS = createMenu(MenuIslandRatings.createInstance());\n        MENU_ISLAND_UNIQUE_VISITORS = createMenu(MenuIslandUniqueVisitors.createInstance());\n        MENU_ISLAND_UPGRADES = createMenu(MenuIslandUpgrades.createInstance());\n        MENU_ISLAND_VALUES = createMenu(MenuIslandValues.createInstance());\n        MENU_ISLAND_VISITORS = createMenu(MenuIslandVisitors.createInstance());\n        MENU_MEMBER_MANAGE = createMenu(MenuMemberManage.createInstance());\n        MENU_MEMBER_ROLE = createMenu(MenuMemberRole.createInstance());\n        MENU_MISSIONS = createMenu(MenuMissions.createInstance());\n        MENU_MISSIONS_CATEGORY = createMenu(MenuMissionsCategory.createInstance());\n        MENU_PLAYER_LANGUAGE = createMenu(MenuPlayerLanguage.createInstance());\n        MENU_TOP_ISLANDS = createMenu(MenuTopIslands.createInstance());\n        MENU_WARP_CATEGORIES = createMenu(MenuWarpCategories.createInstance());\n        MENU_WARP_CATEGORY_ICON_EDIT = createMenu(MenuWarpCategoryIconEdit.createInstance());\n        MENU_WARP_CATEGORY_MANAGE = createMenu(MenuWarpCategoryManage.createInstance());\n        MENU_WARP_ICON_EDIT = createMenu(MenuWarpIconEdit.createInstance());\n        MENU_WARP_MANAGE = createMenu(MenuWarpManage.createInstance());\n        MENU_WARPS = createMenu(MenuWarps.createInstance());\n    }\n\n    private static <M extends AbstractMenu<V, A>, V extends AbstractMenuView<V, A>, A extends ViewArgs> M createMenu(M menu) {\n        if (menu == null)\n            throw new IllegalStateException(\"Menu could not be initialized.\");\n\n        plugin.getMenus().registerMenu(menu);\n        return menu;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.MenusManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuCommands;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class MenusManagerImpl extends Manager implements MenusManager {\n\n    private final Map<String, Menu<?, ?>> registeredMenus = new HashMap<>();\n\n    public MenusManagerImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadData() {\n        plugin.getProviders().getMenusProvider().initializeMenus();\n    }\n\n    @Override\n    public void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openBankLogs(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshBankLogs(Island island) {\n        plugin.getProviders().getMenusProvider().refreshBankLogs(island);\n    }\n\n    @Override\n    public void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openBiomes(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandBiomesMenu(SuperiorPlayer superiorPlayer) {\n        openBiomes(superiorPlayer, null, superiorPlayer.getIsland());\n    }\n\n    @Override\n    public void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        plugin.getProviders().getMenusProvider().openBorderColor(targetPlayer, previousMenu);\n    }\n\n    @Override\n    public void openBorderColorMenu(SuperiorPlayer superiorPlayer) {\n        openBorderColor(superiorPlayer, null);\n    }\n\n    @Override\n    public void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer) {\n        plugin.getProviders().getMenusProvider().openConfirmBan(targetPlayer, previousMenu, targetIsland, bannedPlayer);\n    }\n\n    @Override\n    public void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openConfirmDisband(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openConfirmDisbandMenu(SuperiorPlayer superiorPlayer) {\n        openConfirmDisband(superiorPlayer, null, superiorPlayer.getIsland());\n    }\n\n    @Override\n    public void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer) {\n        plugin.getProviders().getMenusProvider().openConfirmKick(targetPlayer, previousMenu, targetIsland, kickedPlayer);\n    }\n\n    @Override\n    public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        plugin.getProviders().getMenusProvider().openConfirmLeave(targetPlayer, previousMenu);\n    }\n\n    @Override\n    public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) {\n        plugin.getProviders().getMenusProvider().openConfirmTransfer(targetPlayer, previousMenu, targetIsland, newOwner);\n    }\n\n    @Override\n    public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openControlPanel(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandPanelMenu(SuperiorPlayer superiorPlayer) {\n        openControlPanel(superiorPlayer, null, superiorPlayer.getIsland());\n    }\n\n    @Override\n    public void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openCoops(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshCoops(Island island) {\n        plugin.getProviders().getMenusProvider().refreshCoops(island);\n    }\n\n    @Override\n    public void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openCounts(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandCountsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openCounts(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshCounts(Island island) {\n        plugin.getProviders().getMenusProvider().refreshCounts(island);\n    }\n\n    @Override\n    public void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        plugin.getProviders().getMenusProvider().openGlobalWarps(targetPlayer, previousMenu);\n    }\n\n    @Override\n    public void openGlobalWarpsMenu(SuperiorPlayer superiorPlayer) {\n        openGlobalWarps(superiorPlayer, null);\n    }\n\n    @Override\n    public void refreshGlobalWarps() {\n        plugin.getProviders().getMenusProvider().refreshGlobalWarps();\n    }\n\n    @Override\n    public void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openIslandBank(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshIslandBank(Island island) {\n        plugin.getProviders().getMenusProvider().refreshIslandBank(island);\n    }\n\n    @Override\n    public void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openIslandBannedPlayers(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshIslandBannedPlayers(Island island) {\n        plugin.getProviders().getMenusProvider().refreshIslandBannedPlayers(island);\n    }\n\n    @Override\n    public void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openIslandChest(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshIslandChest(Island island) {\n        plugin.getProviders().getMenusProvider().refreshIslandChest(island);\n    }\n\n    @Override\n    public void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName) {\n        plugin.getProviders().getMenusProvider().openIslandCreation(targetPlayer, previousMenu, islandName);\n    }\n\n    @Override\n    public void openIslandCreationMenu(SuperiorPlayer superiorPlayer, String islandName) {\n        openIslandCreation(superiorPlayer, null, islandName);\n    }\n\n    @Override\n    public void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openIslandRate(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandRateMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openIslandRate(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openIslandRatings(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandRatingsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openIslandRatings(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshIslandRatings(Island island) {\n        plugin.getProviders().getMenusProvider().refreshIslandRatings(island);\n    }\n\n    @Override\n    public void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) {\n        plugin.getProviders().getMenusProvider().openMemberManage(targetPlayer, previousMenu, islandMember);\n    }\n\n    @Override\n    public void openMemberManageMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        openMemberManage(superiorPlayer, null, targetPlayer);\n    }\n\n    @Override\n    public void destroyMemberManage(SuperiorPlayer islandMember) {\n        plugin.getProviders().getMenusProvider().destroyMemberManage(islandMember);\n    }\n\n    @Override\n    public void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) {\n        plugin.getProviders().getMenusProvider().openMemberRole(targetPlayer, previousMenu, islandMember);\n    }\n\n    @Override\n    public void openMemberRoleMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) {\n        openMemberRole(superiorPlayer, null, targetPlayer);\n    }\n\n    @Override\n    public void destroyMemberRole(SuperiorPlayer islandMember) {\n        plugin.getProviders().getMenusProvider().destroyMemberRole(islandMember);\n    }\n\n    @Override\n    public void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openMembers(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandMembersMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openMembers(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshMembers(Island island) {\n        plugin.getProviders().getMenusProvider().refreshMembers(island);\n    }\n\n    @Override\n    public void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        plugin.getProviders().getMenusProvider().openMissions(targetPlayer, previousMenu);\n    }\n\n    @Override\n    public void openIslandMainMissionsMenu(SuperiorPlayer superiorPlayer) {\n        openMissions(superiorPlayer, null);\n    }\n\n    @Override\n    public void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory) {\n        plugin.getProviders().getMenusProvider().openMissionsCategory(targetPlayer, previousMenu, missionCategory);\n    }\n\n    @Override\n    public void openIslandMissionsMenu(SuperiorPlayer superiorPlayer, boolean islandMissions) {\n        // Menu doesn't exist anymore.\n    }\n\n    @Override\n    public void refreshMissionsCategory(MissionCategory missionCategory) {\n        plugin.getProviders().getMenusProvider().refreshMissionsCategory(missionCategory);\n    }\n\n    @Override\n    public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer) {\n        plugin.getProviders().getMenusProvider().openPermissions(targetPlayer, previousMenu, targetIsland, permissiblePlayer);\n    }\n\n    @Override\n    public void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) {\n        openPermissions(superiorPlayer, null, island, targetPlayer);\n    }\n\n    @Override\n    public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole) {\n        plugin.getProviders().getMenusProvider().openPermissions(targetPlayer, previousMenu, targetIsland, permissibleRole);\n    }\n\n    @Override\n    public void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole) {\n        openPermissions(superiorPlayer, null, island, playerRole);\n    }\n\n    @Override\n    public void refreshPermissions(Island island) {\n        plugin.getProviders().getMenusProvider().refreshPermissions(island);\n    }\n\n    @Override\n    public void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer) {\n        plugin.getProviders().getMenusProvider().refreshPermissions(island, permissiblePlayer);\n    }\n\n    @Override\n    public void refreshPermissions(Island island, PlayerRole permissibleRole) {\n        plugin.getProviders().getMenusProvider().refreshPermissions(island, permissibleRole);\n    }\n\n    @Override\n    public void updatePermission(IslandPrivilege islandPrivilege) {\n        plugin.getProviders().getMenusProvider().updatePermission(islandPrivilege);\n    }\n\n    @Override\n    public void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        plugin.getProviders().getMenusProvider().openPlayerLanguage(targetPlayer, previousMenu);\n    }\n\n    @Override\n    public void openPlayerLanguageMenu(SuperiorPlayer superiorPlayer) {\n        openPlayerLanguage(superiorPlayer, null);\n    }\n\n    @Override\n    public void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openSettings(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandSettingsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openSettings(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshSettings(Island island) {\n        plugin.getProviders().getMenusProvider().refreshSettings(island);\n    }\n\n    @Override\n    public void updateSettings(IslandFlag islandFlag) {\n        plugin.getProviders().getMenusProvider().updateSettings(islandFlag);\n    }\n\n    @Override\n    public void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType) {\n        plugin.getProviders().getMenusProvider().openTopIslands(targetPlayer, previousMenu, sortingType);\n    }\n\n    @Override\n    public void openIslandsTopMenu(SuperiorPlayer superiorPlayer, SortingType sortingType) {\n        openTopIslands(superiorPlayer, null, sortingType);\n    }\n\n    @Override\n    public void refreshTopIslands(SortingType sortingType) {\n        plugin.getProviders().getMenusProvider().refreshTopIslands(sortingType);\n    }\n\n    @Override\n    public void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openUniqueVisitors(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openUniqueVisitorsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openUniqueVisitors(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshUniqueVisitors(Island island) {\n        plugin.getProviders().getMenusProvider().refreshUniqueVisitors(island);\n    }\n\n    @Override\n    public void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openUpgrades(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandUpgradeMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openUpgrades(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshUpgrades(Island island) {\n        plugin.getProviders().getMenusProvider().refreshUpgrades(island);\n    }\n\n    @Override\n    public void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openValues(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void openIslandValuesMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openValues(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void refreshValues(Island island) {\n        plugin.getProviders().getMenusProvider().refreshValues(island);\n    }\n\n    @Override\n    public void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openVisitors(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshVisitors(Island island) {\n        plugin.getProviders().getMenusProvider().refreshVisitors(island);\n    }\n\n    @Override\n    public void openIslandVisitorsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openVisitors(superiorPlayer, null, island);\n    }\n\n    @Override\n    public void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        plugin.getProviders().getMenusProvider().openWarpCategories(targetPlayer, previousMenu, targetIsland);\n    }\n\n    @Override\n    public void refreshWarpCategories(Island island) {\n        plugin.getProviders().getMenusProvider().refreshWarpCategories(island);\n    }\n\n    @Override\n    public void destroyWarpCategories(Island island) {\n        plugin.getProviders().getMenusProvider().destroyWarpCategories(island);\n    }\n\n    @Override\n    public void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        plugin.getProviders().getMenusProvider().openWarpCategoryIconEdit(targetPlayer, previousMenu, targetCategory);\n    }\n\n    @Override\n    public void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        plugin.getProviders().getMenusProvider().openWarpCategoryManage(targetPlayer, previousMenu, targetCategory);\n    }\n\n    @Override\n    public void refreshWarpCategoryManage(WarpCategory warpCategory) {\n        plugin.getProviders().getMenusProvider().refreshWarpCategoryManage(warpCategory);\n    }\n\n    @Override\n    public void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) {\n        plugin.getProviders().getMenusProvider().openWarpIconEdit(targetPlayer, previousMenu, targetWarp);\n    }\n\n    @Override\n    public void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) {\n        plugin.getProviders().getMenusProvider().openWarpManage(targetPlayer, previousMenu, targetWarp);\n    }\n\n    @Override\n    public void refreshWarpManage(IslandWarp islandWarp) {\n        plugin.getProviders().getMenusProvider().refreshWarpManage(islandWarp);\n    }\n\n    @Override\n    public void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        plugin.getProviders().getMenusProvider().openWarps(targetPlayer, previousMenu, targetCategory);\n    }\n\n    @Override\n    public void openIslandWarpsMenu(SuperiorPlayer superiorPlayer, Island island) {\n        openWarps(superiorPlayer, null, island.getWarpCategories().values()\n                .stream().findFirst().orElseGet(() -> island.createWarpCategory(\"Default Category\")));\n    }\n\n    @Override\n    public void refreshWarps(WarpCategory warpCategory) {\n        plugin.getProviders().getMenusProvider().refreshWarps(warpCategory);\n    }\n\n    @Override\n    public void destroyWarps(WarpCategory warpCategory) {\n        plugin.getProviders().getMenusProvider().destroyWarps(warpCategory);\n    }\n\n    @Override\n    public void registerMenu(Menu<?, ?> menu) {\n        Preconditions.checkNotNull(menu, \"menu parameter cannot be null\");\n        Preconditions.checkState(getMenu(menu.getIdentifier()) == null, \"There is already a menu with a similar identifier: \" + menu.getIdentifier());\n        this.registeredMenus.put(menu.getIdentifier().toLowerCase(Locale.ENGLISH), menu);\n    }\n\n    public void unregisterMenus() {\n        this.registeredMenus.clear();\n    }\n\n    @Nullable\n    @Override\n    public <V extends MenuView<V, A>, A extends ViewArgs> Menu<V, A> getMenu(String identifier) {\n        Preconditions.checkNotNull(identifier, \"identifier parameter cannot be null\");\n        return (Menu<V, A>) this.registeredMenus.get(identifier.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public Map<String, Menu<?, ?>> getMenus() {\n        return Collections.unmodifiableMap(this.registeredMenus);\n    }\n\n    @Override\n    public Map<String, Menu<?, ?>> getCustomMenus() {\n        Map<String, Menu<?, ?>> customMenus = new LinkedHashMap<>();\n\n        this.registeredMenus.forEach((menuName, menu) -> {\n            if (menu instanceof MenuCustom)\n                customMenus.put(menuName, menu);\n        });\n\n        return customMenus.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(customMenus);\n    }\n\n    @Override\n    public <V extends MenuView<V, ?>> MenuLayout.Builder<V> createPatternBuilder() {\n        return RegularMenuLayoutImpl.newBuilder();\n    }\n\n    @Override\n    public <V extends PagedMenuView<V, ?, E>, E> PagedMenuLayout.Builder<V, E> createPagedPatternBuilder() {\n        return PagedMenuLayoutImpl.newBuilder();\n    }\n\n    @Override\n    public <V extends MenuView<V, ?>> MenuTemplateButton.Builder<V> createButtonBuilder(\n            Class<?> viewButtonType, MenuTemplateButton.MenuViewButtonCreator<V> viewButtonCreator) {\n        return AbstractMenuTemplateButton.newBuilder(viewButtonType, viewButtonCreator);\n    }\n\n    @Override\n    public <V extends MenuView<V, ?>, E> PagedMenuTemplateButton.Builder<V, E> createPagedButtonBuilder(\n            Class<?> viewButtonType, PagedMenuTemplateButton.PagedMenuViewButtonCreator<V, E> viewButtonCreator) {\n        return PagedMenuTemplateButtonImpl.newBuilder(viewButtonType, viewButtonCreator);\n    }\n\n    @Override\n    public MenuParser getParser() {\n        return MenuParserImpl.getInstance();\n    }\n\n    @Override\n    public MenuCommands getMenuCommands() {\n        return MenuCommandsImpl.getInstance();\n    }\n\n    @Override\n    @Deprecated\n    public ISuperiorMenu getOldMenuFromView(MenuView<?, ?> menuView) {\n        return MenuViewWrapper.fromView(menuView);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/TemplateItem.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport org.bukkit.Material;\nimport org.bukkit.inventory.ItemStack;\n\npublic class TemplateItem {\n\n    public static final TemplateItem AIR = new TemplateItem(new ItemBuilder(Material.AIR));\n\n    private final ItemBuilder itemBuilder;\n\n    public TemplateItem(ItemBuilder itemBuilder) {\n        this.itemBuilder = itemBuilder;\n    }\n\n    public ItemBuilder getBuilder() {\n        return itemBuilder.copy();\n    }\n\n    public ItemBuilder getEditableBuilder() {\n        return itemBuilder;\n    }\n\n    public ItemStack build() {\n        return getBuilder().build();\n    }\n\n    public ItemStack build(SuperiorPlayer superiorPlayer) {\n        return getBuilder().build(superiorPlayer);\n    }\n\n    public TemplateItem copy() {\n        return new TemplateItem(this.itemBuilder.copy());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractMenuTemplateButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic abstract class AbstractMenuTemplateButton<V extends MenuView<V, ?>> implements MenuTemplateButton<V> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final TemplateItem buttonItem;\n    private final GameSound clickSound;\n    private final List<String> commands;\n    private final String requiredPermission;\n    private final GameSound lackPermissionSound;\n    private final Class<?> viewButtonType;\n\n    public AbstractMenuTemplateButton(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound,\n                                      @Nullable List<String> commands, @Nullable String requiredPermission,\n                                      @Nullable GameSound lackPermissionSound, Class<?> viewButtonType) {\n        this.buttonItem = buttonItem;\n        this.clickSound = clickSound;\n        this.commands = commands == null ? Collections.emptyList() : Collections.unmodifiableList(commands);\n        this.requiredPermission = requiredPermission;\n        this.lackPermissionSound = lackPermissionSound;\n        this.viewButtonType = viewButtonType;\n    }\n\n    @Nullable\n    @Override\n    public ItemStack getButtonItem() {\n        return this.buttonItem == null ? null : this.buttonItem.getBuilder().build();\n    }\n\n    @Nullable\n    public TemplateItem getButtonTemplateItem() {\n        return buttonItem;\n    }\n\n    @Nullable\n    @Override\n    public GameSound getClickSound() {\n        return this.clickSound;\n    }\n\n    @Override\n    public List<String> getClickCommands() {\n        return this.commands;\n    }\n\n    @Nullable\n    @Override\n    public String getRequiredPermission() {\n        return this.requiredPermission;\n    }\n\n    @Nullable\n    @Override\n    public GameSound getLackPermissionSound() {\n        return this.lackPermissionSound;\n    }\n\n    @Override\n    public Class<?> getViewButtonType() {\n        return this.viewButtonType;\n    }\n\n    protected <B extends MenuViewButton<V>> B ensureCorrectType(B button) {\n        if (!getViewButtonType().isInstance(button))\n            throw new IllegalStateException(\"Menu template \" + getClass().getSimpleName() +\n                    \" expected view button of type \" + getViewButtonType().getSimpleName() + \", got \" + button.getClass());\n        return button;\n    }\n\n    public <B extends MenuTemplateButton.Builder<?>> B applyToBuilder(B buttonBuilder) {\n        if (((AbstractBuilder<?>) buttonBuilder).buttonItem == null)\n            ((AbstractBuilder<?>) buttonBuilder).buttonItem = this.buttonItem;\n\n        if (this.clickSound != null)\n            buttonBuilder.setClickSound(this.clickSound);\n        if (this.commands != null && !this.commands.isEmpty())\n            buttonBuilder.setClickCommands(this.commands);\n        if (!Text.isBlank(this.requiredPermission))\n            buttonBuilder.setRequiredPermission(this.requiredPermission);\n        if (this.lackPermissionSound != null)\n            buttonBuilder.setLackPermissionsSound(this.lackPermissionSound);\n\n        return buttonBuilder;\n    }\n\n    public static <V extends MenuView<V, ?>> AbstractBuilder<V> newBuilder(Class<?> viewButtonType, MenuViewButtonCreator<V> viewButtonCreator) {\n        return new AbstractBuilder<V>() {\n            @Override\n            public MenuTemplateButton<V> build() {\n                return new AbstractMenuTemplateButton<V>(this.buttonItem, this.clickSound, this.commands,\n                        this.requiredPermission, this.lackPermissionSound, viewButtonType) {\n\n                    @Override\n                    public MenuViewButton<V> createViewButton(V menuView) {\n                        return ensureCorrectType(viewButtonCreator.create(this, menuView));\n                    }\n                };\n            }\n        };\n    }\n\n    public static abstract class AbstractBuilder<V extends MenuView<V, ?>> implements MenuTemplateButton.Builder<V> {\n\n        protected TemplateItem buttonItem = null;\n        protected GameSound clickSound = null;\n        protected List<String> commands = null;\n        protected String requiredPermission = null;\n        protected GameSound lackPermissionSound = null;\n\n        public Builder<V> setButtonItem(ItemStack buttonItem) {\n            return this.setButtonItem(new TemplateItem(new ItemBuilder(buttonItem)));\n        }\n\n        public Builder<V> setButtonItem(TemplateItem buttonItem) {\n            this.buttonItem = buttonItem;\n            return this;\n        }\n\n        public Builder<V> setClickSound(GameSound clickSound) {\n            this.clickSound = clickSound;\n            return this;\n        }\n\n        public Builder<V> setClickCommands(List<String> commands) {\n            this.commands = commands;\n            return this;\n        }\n\n        public Builder<V> setRequiredPermission(String requiredPermission) {\n            this.requiredPermission = requiredPermission;\n            return this;\n        }\n\n        public Builder<V> setLackPermissionsSound(GameSound lackPermissionSound) {\n            this.lackPermissionSound = lackPermissionSound;\n            return this;\n        }\n\n        public abstract MenuTemplateButton<V> build();\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractMenuViewButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic abstract class AbstractMenuViewButton<V extends MenuView<V, ?>> implements MenuViewButton<V> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    protected final V menuView;\n    private final AbstractMenuTemplateButton<V> templateButton;\n\n    protected AbstractMenuViewButton(MenuTemplateButton<V> templateButton, V menuView) {\n        this.templateButton = (AbstractMenuTemplateButton<V>) templateButton;\n        this.menuView = menuView;\n    }\n\n    @Override\n    public MenuTemplateButton<V> getTemplate() {\n        return this.templateButton;\n    }\n\n    @Override\n    public V getView() {\n        return this.menuView;\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        TemplateItem templateItem = this.templateButton.getButtonTemplateItem();\n        return templateItem == null ? null : templateItem.getBuilder().build(menuView.getInventoryViewer());\n    }\n\n    @Override\n    public abstract void onButtonClick(InventoryClickEvent clickEvent);\n\n    public void onButtonClickLackPermission(InventoryClickEvent clickEvent) {\n        GameSoundImpl.playSound(clickEvent.getWhoClicked(), this.templateButton.getLackPermissionSound());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractPagedMenuButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.inventory.ItemStack;\n\npublic abstract class AbstractPagedMenuButton<V extends MenuView<V, ?>, E>\n        extends AbstractMenuViewButton<V> implements PagedMenuViewButton<V, E> {\n\n    protected E pagedObject = null;\n\n    protected AbstractPagedMenuButton(MenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void updateObject(E pagedObject) {\n        this.pagedObject = pagedObject;\n    }\n\n    @Override\n    public E getPagedObject() {\n        return pagedObject;\n    }\n\n    @Override\n    public final ItemStack createViewItem() {\n        return modifyViewItem(super.createViewItem());\n    }\n\n    public abstract ItemStack modifyViewItem(ItemStack buttonItem);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/MenuTemplateButtonImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\n\nimport java.util.List;\n\npublic class MenuTemplateButtonImpl<V extends MenuView<V, ?>> extends AbstractMenuTemplateButton<V> implements MenuTemplateButton<V> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final ViewButtonCreator<V> viewButtonCreator;\n\n    public MenuTemplateButtonImpl(TemplateItem buttonItem, GameSound clickSound, List<String> commands,\n                                  String requiredPermission, GameSound lackPermissionSound,\n                                  Class<?> viewButtonType, ViewButtonCreator<V> viewButtonCreator) {\n        super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, viewButtonType);\n        this.viewButtonCreator = viewButtonCreator;\n    }\n\n    @Override\n    public MenuViewButton<V> createViewButton(V menuView) {\n        return ensureCorrectType(this.viewButtonCreator.create(this, menuView));\n    }\n\n    public interface ViewButtonCreator<V extends MenuView<V, ?>> {\n\n        MenuViewButton<V> create(AbstractMenuTemplateButton<V> templateButton, V menuView);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\npublic class PagedMenuTemplateButtonImpl<V extends MenuView<V, ?>, E> extends AbstractMenuTemplateButton<V> implements PagedMenuTemplateButton<V, E> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final TemplateItem nullItem;\n    private final PagedMenuViewButtonCreator<V, E> viewButtonCreator;\n    private int buttonIndex;\n\n    public PagedMenuTemplateButtonImpl(TemplateItem buttonItem, GameSound clickSound, List<String> commands,\n                                       String requiredPermission, GameSound lackPermissionSound, TemplateItem nullItem,\n                                       int buttonIndex, Class<?> viewButtonType, PagedMenuViewButtonCreator<V, E> viewButtonCreator) {\n        super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, viewButtonType);\n        this.nullItem = nullItem;\n        this.buttonIndex = buttonIndex;\n        this.viewButtonCreator = viewButtonCreator;\n    }\n\n    @Override\n    public ItemStack getNullItem() {\n        return this.nullItem == null ? null : this.nullItem.getBuilder().build();\n    }\n\n    public TemplateItem getNullTemplateItem() {\n        return this.nullItem;\n    }\n\n    @Override\n    public int getButtonIndex() {\n        return this.buttonIndex;\n    }\n\n    @Override\n    public void setButtonIndex(int buttonIndex) {\n        Preconditions.checkArgument(buttonIndex >= 0, \"buttonIndex cannot be negative.\");\n        this.buttonIndex = buttonIndex;\n    }\n\n    @Override\n    public PagedMenuViewButton<V, E> createViewButton(V menuView) {\n        return ensureCorrectType(this.viewButtonCreator.create(this, menuView));\n    }\n\n    public static <V extends MenuView<V, ?>, E> AbstractBuilder<V, E> newBuilder(Class<?> viewButtonType, PagedMenuViewButtonCreator<V, E> viewButtonCreator) {\n        return new AbstractBuilder<V, E>() {\n            @Override\n            public PagedMenuTemplateButton<V, E> build() {\n                return new PagedMenuTemplateButtonImpl<>(this.buttonItem, this.clickSound, this.commands,\n                        this.requiredPermission, this.lackPermissionSound, this.nullItem, getButtonIndex(),\n                        viewButtonType, viewButtonCreator);\n            }\n        };\n    }\n\n    public static abstract class AbstractBuilder<V extends MenuView<V, ?>, E>\n            extends AbstractMenuTemplateButton.AbstractBuilder<V> implements PagedMenuTemplateButton.Builder<V, E> {\n\n        private int buttonIndex = 0;\n        protected TemplateItem nullItem = null;\n\n        @Override\n        public AbstractBuilder<V, E> setNullItem(ItemStack nullItem) {\n            return this.setNullItem(new TemplateItem(new ItemBuilder(nullItem)));\n        }\n\n        public AbstractBuilder<V, E> setNullItem(TemplateItem nullItem) {\n            this.nullItem = nullItem;\n            return this;\n        }\n\n        protected int getButtonIndex() {\n            return buttonIndex++;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BackButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class BackButton<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuViewButton<V> {\n\n    private BackButton(AbstractMenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    public static class Builder<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuTemplateButton.AbstractBuilder<V> {\n\n        @Override\n        public MenuTemplateButton<V> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, BackButton.class, BackButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\n\npublic class BanButton extends AbstractMenuViewButton<MenuConfirmBan.View> {\n\n    private BanButton(AbstractMenuTemplateButton<MenuConfirmBan.View> templateButton, MenuConfirmBan.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        if (getTemplate().banPlayer)\n            IslandUtils.handleBanPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer());\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuConfirmBan.View> {\n\n        private boolean banPlayer;\n\n        public Builder setBanPlayer(boolean banPlayer) {\n            this.banPlayer = banPlayer;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuConfirmBan.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, banPlayer);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuConfirmBan.View> {\n\n        private final boolean banPlayer;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean banPlayer) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    BanButton.class, BanButton::new);\n            this.banPlayer = banPlayer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Date;\n\npublic class BankBalanceButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BankBalanceButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        Island island = menuView.getInventoryViewer().getIsland();\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        ItemStack buttonItem = super.createViewItem();\n\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", island.getIslandBank().getBalance() + \"\")\n                .replaceAll(\"{1}\", Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance()))\n                .replaceAll(\"{2}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), inventoryViewer.getUserLocale()))\n                .replaceAll(\"{3}\", island.getBankLimit() + \"\")\n                .replaceAll(\"{4}\", Formatters.NUMBER_FORMATTER.format(island.getBankLimit()))\n                .replaceAll(\"{5}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), inventoryViewer.getUserLocale()))\n                .replaceAll(\"{6}\", Formatters.DATE_FORMATTER.format(new Date(island.getLastInterestTime() * 1000L)))\n                .replaceAll(\"{7}\", Formatters.DATE_FORMATTER.format(new Date(System.currentTimeMillis() + island.getNextInterest() * 1000L)))\n                .build();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, BankBalanceButton.class, BankBalanceButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class BankCustomDepositButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BankCustomDepositButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        Island island = menuView.getIsland();\n\n        Message.BANK_DEPOSIT_CUSTOM.send(clickedPlayer);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            try {\n                BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message));\n                BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, newAmount);\n                MenuActions.handleDeposit(clickedPlayer, island, bankTransaction,\n                        getTemplate().successSound, getTemplate().failSound, newAmount);\n            } catch (IllegalArgumentException ex) {\n                Message.INVALID_AMOUNT.send(clickedPlayer, message);\n            }\n\n            PlayerChat.remove(player);\n\n            return true;\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private GameSound failSound;\n        private GameSound successSound;\n\n        public Builder setSuccessSound(GameSound successSound) {\n            this.successSound = successSound;\n            return this;\n        }\n\n        public Builder setFailSound(GameSound failSound) {\n            this.failSound = failSound;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        @Nullable\n        private final GameSound successSound;\n        @Nullable\n        private final GameSound failSound;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable List<String> commands, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound) {\n            super(buttonItem, null, commands, requiredPermission, lackPermissionSound,\n                    BankCustomDepositButton.class, BankCustomDepositButton::new);\n            this.successSound = successSound;\n            this.failSound = failSound;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class BankCustomWithdrawButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BankCustomWithdrawButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        Island island = menuView.getIsland();\n\n        Message.BANK_WITHDRAW_CUSTOM.send(clickedPlayer);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            try {\n                BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message));\n                BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, newAmount, null);\n                MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction,\n                        getTemplate().successSound, getTemplate().failSound, newAmount);\n            } catch (IllegalArgumentException ex) {\n                Message.INVALID_AMOUNT.send(clickedPlayer, message);\n            }\n\n            PlayerChat.remove(player);\n\n            return true;\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private GameSound successSound;\n        private GameSound failSound;\n\n        public Builder setSuccessSound(GameSound successSound) {\n            this.successSound = successSound;\n            return this;\n        }\n\n        public Builder setFailSound(GameSound failSound) {\n            this.failSound = failSound;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        @Nullable\n        private final GameSound successSound;\n        @Nullable\n        private final GameSound failSound;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable List<String> commands, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound) {\n            super(buttonItem, null, commands, requiredPermission, lackPermissionSound,\n                    BankCustomWithdrawButton.class, BankCustomWithdrawButton::new);\n            this.successSound = successSound;\n            this.failSound = failSound;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class BankDepositButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BankDepositButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        Island island = menuView.getIsland();\n\n        BigDecimal amount = plugin.getProviders().getBankEconomyProvider().getBalance(clickedPlayer)\n                .multiply(getTemplate().depositPercentage);\n\n        BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, amount);\n        MenuActions.handleDeposit(clickedPlayer, island, bankTransaction,\n                getTemplate().successSound, getTemplate().failSound, amount);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private final double depositPercentage;\n        private GameSound successSound;\n        private GameSound failSound;\n\n        public Builder(double depositPercentage) {\n            this.depositPercentage = depositPercentage;\n        }\n\n        public Builder setSuccessSound(GameSound successSound) {\n            this.successSound = successSound;\n            return this;\n        }\n\n        public Builder setFailSound(GameSound failSound) {\n            this.failSound = failSound;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, commands, requiredPermission, lackPermissionSound,\n                    successSound, failSound, depositPercentage);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        @Nullable\n        private final GameSound successSound;\n        @Nullable\n        private final GameSound failSound;\n        private final BigDecimal depositPercentage;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable List<String> commands, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound,\n                 @Nullable GameSound failSound, double depositPercentage) {\n            super(buttonItem, null, commands, requiredPermission, lackPermissionSound,\n                    BankDepositButton.class, BankDepositButton::new);\n            this.successSound = successSound;\n            this.failSound = failSound;\n            this.depositPercentage = BigDecimal.valueOf(depositPercentage / 100D);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankLogsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.UUID;\n\npublic class BankLogsPagedObjectButton extends AbstractPagedMenuButton<MenuBankLogs.View, BankTransaction> {\n\n    private static final UUID CONSOLE_UUID = new UUID(0, 0);\n\n    private BankLogsPagedObjectButton(MenuTemplateButton<MenuBankLogs.View> templateButton, MenuBankLogs.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setFilteredPlayer(pagedObject.getPlayer());\n        menuView.refreshView();\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", pagedObject.getPosition() + \"\")\n                .replaceAll(\"{1}\", getFilteredPlayerName(pagedObject.getPlayer() == null ? CONSOLE_UUID : pagedObject.getPlayer()))\n                .replaceAll(\"{2}\", (pagedObject.getAction() == BankAction.WITHDRAW_COMPLETED ?\n                        Message.BANK_WITHDRAW_COMPLETED : Message.BANK_DEPOSIT_COMPLETED).getMessage(inventoryViewer.getUserLocale()))\n                .replaceAll(\"{3}\", pagedObject.getDate())\n                .replaceAll(\"{4}\", pagedObject.getAmount() + \"\")\n                .replaceAll(\"{5}\", Formatters.NUMBER_FORMATTER.format(pagedObject.getAmount()))\n                .replaceAll(\"{6}\", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getAmount(), inventoryViewer.getUserLocale()))\n                .asSkullOf(inventoryViewer)\n                .build(inventoryViewer);\n    }\n\n    private static String getFilteredPlayerName(UUID filteredPlayer) {\n        if (filteredPlayer == null) {\n            return \"\";\n        } else if (filteredPlayer.equals(CONSOLE_UUID)) {\n            return \"Console\";\n        } else {\n            return plugin.getPlayers().getSuperiorPlayer(filteredPlayer).getName();\n        }\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuBankLogs.View, BankTransaction> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuBankLogs.View, BankTransaction> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), BankLogsPagedObjectButton.class, BankLogsPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankLogsSortButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class BankLogsSortButton extends AbstractMenuViewButton<MenuBankLogs.View> {\n\n    private BankLogsSortButton(AbstractMenuTemplateButton<MenuBankLogs.View> templateButton, MenuBankLogs.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        getTemplate().sortType.onButtonClick(clickEvent, menuView);\n        menuView.refreshView();\n    }\n\n    public enum SortType {\n\n        TIME {\n            @Override\n            void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView) {\n                menuView.setSorting(Comparator.comparingLong(BankTransaction::getTime));\n            }\n        },\n        MONEY {\n            @Override\n            void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView) {\n                menuView.setSorting((o1, o2) -> o2.getAmount().compareTo(o1.getAmount()));\n            }\n        };\n\n        SortType() {\n\n        }\n\n        abstract void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView);\n\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuBankLogs.View> {\n\n        private SortType sortType;\n\n        public Builder setSortType(SortType sortType) {\n            this.sortType = sortType;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuBankLogs.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, sortType);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuBankLogs.View> {\n\n        private final SortType sortType;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, SortType sortType) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    BankLogsSortButton.class, BankLogsSortButton::new);\n            this.sortType = Objects.requireNonNull(sortType, \"sortType cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class BankWithdrawButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BankWithdrawButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n        Island island = menuView.getIsland();\n\n        BigDecimal amount = island.getIslandBank().getBalance()\n                .multiply(getTemplate().withdrawValue);\n\n        BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, amount, getTemplate().withdrawCommands);\n        MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction,\n                getTemplate().successSound, getTemplate().failSound, amount);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private final double withdrawValue;\n        private final List<String> withdrawCommands;\n        private GameSound successSound;\n        private GameSound failSound;\n\n        public Builder(double withdrawValue) {\n            this.withdrawValue = withdrawValue;\n            this.withdrawCommands = null;\n        }\n\n        public Builder(List<String> withdrawCommands) {\n            this.withdrawValue = 100D;\n            this.withdrawCommands = withdrawCommands;\n        }\n\n        public BankWithdrawButton.Builder setSuccessSound(GameSound successSound) {\n            this.successSound = successSound;\n            return this;\n        }\n\n        public BankWithdrawButton.Builder setFailSound(GameSound failSound) {\n            this.failSound = failSound;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, commands, requiredPermission, lackPermissionSound,\n                    successSound, failSound, withdrawValue, withdrawCommands);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        @Nullable\n        private final GameSound successSound;\n        @Nullable\n        private final GameSound failSound;\n        private final BigDecimal withdrawValue;\n        private final List<String> withdrawCommands;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable List<String> commands, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound,\n                 @Nullable GameSound failSound, double withdrawValue, @Nullable List<String> withdrawCommands) {\n            super(buttonItem, null, commands, requiredPermission, lackPermissionSound,\n                    BankWithdrawButton.class, BankWithdrawButton::new);\n            this.successSound = successSound;\n            this.failSound = failSound;\n            this.withdrawValue = BigDecimal.valueOf(withdrawValue / 100D);\n            this.withdrawCommands = withdrawCommands == null ? Collections.emptyList() : withdrawCommands;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BannedPlayersPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBannedPlayers;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class BannedPlayersPagedObjectButton extends AbstractPagedMenuButton<MenuIslandBannedPlayers.View, SuperiorPlayer> {\n\n    private BannedPlayersPagedObjectButton(MenuTemplateButton<MenuIslandBannedPlayers.View> templateButton, MenuIslandBannedPlayers.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"unban\", pagedObject.getName());\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", pagedObject.getName())\n                .replaceAll(\"{1}\", pagedObject.getPlayerRole() + \"\")\n                .asSkullOf(pagedObject)\n                .build(pagedObject);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandBannedPlayers.View, SuperiorPlayer> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandBannedPlayers.View, SuperiorPlayer> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), BannedPlayersPagedObjectButton.class,\n                    BannedPlayersPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.Bukkit;\nimport org.bukkit.block.Biome;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class BiomeButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private BiomeButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Nullable\n    @Override\n    public ItemStack createViewItem() {\n        ItemStack buttonItem = null;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        String requiredPermission = getTemplate().getRequiredPermission();\n\n        if (requiredPermission == null || inventoryViewer.hasPermission(requiredPermission)) {\n            buttonItem = super.createViewItem();\n        } else if (getTemplate().lackPermissionItem != null) {\n            buttonItem = getTemplate().lackPermissionItem.build(inventoryViewer);\n        }\n\n        if (buttonItem == null || !Menus.MENU_BIOMES.isCurrentBiomeGlow())\n            return buttonItem;\n\n        Island island = inventoryViewer.getIsland();\n\n        if (island == null || island.getBiome() != getTemplate().biome)\n            return buttonItem;\n\n        return new ItemBuilder(buttonItem)\n                .makeItemGlow()\n                .build();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Player player = inventoryViewer.asPlayer();\n\n        PluginEvent<PluginEventArgs.IslandBiomeChange> event = PluginEventsFactory.callIslandBiomeChangeEvent(\n                menuView.getIsland(), inventoryViewer, getTemplate().biome);\n\n        if (event.isCancelled()) {\n            GameSoundImpl.playSound(player, getTemplate().getLackPermissionSound());\n            return;\n        }\n\n        GameSoundImpl.playSound(player, getTemplate().accessSound);\n\n        getTemplate().accessCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", inventoryViewer.getName())));\n\n        menuView.getIsland().setBiome(event.getArgs().biome);\n        Message.CHANGED_BIOME.send(inventoryViewer,\n                Formatters.CAPITALIZED_FORMATTER.format(event.getArgs().biome.name()));\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    @Override\n    public void onButtonClickLackPermission(InventoryClickEvent clickEvent) {\n        super.onButtonClickLackPermission(clickEvent);\n        getTemplate().lackPermissionCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", menuView.getInventoryViewer().getName())));\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private final Biome biome;\n        private TemplateItem noAccessItem = null;\n        private List<String> noAccessCommands = null;\n\n        public Builder(Biome biome) {\n            this.biome = biome;\n        }\n\n        public void setAccessItem(TemplateItem accessItem) {\n            this.buttonItem = accessItem;\n        }\n\n        public void setNoAccessItem(TemplateItem noAccessItem) {\n            this.noAccessItem = noAccessItem;\n        }\n\n        public void setAccessSound(GameSound accessSound) {\n            this.clickSound = accessSound;\n        }\n\n        public void setNoAccessSound(GameSound noAccessSound) {\n            this.lackPermissionSound = noAccessSound;\n        }\n\n        public void setAccessCommands(List<String> accessCommands) {\n            this.commands = accessCommands;\n        }\n\n        public void setNoAccessCommands(List<String> noAccessCommands) {\n            this.noAccessCommands = noAccessCommands;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, requiredPermission, lackPermissionSound,\n                    clickSound, commands, noAccessItem, noAccessCommands, biome);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        @Nullable\n        private final GameSound accessSound;\n        private final List<String> accessCommands;\n        @Nullable\n        private final TemplateItem lackPermissionItem;\n        private final List<String> lackPermissionCommands;\n        private final Biome biome;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable GameSound accessSound,\n                 @Nullable List<String> accessCommands, @Nullable TemplateItem lackPermissionItem,\n                 @Nullable List<String> lackPermissionCommands, Biome biome) {\n            super(buttonItem, null, null, requiredPermission, lackPermissionSound,\n                    BiomeButton.class, BiomeButton::new);\n            this.accessSound = accessSound;\n            this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands;\n            this.lackPermissionItem = lackPermissionItem;\n            this.lackPermissionCommands = lackPermissionCommands == null ? Collections.emptyList() : lackPermissionCommands;\n            this.biome = Objects.requireNonNull(biome, \"biome cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BorderColorButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class BorderColorButton extends AbstractMenuViewButton<BaseMenuView> {\n\n    private BorderColorButton(AbstractMenuTemplateButton<BaseMenuView> templateButton, BaseMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        if (IslandUtils.handleBorderColorUpdate(menuView.getInventoryViewer(), getTemplate().borderColor))\n            BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<BaseMenuView> {\n\n        private BorderColor borderColor;\n\n        public Builder setBorderColor(BorderColor borderColor) {\n            this.borderColor = borderColor;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<BaseMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, borderColor);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<BaseMenuView> {\n\n        private final BorderColor borderColor;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, BorderColor borderColor) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    BorderColorButton.class, BorderColorButton::new);\n            this.borderColor = Objects.requireNonNull(borderColor, \"borderColor cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BorderColorToggleButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\npublic class BorderColorToggleButton extends AbstractMenuViewButton<BaseMenuView> {\n\n    private BorderColorToggleButton(AbstractMenuTemplateButton<BaseMenuView> templateButton, BaseMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        TemplateItem buttonItem = inventoryViewer.hasWorldBorderEnabled() ? getTemplate().enabledItem : getTemplate().disabledItem;\n        return buttonItem.build(inventoryViewer);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"toggle\", \"border\");\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<BaseMenuView> {\n\n        private TemplateItem disabledItem;\n\n        public Builder setEnabledItem(TemplateItem enabledItem) {\n            this.buttonItem = enabledItem;\n            return this;\n        }\n\n        public Builder setDisabledItem(TemplateItem disabledItem) {\n            this.disabledItem = disabledItem;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<BaseMenuView> build() {\n            return new Template(clickSound, commands, requiredPermission, lackPermissionSound, buttonItem, disabledItem);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<BaseMenuView> {\n\n        private final TemplateItem enabledItem;\n        private final TemplateItem disabledItem;\n\n        Template(@Nullable GameSound clickSound, @Nullable List<String> commands, @Nullable String requiredPermission,\n                 @Nullable GameSound lackPermissionSound, @Nullable TemplateItem enabledItem,\n                 @Nullable TemplateItem disabledItem) {\n            super(null, clickSound, commands, requiredPermission, lackPermissionSound,\n                    BorderColorToggleButton.class, BorderColorToggleButton::new);\n            this.enabledItem = enabledItem == null ? TemplateItem.AIR : enabledItem;\n            this.disabledItem = disabledItem == null ? TemplateItem.AIR : disabledItem;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class ChangeSortingTypeButton extends AbstractMenuViewButton<MenuTopIslands.View> {\n\n    private ChangeSortingTypeButton(AbstractMenuTemplateButton<MenuTopIslands.View> templateButton, MenuTopIslands.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        ItemStack buttonItem = super.createViewItem();\n\n        if (buttonItem == null || !Menus.MENU_TOP_ISLANDS.isSortGlowWhenSelected() ||\n                menuView.getSortingType() != getTemplate().sortingType)\n            return buttonItem;\n\n        return new ItemBuilder(buttonItem)\n                .makeItemGlow()\n                .build();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SortingType sortingType = getTemplate().sortingType;\n\n        if (menuView.getSortingType() == sortingType)\n            return;\n\n        boolean notSortedAlready = menuView.setSortingType(sortingType);\n\n        if (notSortedAlready) {\n            plugin.getGrid().sortIslands(sortingType, menuView::refreshView);\n        } else {\n            menuView.refreshView();\n        }\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuTopIslands.View> {\n\n        private SortingType sortingType;\n\n        public Builder setSortingType(SortingType sortingType) {\n            this.sortingType = sortingType;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuTopIslands.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, sortingType);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuTopIslands.View> {\n\n        private final SortingType sortingType;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, SortingType sortingType) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    ChangeSortingTypeButton.class, ChangeSortingTypeButton::new);\n            this.sortingType = Objects.requireNonNull(sortingType, \"sortingType cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ConfigEditorPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.ChatColor;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\n\npublic class ConfigEditorPagedObjectButton extends AbstractPagedMenuButton<MenuConfigEditor.View, ItemStack> {\n\n    private ConfigEditorPagedObjectButton(MenuTemplateButton<MenuConfigEditor.View> templateButton, MenuConfigEditor.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        MenuConfigEditor.View currentView = getView();\n        SuperiorPlayer inventoryViewer = currentView.getInventoryViewer();\n        Player player = inventoryViewer.asPlayer();\n\n        if (player == null)\n            return;\n\n        try {\n            String sectionPath = currentView.getPathSlots().get((currentView.getCurrentPage() - 1) * 36 + clickEvent.getRawSlot());\n\n            if (sectionPath == null)\n                return;\n\n            String viewPath = currentView.getPath();\n            String fullPath = viewPath.isEmpty() ? sectionPath : viewPath + \".\" + sectionPath;\n\n            CommentedConfiguration config = Menus.MENU_CONFIG_EDITOR.getConfig();\n\n            if (config.isConfigurationSection(fullPath)) {\n                currentView.setPreviousMove(false);\n                currentView.closeView();\n                currentView.getMenu().createView(inventoryViewer, new MenuConfigEditor.Args(fullPath), currentView);\n            } else if (config.isBoolean(fullPath)) {\n                Menus.MENU_CONFIG_EDITOR.updateConfig(player, fullPath, !config.getBoolean(fullPath));\n                currentView.refreshView();\n            } else {\n                PlayerChat.listen(player, message -> onPlayerChat(currentView, config, player, message, fullPath));\n\n                currentView.closeView();\n\n                player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY + \" Please enter a new value (-cancel to cancel):\");\n\n                if (config.isList(fullPath)) {\n                    player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY + \" If you enter a value that is already in the list, it will be removed.\");\n                }\n            }\n        } catch (Exception ignored) {\n        }\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return pagedObject;\n    }\n\n    private boolean onPlayerChat(MenuView<?, ?> lastView, CommentedConfiguration config, Player player, Object message, String path) {\n        if (!message.toString().equalsIgnoreCase(\"-cancel\")) {\n            if (config.isList(path)) {\n                List<String> list = config.getStringList(path);\n\n                if (list.contains(message.toString())) {\n                    list.remove(message.toString());\n                    player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY + \" Removed the value \" + message + \" from \" + path);\n                } else {\n                    list.add(message.toString());\n                    player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY + \" Added the value \" + message + \" to \" + path);\n                }\n\n                config.set(path, list);\n            } else {\n                boolean valid = true;\n                if (config.isInt(path)) {\n                    try {\n                        message = Integer.valueOf(message.toString());\n                    } catch (IllegalArgumentException ex) {\n                        player.sendMessage(ChatColor.RED + \"Please specify a valid number\");\n                        valid = false;\n                    }\n                } else if (config.isDouble(path)) {\n                    try {\n                        message = Double.valueOf(message.toString());\n                    } catch (IllegalArgumentException ex) {\n                        player.sendMessage(ChatColor.RED + \"Please specify a valid number\");\n                        valid = false;\n                    }\n                }\n\n                if (valid) {\n                    config.set(path, message);\n                    Menus.MENU_CONFIG_EDITOR.updateConfig(player, path, message);\n                }\n            }\n        }\n\n        PlayerChat.remove(player);\n\n        lastView.refreshView();\n\n        return true;\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuConfigEditor.View, ItemStack> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuConfigEditor.View, ItemStack> build() {\n            return new PagedMenuTemplateButtonImpl<>(null, null, null, null,\n                    null, null, getButtonIndex(),\n                    ConfigEditorPagedObjectButton.class, ConfigEditorPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ConfigEditorSaveButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Material;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class ConfigEditorSaveButton extends AbstractMenuViewButton<MenuConfigEditor.View> {\n\n    private static final TemplateItem SAVE_BUTTON_ITEM = new TemplateItem(new ItemBuilder(Material.EMERALD).withName(\"&aSave Changes\"));\n\n    private ConfigEditorSaveButton(AbstractMenuTemplateButton<MenuConfigEditor.View> templateButton, MenuConfigEditor.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n        BukkitExecutor.async(() -> {\n            Menus.MENU_CONFIG_EDITOR.saveConfig(config -> plugin.getSettings().loadData());\n            player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY + \" Saved configuration successfully.\");\n            BukkitExecutor.sync(() -> {\n                getView().setPreviousMove(false);\n                getView().closeView();\n            });\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuConfigEditor.View> {\n\n        @Override\n        public MenuTemplateButton<MenuConfigEditor.View> build() {\n            return new MenuTemplateButtonImpl<>(SAVE_BUTTON_ITEM, null, null, null,\n                    null, ConfigEditorSaveButton.class, ConfigEditorSaveButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class ControlPanelButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private ControlPanelButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        switch (getTemplate().controlPanelAction) {\n            case OPEN_MEMBERS:\n                plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"members\");\n                break;\n            case OPEN_SETTINGS:\n                plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"settings\");\n                break;\n            case OPEN_VISITORS:\n                plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"visitors\");\n                break;\n        }\n    }\n\n    public enum ControlPanelAction {\n\n        OPEN_MEMBERS,\n        OPEN_SETTINGS,\n        OPEN_VISITORS\n\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private ControlPanelAction controlPanelAction;\n\n        public Builder setAction(ControlPanelAction controlPanelAction) {\n            this.controlPanelAction = controlPanelAction;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, controlPanelAction);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        private final ControlPanelAction controlPanelAction;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound,\n                 ControlPanelAction controlPanelAction) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    ControlPanelButton.class, ControlPanelButton::new);\n            this.controlPanelAction = Objects.requireNonNull(controlPanelAction, \"controlPanelAction cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuCoops;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class CoopsPagedObjectButton extends AbstractPagedMenuButton<MenuCoops.View, SuperiorPlayer> {\n\n    private CoopsPagedObjectButton(MenuTemplateButton<MenuCoops.View> templateButton, MenuCoops.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"uncoop\", pagedObject.getName());\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", pagedObject.getName())\n                .replaceAll(\"{1}\", pagedObject.getPlayerRole() + \"\")\n                .asSkullOf(pagedObject)\n                .build(pagedObject);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuCoops.View, SuperiorPlayer> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuCoops.View, SuperiorPlayer> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), CoopsPagedObjectButton.class,\n                    CoopsPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuCounts;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport org.bukkit.Material;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\nimport java.util.Optional;\n\npublic class CountsPagedObjectButton extends AbstractPagedMenuButton<MenuCounts.View, MenuCounts.BlockCount> {\n\n    private static final BigInteger MAX_STACK = BigInteger.valueOf(64);\n\n    private static final Map<Material, Material> BLOCKS_TO_ITEMS = new MapBuilder()\n            .put(\"ACACIA_DOOR\", \"ACACIA_DOOR_ITEM\")\n            .put(\"ACACIA_WALL_HANGING_SIGN\", \"ACACIA_HANGING_SIGN\")\n            .put(\"ACACIA_WALL_SIGN\", \"ACACIA_SIGN\")\n            .put(\"ATTACHED_MELON_STEM\", \"MELON_SEEDS\")\n            .put(\"ATTACHED_PUMPKIN_STEM\", \"PUMPKIN_SEEDS\")\n            .put(\"BAMBOO_SAPLING\", \"BAMBOO\")\n            .put(\"BAMBOO_WALL_HANGING_SIGN\", \"BAMBOO_HANGING_SIGN\")\n            .put(\"BAMBOO_WALL_SIGN\", \"BAMBOO_SIGN\")\n            .put(\"BED_BLOCK\", \"BED\")\n            .put(\"BEETROOT_BLOCK\", \"BEETROOT\")\n            .put(\"BEETROOTS\", \"BEETROOT\")\n            .put(\"BIG_DRIPLEAF_STEM\", \"BIG_DRIPLEAF\")\n            .put(\"BIRCH_DOOR\", \"BIRCH_DOOR_ITEM\")\n            .put(\"BIRCH_WALL_HANGING_SIGN\", \"BIRCH_HANGING_SIGN\")\n            .put(\"BIRCH_WALL_SIGN\", \"BIRCH_SIGN\")\n            .put(\"BLACK_CANDLE_CAKE\", \"BLACK_CANDLE\")\n            .put(\"BLACK_WALL_BANNER\", \"BLACK_BANNER\")\n            .put(\"BLUE_CANDLE_CAKE\", \"BLUE_CANDLE\")\n            .put(\"BLUE_WALL_BANNER\", \"BLUE_BANNER\")\n            .put(\"BRAIN_CORAL_WALL_FAN\", \"BRAIN_CORAL\")\n            .put(\"BREWING_STAND\", \"BREWING_STAND_ITEM\")\n            .put(\"BROWN_CANDLE_CAKE\", \"BROWN_CANDLE\")\n            .put(\"BROWN_WALL_BANNER\", \"BROWN_BANNER\")\n            .put(\"BUBBLE_CORAL_WALL_FAN\", \"BUBBLE_CORAL\")\n            .put(\"BURNING_FURNACE\", \"FURNACE\")\n            .put(\"CAKE_BLOCK\", \"CAKE\")\n            .put(\"CANDLE_CAKE\", \"CANDLE\")\n            .put(\"CARROT\", \"CARROT_ITEM\")\n            .put(\"CARROTS\", \"CARROT\")\n            .put(\"CAULDRON\", \"CAULDRON_ITEM\")\n            .put(\"CAVE_VINES\", \"GLOW_BERRIES\")\n            .put(\"CAVE_VINES_PLANT\", \"GLOW_BERRIES\")\n            .put(\"CHERRY_WALL_HANGING_SIGN\", \"CHERRY_HANGING_SIGN\")\n            .put(\"CHERRY_WALL_SIGN\", \"CHERRY_SIGN\")\n            .put(\"COCOA\", ServerVersion.isLegacy() ? \"INK_SACK:3\" : \"COCOA_BEANS\")\n            .put(\"COPPER_WALL_TORCH\", \"COPPER_TORCH\")\n            .put(\"CREEPER_WALL_HEAD\", \"CREEPER_HEAD\")\n            .put(\"CRIMSON_WALL_HANGING_SIGN\", \"CRIMSON_HANGING_SIGN\")\n            .put(\"CRIMSON_WALL_SIGN\", \"CRIMSON_SIGN\")\n            .put(\"CROPS\", \"SEEDS\")\n            .put(\"CYAN_CANDLE_CAKE\", \"CYAN_CANDLE\")\n            .put(\"CYAN_WALL_BANNER\", \"CYAN_BANNER\")\n            .put(\"DARK_OAK_DOOR\", \"DARK_OAK_DOOR_ITEM\")\n            .put(\"DARK_OAK_WALL_HANGING_SIGN\", \"DARK_OAK_HANGING_SIGN\")\n            .put(\"DARK_OAK_WALL_SIGN\", \"DARK_OAK_SIGN\")\n            .put(\"DAYLIGHT_DETECTOR_INVERTED\", \"DAYLIGHT_DETECTOR\")\n            .put(\"DEAD_BRAIN_CORAL_WALL_FAN\", \"DEAD_BRAIN_CORAL\")\n            .put(\"DEAD_BUBBLE_CORAL_WALL_FAN\", \"DEAD_BUBBLE_CORAL\")\n            .put(\"DEAD_FIRE_CORAL_WALL_FAN\", \"DEAD_FIRE_CORAL\")\n            .put(\"DEAD_HORN_CORAL_WALL_FAN\", \"DEAD_HORN_CORAL\")\n            .put(\"DEAD_TUBE_CORAL_WALL_FAN\", \"DEAD_TUBE_CORAL\")\n            .put(\"DIODE_BLOCK_OFF\", \"DIODE\")\n            .put(\"DIODE_BLOCK_ON\", \"DIODE\")\n            .put(\"DRAGON_WALL_HEAD\", \"DRAGON_HEAD\")\n            .put(\"END_GATEWAY\", ServerVersion.isLegacy() ? \"ENDER_PORTAL_FRAME\" : \"END_PORTAL_FRAME\")\n            .put(\"END_PORTAL\", \"END_PORTAL_FRAME\")\n            .put(\"ENDER_PORTAL\", \"ENDER_PORTAL_FRAME\")\n            .put(\"FIRE\", \"FIRE_CHARGE\")\n            .put(\"FIRE_CORAL_WALL_FAN\", \"FIRE_CORAL\")\n            .put(\"FLOWER_POT\", \"FLOWER_POT_ITEM\")\n            .put(\"FROSTED_ICE\", \"ICE\")\n            .put(\"GLOWING_REDSTONE_ORE\", \"REDSTONE_ORE\")\n            .put(\"GRAY_CANDLE_CAKE\", \"GRAY_CANDLE\")\n            .put(\"GRAY_WALL_BANNER\", \"GRAY_BANNER\")\n            .put(\"GREEN_CANDLE_CAKE\", \"GREEN_CANDLE\")\n            .put(\"GREEN_WALL_BANNER\", \"GREEN_BANNER\")\n            .put(\"HORN_CORAL_WALL_FAN\", \"HORN_CORAL\")\n            .put(\"IRON_DOOR_BLOCK\", \"IRON_DOOR\")\n            .put(\"JUNGLE_DOOR\", \"JUNGLE_DOOR_ITEM\")\n            .put(\"JUNGLE_WALL_HANGING_SIGN\", \"JUNGLE_HANGING_SIGN\")\n            .put(\"JUNGLE_WALL_SIGN\", \"JUNGLE_SIGN\")\n            .put(\"KELP_PLANT\", \"KELP\")\n            .put(\"LAVA\", \"LAVA_BUCKET\")\n            .put(\"LAVA_CAULDRON\", \"CAULDRON\")\n            .put(\"LIGHT_BLUE_CANDLE_CAKE\", \"LIGHT_BLUE_CANDLE\")\n            .put(\"LIGHT_BLUE_WALL_BANNER\", \"LIGHT_BLUE_BANNER\")\n            .put(\"LIGHT_GRAY_CANDLE_CAKE\", \"LIGHT_GRAY_CANDLE\")\n            .put(\"LIGHT_GRAY_WALL_BANNER\", \"LIGHT_GRAY_BANNER\")\n            .put(\"LIME_CANDLE_CAKE\", \"LIME_CANDLE\")\n            .put(\"LIME_WALL_BANNER\", \"LIME_BANNER\")\n            .put(\"MAGENTA_CANDLE_CAKE\", \"MAGENTA_CANDLE\")\n            .put(\"MAGENTA_WALL_BANNER\", \"MAGENTA_BANNER\")\n            .put(\"MANGROVE_WALL_HANGING_SIGN\", \"MANGROVE_HANGING_SIGN\")\n            .put(\"MANGROVE_WALL_SIGN\", \"MANGROVE_SIGN\")\n            .put(\"MELON_STEM\", \"MELON_SEEDS\")\n            .put(\"MOVING_PISTON\", \"PISTON\")\n            .put(\"NETHER_PORTAL\", \"OBSIDIAN\")\n            .put(\"NETHER_WARTS\", \"NETHER_STALK\")\n            .put(\"OAK_WALL_HANGING_SIGN\", \"OAK_HANGING_SIGN\")\n            .put(\"OAK_WALL_SIGN\", \"OAK_SIGN\")\n            .put(\"ORANGE_CANDLE_CAKE\", \"ORANGE_CANDLE\")\n            .put(\"ORANGE_WALL_BANNER\", \"ORANGE_BANNER\")\n            .put(\"PALE_OAK_WALL_HANGING_SIGN\", \"PALE_OAK_HANGING_SIGN\")\n            .put(\"PALE_OAK_WALL_SIGN\", \"PALE_OAK_SIGN\")\n            .put(\"PIGLIN_WALL_HEAD\", \"PIGLIN_HEAD\")\n            .put(\"PINK_CANDLE_CAKE\", \"PINK_CANDLE\")\n            .put(\"PINK_WALL_BANNER\", \"PINK_BANNER\")\n            .put(\"PISTON_EXTENSION\", \"PISTON\")\n            .put(\"PISTON_HEAD\", \"PISTON\")\n            .put(\"PISTON_MOVING_PIECE\", \"PISTON\")\n            .put(\"PITCHER_CROP\", \"PITCHER_PLANT\")\n            .put(\"PLAYER_WALL_HEAD\", \"PLAYER_HEAD\")\n            .put(\"PORTAL\", \"OBSIDIAN\")\n            .put(\"POTATO\", \"POTATO_ITEM\")\n            .put(\"POTATOES\", \"POTATO\")\n            .put(\"POTTED_ACACIA_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_ALLIUM\", \"FLOWER_POT\")\n            .put(\"POTTED_AZALEA_BUSH\", \"FLOWER_POT\")\n            .put(\"POTTED_AZURE_BLUET\", \"FLOWER_POT\")\n            .put(\"POTTED_BAMBOO\", \"FLOWER_POT\")\n            .put(\"POTTED_BIRCH_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_BLUE_ORCHID\", \"FLOWER_POT\")\n            .put(\"POTTED_BROWN_MUSHROOM\", \"FLOWER_POT\")\n            .put(\"POTTED_CACTUS\", \"FLOWER_POT\")\n            .put(\"POTTED_CHERRY_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_CLOSED_EYEBLOSSOM\", \"FLOWER_POT\")\n            .put(\"POTTED_CORNFLOWER\", \"FLOWER_POT\")\n            .put(\"POTTED_CRIMSON_FUNGUS\", \"FLOWER_POT\")\n            .put(\"POTTED_CRIMSON_ROOTS\", \"FLOWER_POT\")\n            .put(\"POTTED_DANDELION\", \"FLOWER_POT\")\n            .put(\"POTTED_DARK_OAK_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_DEAD_BUSH\", \"FLOWER_POT\")\n            .put(\"POTTED_FERN\", \"FLOWER_POT\")\n            .put(\"POTTED_FLOWERING_AZALEA_BUSH\", \"FLOWER_POT\")\n            .put(\"POTTED_GOLDEN_DANDELION\", \"GOLDEN_DANDELION\")\n            .put(\"POTTED_JUNGLE_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_LILY_OF_THE_VALLEY\", \"FLOWER_POT\")\n            .put(\"POTTED_MANGROVE_PROPAGULE\", \"FLOWER_POT\")\n            .put(\"POTTED_OAK_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_OPEN_EYEBLOSSOM\", \"FLOWER_POT\")\n            .put(\"POTTED_ORANGE_TULIP\", \"FLOWER_POT\")\n            .put(\"POTTED_OXEYE_DAISY\", \"FLOWER_POT\")\n            .put(\"POTTED_PALE_OAK_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_PINK_TULIP\", \"FLOWER_POT\")\n            .put(\"POTTED_POPPY\", \"FLOWER_POT\")\n            .put(\"POTTED_RED_MUSHROOM\", \"FLOWER_POT\")\n            .put(\"POTTED_RED_TULIP\", \"FLOWER_POT\")\n            .put(\"POTTED_SPRUCE_SAPLING\", \"FLOWER_POT\")\n            .put(\"POTTED_TORCHFLOWER\", \"FLOWER_POT\")\n            .put(\"POTTED_WARPED_FUNGUS\", \"FLOWER_POT\")\n            .put(\"POTTED_WARPED_ROOTS\", \"FLOWER_POT\")\n            .put(\"POTTED_WHITE_TULIP\", \"FLOWER_POT\")\n            .put(\"POTTED_WITHER_ROSE\", \"FLOWER_POT\")\n            .put(\"POWDER_SNOW\", \"POWDER_SNOW_BUCKET\")\n            .put(\"POWDER_SNOW_CAULDRON\", \"CAULDRON\")\n            .put(\"PUMPKIN_STEM\", \"PUMPKIN_SEEDS\")\n            .put(\"PURPLE_CANDLE_CAKE\", \"PURPLE_CANDLE\")\n            .put(\"PURPLE_WALL_BANNER\", \"PURPLE_BANNER\")\n            .put(\"RED_CANDLE_CAKE\", \"RED_CANDLE\")\n            .put(\"RED_WALL_BANNER\", \"RED_BANNER\")\n            .put(\"REDSTONE_COMPARATOR_OFF\", \"REDSTONE_COMPARATOR\")\n            .put(\"REDSTONE_COMPARATOR_ON\", \"REDSTONE_COMPARATOR\")\n            .put(\"REDSTONE_LAMP_ON\", \"REDSTONE_LAMP_OFF\")\n            .put(\"REDSTONE_TORCH_OFF\", \"REDSTONE_TORCH_ON\")\n            .put(\"REDSTONE_WALL_TORCH\", \"REDSTONE_TORCH\")\n            .put(\"REDSTONE_WIRE\", \"REDSTONE\")\n            .put(\"SIGN_POST\", \"SIGN\")\n            .put(\"SKELETON_WALL_SKULL\", \"SKELETON_SKULL\")\n            .put(\"SKULL\", \"SKULL_ITEM\")\n            .put(\"SOIL\", \"DIRT\")\n            .put(\"SOUL_FIRE\", \"FIRE_CHARGE\")\n            .put(\"SOUL_WALL_TORCH\", \"SOUL_TORCH\")\n            .put(\"SPRUCE_DOOR\", \"SPRUCE_DOOR_ITEM\")\n            .put(\"SPRUCE_WALL_HANGING_SIGN\", \"SPRUCE_HANGING_SIGN\")\n            .put(\"SPRUCE_WALL_SIGN\", \"SPRUCE_SIGN\")\n            .put(\"STANDING_BANNER\", \"BANNER\")\n            .put(\"STATIONARY_LAVA\", \"LAVA_BUCKET\")\n            .put(\"STATIONARY_WATER\", \"WATER_BUCKET\")\n            .put(\"SUGAR_CANE_BLOCK\", \"SUGAR_CANE\")\n            .put(\"SWEET_BERRY_BUSH\", \"SWEET_BERRIES\")\n            .put(\"TALL_SEAGRASS\", \"SEAGRASS\")\n            .put(\"TORCHFLOWER_CROP\", \"TORCHFLOWER\")\n            .put(\"TRIPWIRE\", \"TRIPWIRE_HOOK\")\n            .put(\"TUBE_CORAL_WALL_FAN\", \"TUBE_CORAL\")\n            .put(\"TWISTING_VINES_PLANT\", \"TWISTING_VINES\")\n            .put(\"WALL_BANNER\", \"BANNER\")\n            .put(\"WALL_SIGN\", \"SIGN\")\n            .put(\"WALL_TORCH\", \"TORCH\")\n            .put(\"WARPED_WALL_HANGING_SIGN\", \"WARPED_HANGING_SIGN\")\n            .put(\"WARPED_WALL_SIGN\", \"WARPED_SIGN\")\n            .put(\"WATER\", \"WATER_BUCKET\")\n            .put(\"WATER_CAULDRON\", \"CAULDRON\")\n            .put(\"WEEPING_VINES_PLANT\", \"WEEPING_VINES\")\n            .put(\"WHITE_CANDLE_CAKE\", \"WHITE_CANDLE\")\n            .put(\"WHITE_WALL_BANNER\", \"WHITE_BANNER\")\n            .put(\"WITHER_SKELETON_WALL_SKULL\", \"WITHER_SKELETON_SKULL\")\n            .put(\"WOODEN_DOOR\", \"WOOD_DOOR\")\n            .put(\"YELLOW_CANDLE_CAKE\", \"YELLOW_CANDLE\")\n            .put(\"YELLOW_WALL_BANNER\", \"YELLOW_BANNER\")\n            .put(\"ZOMBIE_WALL_HEAD\", \"ZOMBIE_HEAD\")\n            .build();\n\n\n    private CountsPagedObjectButton(MenuTemplateButton<MenuCounts.View> templateButton, MenuCounts.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        Key rawKey = pagedObject.getBlockKey();\n        Pair<Key, ItemStack> customKeyItem = plugin.getBlockValues().convertCustomKeyItem(rawKey);\n\n        BigDecimal amount = new BigDecimal(pagedObject.getAmount());\n\n        ItemMeta currentMeta = buttonItem.getItemMeta();\n        ItemBuilder itemBuilder;\n        String materialName;\n\n        ItemStack customItem = customKeyItem.getValue();\n        if (customItem != null) {\n            itemBuilder = new ItemBuilder(customItem);\n            materialName = Optional.ofNullable(rawKey.getSubKey()).orElseGet(rawKey::toString);\n        } else {\n            Key blockKey = customKeyItem.getKey();\n\n            Pair<Material, Short> blockTypeAndData = getMaterialAndData(blockKey);\n            Material blockMaterial = BLOCKS_TO_ITEMS.getOrDefault(blockTypeAndData.getKey(), blockTypeAndData.getKey());\n            short damage = blockTypeAndData.getValue();\n\n            String texture;\n\n            if (blockMaterial == Materials.SPAWNER.toBukkitType() && !blockKey.getSubKey().isEmpty() &&\n                    !(texture = ItemSkulls.getTexture(blockKey.getSubKey())).isEmpty()) {\n                itemBuilder = new ItemBuilder(ItemSkulls.getPlayerHead(Materials.PLAYER_HEAD.toBukkitItem(), texture));\n                materialName = blockKey.getSubKey() + \"_SPAWNER\";\n            } else {\n                itemBuilder = new ItemBuilder(blockMaterial, damage);\n                if (blockMaterial == Materials.SPAWNER.toBukkitType())\n                    materialName = blockKey.getSubKey() + \"_SPAWNER\";\n                else\n                    materialName = rawKey.getGlobalKey();\n            }\n        }\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(rawKey);\n        BigDecimal worthValue = blockValue.getWorth();\n        BigDecimal levelValue = blockValue.getLevel();\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        return itemBuilder\n                .withName(currentMeta.hasDisplayName() ? currentMeta.getDisplayName() : \"\")\n                .withLore(currentMeta.hasLore() ? currentMeta.getLore() : Collections.emptyList())\n                .withAmount(BigInteger.ONE.max(MAX_STACK.min(amount.toBigInteger())).intValue())\n                .replaceAll(\"{0}\", Formatters.CAPITALIZED_FORMATTER.format(materialName))\n                .replaceAll(\"{1}\", amount + \"\")\n                .replaceAll(\"{2}\", Formatters.NUMBER_FORMATTER.format(worthValue.multiply(amount)))\n                .replaceAll(\"{3}\", Formatters.NUMBER_FORMATTER.format(levelValue.multiply(amount)))\n                .replaceAll(\"{4}\", Formatters.FANCY_NUMBER_FORMATTER.format(worthValue.multiply(amount), inventoryViewer.getUserLocale()))\n                .replaceAll(\"{5}\", Formatters.FANCY_NUMBER_FORMATTER.format(levelValue.multiply(amount), inventoryViewer.getUserLocale()))\n                .build(inventoryViewer);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuCounts.View, MenuCounts.BlockCount> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuCounts.View, MenuCounts.BlockCount> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), CountsPagedObjectButton.class,\n                    CountsPagedObjectButton::new);\n        }\n\n    }\n\n    private static class MapBuilder {\n\n        private final EnumMap<Material, Material> mapper = new EnumMap<>(Material.class);\n\n        public MapBuilder put(String block, String item) {\n            Material blockMaterial = EnumHelper.getEnum(Material.class, block);\n            Material itemMaterial = EnumHelper.getEnum(Material.class, item);\n            if (blockMaterial != null && itemMaterial != null)\n                mapper.put(blockMaterial, itemMaterial);\n            return this;\n        }\n\n        public Map<Material, Material> build() {\n            return mapper;\n        }\n\n    }\n\n    private static Pair<Material, Short> getMaterialAndData(Key key) {\n        if (key instanceof MaterialKey)\n            return new Pair<>(((MaterialKey) key).getMaterial(), ((MaterialKey) key).getDurability());\n\n        try {\n            Material blockMaterial = Material.valueOf(key.getGlobalKey());\n            short damage = 0;\n\n            if (!key.getSubKey().isEmpty()) {\n                try {\n                    damage = Short.parseShort(key.getSubKey());\n                } catch (Throwable ignored) {\n                }\n            }\n\n            return new Pair<>(blockMaterial, damage);\n        } catch (Exception ignored) {\n        }\n\n        return new Pair<>(Material.BEDROCK, (short) 0);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CurrentPageButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class CurrentPageButton<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuViewButton<V> {\n\n    private CurrentPageButton(AbstractMenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    public static class Builder<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuTemplateButton.AbstractBuilder<V> {\n\n        @Override\n        public MenuTemplateButton<V> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, CurrentPageButton.class, CurrentPageButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class DisbandButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private DisbandButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island targetIsland = menuView.getIsland();\n\n        if (getTemplate().disbandIsland && PluginEventsFactory.callIslandDisbandEvent(targetIsland, inventoryViewer)) {\n            IslandUtils.sendMessage(targetIsland, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName());\n\n            Message.DISBANDED_ISLAND.send(inventoryViewer);\n\n            if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) {\n                BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund();\n                Message.DISBAND_ISLAND_BALANCE_REFUND.send(targetIsland.getOwner(), Formatters.NUMBER_FORMATTER.format(\n                        targetIsland.getIslandBank().getBalance().multiply(disbandRefund)));\n            }\n\n            if (plugin.getSettings().getDisbandCount() >= 0) {\n                inventoryViewer.setDisbands(inventoryViewer.getDisbands() - 1);\n            }\n\n            targetIsland.disbandIsland();\n        }\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private boolean disbandIsland;\n\n        public Builder setDisbandIsland(boolean disbandIsland) {\n            this.disbandIsland = disbandIsland;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, disbandIsland);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        private final boolean disbandIsland;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean disbandIsland) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    DisbandButton.class, DisbandButton::new);\n            this.disbandIsland = disbandIsland;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DummyButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class DummyButton<V extends MenuView<V, ?>> extends AbstractMenuViewButton<V> {\n\n    public static final MenuTemplateButton EMPTY_BUTTON = new DummyButton.Builder<>().build();\n\n    private DummyButton(AbstractMenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    public static class Builder<V extends MenuView<V, ?>> extends AbstractMenuTemplateButton.AbstractBuilder<V> {\n\n        @Override\n        public MenuTemplateButton<V> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, DummyButton.class, DummyButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class GlobalWarpsPagedObjectButton extends AbstractPagedMenuButton<MenuGlobalWarps.View, Island> {\n\n    private static final String[] EMPTY_STRING_ARRAY = new String[0];\n\n    private GlobalWarpsPagedObjectButton(MenuTemplateButton<MenuGlobalWarps.View> templateButton, MenuGlobalWarps.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        if (Menus.MENU_GLOBAL_WARPS.isVisitorWarps()) {\n            menuView.setPreviousMove(false);\n            plugin.getCommands().dispatchSubCommand(menuView.getInventoryViewer().asPlayer(),\n                    \"visit\", pagedObject.getOwner().getName());\n        } else {\n            plugin.getProviders().getMenusProvider().openWarpCategories(\n                    menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject);\n        }\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        String ownerName = pagedObject.getOwner().getName();\n        String islandName = pagedObject.getName().isEmpty() ? ownerName : pagedObject.getName();\n\n        Locale locale = menuView.getInventoryViewer().getUserLocale();\n        String[] description;\n\n        if (!pagedObject.getDescription().isEmpty())\n            description = pagedObject.getDescription().split(\"\\n\");\n        else if (!Message.ISLAND_DESCRIPTION_NONE.isEmpty(locale))\n            description = new String[] {Message.ISLAND_DESCRIPTION_NONE.getMessage(locale)};\n        else\n            description = EMPTY_STRING_ARRAY;\n\n        return new ItemBuilder(buttonItem)\n                .asSkullOf(pagedObject.getOwner())\n                .replaceAll(\"{0}\", ownerName)\n                .replaceLoreWithLines(\"{1}\", description)\n                .replaceAll(\"{2}\", String.valueOf(pagedObject.getIslandWarps().size()))\n                .replaceAll(\"{3}\", islandName)\n                .replaceAll(\"{4}\", Formatters.NUMBER_FORMATTER.format(pagedObject.getIslandLevel()))\n                .replaceAll(\"{5}\", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getIslandLevel(), locale))\n                .replaceAll(\"{6}\", Formatters.NUMBER_FORMATTER.format(pagedObject.getWorth()))\n                .replaceAll(\"{7}\", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getWorth(), locale))\n                .replaceAll(\"{8}\", Formatters.NUMBER_FORMATTER.format(pagedObject.getTotalRating()))\n                .replaceAll(\"{9}\", Formatters.RATING_FORMATTER.format(pagedObject.getTotalRating(), locale))\n                .replaceAll(\"{10}\", String.valueOf(pagedObject.getRatingAmount()))\n                .build(pagedObject.getOwner());\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuGlobalWarps.View, Island> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuGlobalWarps.View, Island> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), GlobalWarpsPagedObjectButton.class,\n                    GlobalWarpsPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconDisplayButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class IconDisplayButton<E> extends AbstractMenuViewButton<AbstractIconProviderMenu.View<E>> {\n\n    private IconDisplayButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<E>> templateButton,\n                              AbstractIconProviderMenu.View<E> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        TemplateItem iconTemplate = menuView.getIconTemplate();\n        return iconTemplate == null ? null : iconTemplate.build();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    public static class Builder<E> extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<E>> {\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<E>> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, IconDisplayButton.class, IconDisplayButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconEditLoreButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class IconEditLoreButton<E> extends AbstractMenuViewButton<AbstractIconProviderMenu.View<E>> {\n\n    private IconEditLoreButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<E>> templateButton, AbstractIconProviderMenu.View<E> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template<E> getTemplate() {\n        return (Template<E>) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        getTemplate().newLoreMessage.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            if (!message.equalsIgnoreCase(\"-cancel\")) {\n                menuView.getIconTemplate().getEditableBuilder().withLore(message.split(\"\\\\\\\\n\"));\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder<E> extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newLoreMessage;\n\n        public Builder(Message newLoreMessage) {\n            this.newLoreMessage = newLoreMessage;\n        }\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<E>> build() {\n            return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newLoreMessage);\n        }\n\n    }\n\n    public static class Template<E> extends MenuTemplateButtonImpl<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newLoreMessage;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newLoreMessage) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    IconEditLoreButton.class, IconEditLoreButton::new);\n            this.newLoreMessage = Objects.requireNonNull(newLoreMessage, \"newLoreMessage cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconEditTypeButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.Material;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\npublic class IconEditTypeButton<E> extends AbstractMenuViewButton<AbstractIconProviderMenu.View<E>> {\n\n    private IconEditTypeButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<E>> templateButton, AbstractIconProviderMenu.View<E> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template<E> getTemplate() {\n        return (Template<E>) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        getTemplate().newLoreMessage.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            if (!message.equalsIgnoreCase(\"-cancel\")) {\n                String[] sections = message.split(\":\");\n                Material material;\n\n                try {\n                    material = Material.valueOf(sections[0].toUpperCase(Locale.ENGLISH));\n                    if (material == Material.AIR)\n                        throw new IllegalArgumentException();\n                } catch (IllegalArgumentException ex) {\n                    Message.INVALID_MATERIAL.send(player, message);\n                    return true;\n                }\n\n                String rawMessage = sections.length == 2 ? sections[1] : \"0\";\n\n                short data;\n\n                try {\n                    data = Short.parseShort(rawMessage);\n                    if (data < 0)\n                        throw new IllegalArgumentException();\n                } catch (IllegalArgumentException ex) {\n                    Message.INVALID_MATERIAL_DATA.send(player, rawMessage);\n                    return true;\n                }\n\n                menuView.getIconTemplate().getEditableBuilder().withType(material).withDurablity(data);\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder<E> extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newLoreMessage;\n\n        public Builder(Message newLoreMessage) {\n            this.newLoreMessage = newLoreMessage;\n        }\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<E>> build() {\n            return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newLoreMessage);\n        }\n\n    }\n\n    public static class Template<E> extends MenuTemplateButtonImpl<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newLoreMessage;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newLoreMessage) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    IconEditTypeButton.class, IconEditTypeButton::new);\n            this.newLoreMessage = Objects.requireNonNull(newLoreMessage, \"newLoreMessage cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconRenameButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class IconRenameButton<E> extends AbstractMenuViewButton<AbstractIconProviderMenu.View<E>> {\n\n    private IconRenameButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<E>> templateButton, AbstractIconProviderMenu.View<E> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template<E> getTemplate() {\n        return (Template<E>) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        getTemplate().newNameMessage.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            if (!message.equalsIgnoreCase(\"-cancel\")) {\n                menuView.getIconTemplate().getEditableBuilder().withName(message);\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder<E> extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newNameMessage;\n\n        public Builder(Message newNameMessage) {\n            this.newNameMessage = newNameMessage;\n        }\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<E>> build() {\n            return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newNameMessage);\n        }\n\n    }\n\n    public static class Template<E> extends MenuTemplateButtonImpl<AbstractIconProviderMenu.View<E>> {\n\n        private final Message newNameMessage;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newNameMessage) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    IconRenameButton.class, IconRenameButton::new);\n            this.newNameMessage = Objects.requireNonNull(newNameMessage, \"newNameMessage cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandChestPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandChest;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class IslandChestPagedObjectButton extends AbstractPagedMenuButton<MenuIslandChest.View, IslandChest> {\n\n    private IslandChestPagedObjectButton(MenuTemplateButton<MenuIslandChest.View> templateButton, MenuIslandChest.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n        pagedObject.openChest(menuView.getInventoryViewer());\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", (pagedObject.getIndex() + 1) + \"\")\n                .replaceAll(\"{1}\", (pagedObject.getRows() * 9) + \"\")\n                .build(menuView.getInventoryViewer());\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandChest.View, IslandChest> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandChest.View, IslandChest> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), IslandChestPagedObjectButton.class,\n                    IslandChestPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuConfig;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation;\nimport org.bukkit.Bukkit;\nimport org.bukkit.block.Biome;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class IslandCreationButton extends AbstractMenuViewButton<MenuIslandCreation.View> {\n\n    private IslandCreationButton(AbstractMenuTemplateButton<MenuIslandCreation.View> templateButton, MenuIslandCreation.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        String requiredPermission = getTemplate().getRequiredPermission();\n        return (requiredPermission == null || inventoryViewer.hasPermission(requiredPermission) ?\n                getTemplate().getAccessItem() : getTemplate().lackPermissionItem).build(inventoryViewer);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n        MenuActions.simulateIslandCreationClick(clickedPlayer, menuView.getIslandName(),\n                getTemplate().getCreationConfig(), clickEvent.getClick().isRightClick(), menuView);\n    }\n\n    @Override\n    public void onButtonClickLackPermission(InventoryClickEvent clickEvent) {\n        super.onButtonClickLackPermission(clickEvent);\n        getTemplate().lackPermissionCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", clickEvent.getWhoClicked().getName())));\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuIslandCreation.View> {\n\n        private final Schematic schematic;\n        private TemplateItem noAccessItem = null;\n        private List<String> noAccessCommands = null;\n        @Nullable\n        private Biome biome;\n        private BigDecimal bonusWorth;\n        private BigDecimal bonusLevel;\n        private boolean isOffset;\n        private BlockOffset spawnOffset = null;\n\n        public Builder(Schematic schematic) {\n            this.schematic = schematic;\n        }\n\n        public void setAccessItem(TemplateItem accessItem) {\n            this.buttonItem = accessItem;\n        }\n\n        public void setNoAccessItem(TemplateItem noAccessItem) {\n            this.noAccessItem = noAccessItem;\n        }\n\n        public void setAccessSound(GameSound accessSound) {\n            this.clickSound = accessSound;\n        }\n\n        public void setNoAccessSound(GameSound noAccessSound) {\n            this.lackPermissionSound = noAccessSound;\n        }\n\n        public void setAccessCommands(List<String> accessCommands) {\n            this.commands = accessCommands;\n        }\n\n        public void setNoAccessCommands(List<String> noAccessCommands) {\n            this.noAccessCommands = noAccessCommands;\n        }\n\n        public void setBiome(Biome biome) {\n            this.biome = biome;\n        }\n\n        public void setBonusWorth(BigDecimal bonusWorth) {\n            this.bonusWorth = bonusWorth;\n        }\n\n        public void setBonusLevel(BigDecimal bonusLevel) {\n            this.bonusLevel = bonusLevel;\n        }\n\n        public void setOffset(boolean isOffset) {\n            this.isOffset = isOffset;\n        }\n\n        public void setSpawnOffset(BlockOffset spawnOffset) {\n            this.spawnOffset = spawnOffset;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuIslandCreation.View> build() {\n            return new Template(requiredPermission, lackPermissionSound, clickSound, commands, noAccessItem,\n                    noAccessCommands, biome, bonusWorth, bonusLevel, isOffset, buttonItem, spawnOffset, schematic);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuIslandCreation.View> {\n\n        @Nullable\n        private final GameSound accessSound;\n        private final List<String> accessCommands;\n        private final TemplateItem lackPermissionItem;\n        private final List<String> lackPermissionCommands;\n        @Nullable\n        private final Biome biome;\n        private final BigDecimal bonusWorth;\n        private final BigDecimal bonusLevel;\n        private final boolean isOffset;\n        private final Schematic schematic;\n        @Nullable\n        private final BlockOffset spawnOffset;\n\n        private final MenuIslandCreationConfig creationConfig;\n\n        Template(@Nullable String requiredPermission, @Nullable GameSound lackPermissionSound,\n                 @Nullable GameSound accessSound, @Nullable List<String> accessCommands,\n                 @Nullable TemplateItem lackPermissionItem, @Nullable List<String> lackPermissionCommands,\n                 @Nullable Biome biome, @Nullable BigDecimal bonusWorth, @Nullable BigDecimal bonusLevel, boolean isOffset,\n                 @Nullable TemplateItem accessItem, @Nullable BlockOffset spawnOffset, Schematic schematic) {\n            super(accessItem == null ? TemplateItem.AIR : accessItem, null, null, requiredPermission,\n                    lackPermissionSound, IslandCreationButton.class, IslandCreationButton::new);\n            this.accessSound = accessSound;\n            this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands;\n            this.lackPermissionItem = lackPermissionItem == null ? TemplateItem.AIR : lackPermissionItem;\n            this.lackPermissionCommands = lackPermissionCommands == null ? Collections.emptyList() : lackPermissionCommands;\n            this.biome = biome;\n            this.bonusWorth = bonusWorth == null ? BigDecimal.ZERO : bonusWorth;\n            this.bonusLevel = bonusLevel == null ? BigDecimal.ZERO : bonusLevel;\n            this.isOffset = isOffset;\n            this.spawnOffset = spawnOffset;\n            this.schematic = Objects.requireNonNull(schematic, \"schematic cannot be null\");\n            this.creationConfig = new MenuConfig.IslandCreation(this);\n        }\n\n        public TemplateItem getAccessItem() {\n            return super.getButtonTemplateItem();\n        }\n\n        @Nullable\n        public GameSound getAccessSound() {\n            return accessSound;\n        }\n\n        public List<String> getAccessCommands() {\n            return accessCommands;\n        }\n\n        @Nullable\n        public Biome getBiome() {\n            return biome;\n        }\n\n        public BigDecimal getBonusWorth() {\n            return bonusWorth;\n        }\n\n        public BigDecimal getBonusLevel() {\n            return bonusLevel;\n        }\n\n        public boolean isOffset() {\n            return isOffset;\n        }\n\n        public Schematic getSchematic() {\n            return schematic;\n        }\n\n        public BlockOffset getSpawnOffset() {\n            return spawnOffset;\n        }\n\n        public MenuIslandCreationConfig getCreationConfig() {\n            return creationConfig;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandFlags;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class IslandFlagPagedObjectButton extends AbstractPagedMenuButton<MenuIslandFlags.View, MenuIslandFlags.IslandFlagInfo> {\n\n    private IslandFlagPagedObjectButton(MenuTemplateButton<MenuIslandFlags.View> templateButton, MenuIslandFlags.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        Island island = menuView.getIsland();\n\n        IslandFlag islandFlag = pagedObject.getIslandFlag();\n\n        if (islandFlag == null)\n            return;\n\n        if (island.hasSettingsEnabled(islandFlag)) {\n            if (!PluginEventsFactory.callIslandDisableFlagEvent(island, inventoryViewer, islandFlag))\n                return;\n\n            island.disableSettings(islandFlag);\n        } else {\n            if (!PluginEventsFactory.callIslandEnableFlagEvent(island, inventoryViewer, islandFlag))\n                return;\n\n            island.enableSettings(islandFlag);\n        }\n\n        GameSoundImpl.playSound(clickEvent.getWhoClicked(), pagedObject.getClickSound());\n\n        Message.UPDATED_SETTINGS.send(inventoryViewer, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()));\n\n        menuView.refreshView();\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island island = menuView.getIsland();\n\n        IslandFlag islandFlag = pagedObject.getIslandFlag();\n\n        return islandFlag != null && island.hasSettingsEnabled(islandFlag) ?\n                pagedObject.getEnabledIslandFlagItem().build(inventoryViewer) :\n                pagedObject.getDisabledIslandFlagItem().build(inventoryViewer);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandFlags.View, MenuIslandFlags.IslandFlagInfo> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandFlags.View, MenuIslandFlags.IslandFlagInfo> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), IslandFlagPagedObjectButton.class,\n                    IslandFlagPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PermissionNode;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Material;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class IslandPrivilegePagedObjectButton extends AbstractPagedMenuButton<MenuIslandPrivileges.View, MenuIslandPrivileges.IslandPrivilegeInfo> {\n\n    private final PrivilegeButtonActions actions;\n\n    private IslandPrivilegePagedObjectButton(MenuTemplateButton<MenuIslandPrivileges.View> templateButton, MenuIslandPrivileges.View menuView) {\n        super(templateButton, menuView);\n\n        if (menuView.getPermissionHolder() instanceof PlayerRole) {\n            this.actions = RolePrivilegeButtonActions.INSTANCE;\n        } else {\n            this.actions = PlayerPrivilegeButtonActions.INSTANCE;\n        }\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        this.actions.onButtonClick(clickEvent, this);\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return this.actions.modifyViewItem(buttonItem, this);\n    }\n\n    private static void onSuccessfulPermissionChange(IslandPrivilegePagedObjectButton button,\n                                                     SuperiorPlayer clickedPlayer, String permissionHolderName) {\n        Player player = clickedPlayer.asPlayer();\n\n        if (player == null)\n            return;\n\n        Message.UPDATED_PERMISSION.send(clickedPlayer, permissionHolderName);\n\n        GameSoundImpl.playSound(player, button.pagedObject.getAccessSound());\n\n        button.pagedObject.getAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", clickedPlayer.getName())));\n\n        Menus.MENU_ISLAND_PRIVILEGES.refreshViews();\n    }\n\n    private static void onFailurePermissionChange(IslandPrivilegePagedObjectButton button,\n                                                  SuperiorPlayer clickedPlayer, boolean sendFailMessage) {\n        Player player = clickedPlayer.asPlayer();\n\n        if (player == null)\n            return;\n\n        if (sendFailMessage)\n            Message.LACK_CHANGE_PERMISSION.send(clickedPlayer);\n\n        GameSoundImpl.playSound(player, button.pagedObject.getNoAccessSound());\n\n        button.pagedObject.getNoAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%player%\", clickedPlayer.getName())));\n    }\n\n    private static boolean isRoleAllowed(@Nullable PlayerRole playerRole, @Nullable IslandPrivilege.Type islandPrivilegeType) {\n        if (!plugin.getSettings().isCoopMembers() && playerRole == SPlayerRole.coopRole())\n            return false;\n\n        if (islandPrivilegeType == IslandPrivilege.Type.COMMAND &&\n                playerRole != null && playerRole.isLessThan(SPlayerRole.defaultRole())) {\n            return false;\n        }\n\n        return true;\n    }\n\n    private interface PrivilegeButtonActions {\n\n        void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button);\n\n        ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button);\n\n    }\n\n    private static class RolePrivilegeButtonActions implements PrivilegeButtonActions {\n\n        private static final RolePrivilegeButtonActions INSTANCE = new RolePrivilegeButtonActions();\n\n        @Override\n        public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) {\n            IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege();\n\n            if (islandPrivilege == null)\n                return;\n\n            Island island = button.menuView.getIsland();\n            SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer();\n            IslandPrivilege.Type islandPrivilegeType = islandPrivilege.getType();\n\n            PlayerRole currentRole = island.getRequiredPlayerRole(islandPrivilege);\n\n            if (clickedPlayer.getPlayerRole().isLessThan(currentRole)) {\n                onFailurePermissionChange(button, clickedPlayer, false);\n                return;\n            }\n\n            PlayerRole newRole = null;\n\n            if (clickEvent.getClick().isLeftClick()) {\n                newRole = currentRole;\n                do {\n                    newRole = SPlayerRole.of(newRole.getWeight() - 1);\n                } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType));\n\n                if (newRole == null)\n                    newRole = clickedPlayer.getPlayerRole();\n            } else {\n                if (clickedPlayer.getPlayerRole().isHigherThan(currentRole)) {\n                    newRole = currentRole;\n                    do {\n                        newRole = SPlayerRole.of(newRole.getWeight() + 1);\n                    } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType));\n                }\n\n                if (newRole == null) {\n                    newRole = islandPrivilegeType == IslandPrivilege.Type.COMMAND ? SPlayerRole.defaultRole() : SPlayerRole.guestRole();\n                }\n            }\n\n            if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) {\n                island.setPermission(newRole, islandPrivilege);\n                onSuccessfulPermissionChange(button, clickedPlayer,\n                        Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()));\n            }\n        }\n\n        @Override\n        public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) {\n            ItemBuilder permissionItem = button.pagedObject.getRoleIslandPrivilegeItem();\n            if (permissionItem == null)\n                return new ItemStack(Material.AIR);\n\n            IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege();\n            Island island = button.menuView.getIsland();\n\n            PlayerRole requiredRole = islandPrivilege == null ? null : island.getRequiredPlayerRole(islandPrivilege);\n            IslandPrivilege.Type islandPrivilegeType = islandPrivilege == null ? null : islandPrivilege.getType();\n\n            permissionItem.replaceAll(\"{}\", requiredRole == null ? \"\" : requiredRole.toString());\n\n            if (!Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().isEmpty() &&\n                    !Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().isEmpty() &&\n                    !Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().isEmpty()) {\n                List<String> roleString = new ArrayList<>();\n\n                int roleWeight = requiredRole == null ? Integer.MAX_VALUE : requiredRole.getWeight();\n\n                PlayerRole currentRole;\n                for (int i = -2; (currentRole = SPlayerRole.of(i)) != null; i++) {\n                    if (!isRoleAllowed(currentRole, islandPrivilegeType))\n                        continue;\n\n                    if (i < roleWeight) {\n                        roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().replace(\"{}\", currentRole + \"\"));\n                    } else if (i == roleWeight) {\n                        roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().replace(\"{}\", currentRole + \"\"));\n                    } else {\n                        roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().replace(\"{}\", currentRole + \"\"));\n                    }\n                }\n\n                ItemMeta itemMeta = permissionItem.getItemMeta();\n\n                if (itemMeta != null) {\n                    List<String> lore = itemMeta.getLore();\n\n                    for (int i = 0; i < lore.size(); i++) {\n                        String line = lore.get(i);\n                        if (line.equals(\"{0}\")) {\n                            lore.set(i, roleString.get(0));\n                            for (int j = 1; j < roleString.size(); j++) {\n                                lore.add(i + j, roleString.get(j));\n                            }\n                            i += roleString.size();\n                        }\n                    }\n\n                    permissionItem.withLore(lore);\n                }\n            }\n\n            return permissionItem.build(button.menuView.getInventoryViewer());\n        }\n\n    }\n\n    private static class PlayerPrivilegeButtonActions implements PrivilegeButtonActions {\n\n        private static final PlayerPrivilegeButtonActions INSTANCE = new PlayerPrivilegeButtonActions();\n\n        @Override\n        public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) {\n            IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege();\n\n            if (islandPrivilege == null)\n                return;\n\n            Island island = button.menuView.getIsland();\n            SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer();\n\n            if (!island.hasPermission(clickedPlayer, islandPrivilege))\n                return;\n\n            SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder();\n\n            PermissionNode permissionNode = island.getPermissionNode(permissiblePlayer);\n\n            String permissionHolderName = permissiblePlayer.getName();\n\n            boolean currentValue = permissionNode.hasPermission(islandPrivilege);\n\n            if (!PluginEventsFactory.callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissiblePlayer, !currentValue))\n                return;\n\n            island.setPermission(permissiblePlayer, islandPrivilege, !currentValue);\n\n            onSuccessfulPermissionChange(button, clickedPlayer, permissionHolderName);\n        }\n\n        @Override\n        public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) {\n            IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege();\n            Island targetIsland = button.menuView.getIsland();\n            SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder();\n\n            boolean hasPermission = islandPrivilege != null &&\n                    targetIsland.getPermissionNode(permissiblePlayer).hasPermission(islandPrivilege);\n\n            ItemBuilder permissionItem = hasPermission ? button.pagedObject.getEnabledIslandPrivilegeItem() :\n                    button.pagedObject.getDisabledIslandPrivilegeItem();\n\n            return permissionItem.build(button.menuView.getInventoryViewer());\n        }\n\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandPrivileges.View, MenuIslandPrivileges.IslandPrivilegeInfo> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandPrivileges.View, MenuIslandPrivileges.IslandPrivilegeInfo> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), IslandPrivilegePagedObjectButton.class,\n                    IslandPrivilegePagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\n\npublic class KickButton extends AbstractMenuViewButton<MenuConfirmKick.View> {\n\n    private KickButton(AbstractMenuTemplateButton<MenuConfirmKick.View> templateButton, MenuConfirmKick.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        if (getTemplate().kickPlayer)\n            IslandUtils.handleKickPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer());\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuConfirmKick.View> {\n\n        private boolean kickPlayer;\n\n        public Builder setKickPlayer(boolean kickPlayer) {\n            this.kickPlayer = kickPlayer;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuConfirmKick.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, kickPlayer);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuConfirmKick.View> {\n\n        private final boolean kickPlayer;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean kickPlayer) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    KickButton.class, KickButton::new);\n            this.kickPlayer = kickPlayer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\npublic class LanguageButton extends AbstractMenuViewButton<BaseMenuView> {\n\n    private LanguageButton(AbstractMenuTemplateButton<BaseMenuView> templateButton, BaseMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        Locale language = getTemplate().language;\n\n        if (!PluginEventsFactory.callPlayerChangeLanguageEvent(inventoryViewer, language))\n            return;\n\n        inventoryViewer.setUserLocale(language);\n\n        Message.CHANGED_LANGUAGE.send(inventoryViewer);\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<BaseMenuView> {\n\n        private Locale language;\n\n        public Builder setLanguage(Locale language) {\n            this.language = language;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<BaseMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, language);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<BaseMenuView> {\n\n        private final Locale language;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Locale language) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    LanguageButton.class, LanguageButton::new);\n            this.language = Objects.requireNonNull(language, \"language cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\n\npublic class LeaveButton extends AbstractMenuViewButton<BaseMenuView> {\n\n    private LeaveButton(AbstractMenuTemplateButton<BaseMenuView> templateButton, BaseMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island island = inventoryViewer.getIsland();\n\n        if (getTemplate().leaveIsland && island != null) {\n            IslandUtils.handleLeaveIsland(inventoryViewer, island);\n        }\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<BaseMenuView> {\n\n        private boolean leaveIsland;\n\n        public Builder setLeaveIsland(boolean leaveIsland) {\n            this.leaveIsland = leaveIsland;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<BaseMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, leaveIsland);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<BaseMenuView> {\n\n        private final boolean leaveIsland;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean leaveIsland) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    LeaveButton.class, LeaveButton::new);\n            this.leaveIsland = leaveIsland;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class MemberManageButton extends AbstractMenuViewButton<PlayerMenuView> {\n\n    private MemberManageButton(AbstractMenuTemplateButton<PlayerMenuView> templateButton, PlayerMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        getTemplate().manageAction.onButtonClick(menuView, clickEvent);\n    }\n\n    public enum ManageAction {\n\n        SET_ROLE {\n            @Override\n            void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) {\n                menuView.setPreviousMove(false);\n                plugin.getMenus().openMemberRole(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getSuperiorPlayer());\n            }\n        },\n        BAN_MEMBER {\n            @Override\n            void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) {\n                SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n                if (plugin.getSettings().isBanConfirm()) {\n                    Island island = inventoryViewer.getIsland();\n                    if (IslandUtils.checkBanRestrictions(inventoryViewer, island, menuView.getSuperiorPlayer())) {\n                        menuView.setPreviousMove(false);\n                        plugin.getMenus().openConfirmBan(inventoryViewer, MenuViewWrapper.fromView(menuView), island, menuView.getSuperiorPlayer());\n                    }\n                } else {\n                    plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"ban\", menuView.getSuperiorPlayer().getName());\n                }\n            }\n        },\n        KICK_MEMBER {\n            @Override\n            void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) {\n                SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n                if (plugin.getSettings().isKickConfirm()) {\n                    Island island = inventoryViewer.getIsland();\n\n                    if (island == null)\n                        return;\n\n                    if (IslandUtils.checkKickRestrictions(inventoryViewer, island, menuView.getSuperiorPlayer())) {\n                        menuView.setPreviousMove(false);\n                        plugin.getMenus().openConfirmKick(inventoryViewer, MenuViewWrapper.fromView(menuView), island, menuView.getSuperiorPlayer());\n                    }\n                } else {\n                    plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"kick\", menuView.getSuperiorPlayer().getName());\n                }\n            }\n        };\n\n        ManageAction() {\n\n        }\n\n        abstract void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent);\n\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<PlayerMenuView> {\n\n        private ManageAction manageAction;\n\n        public Builder setManageAction(ManageAction manageAction) {\n            this.manageAction = manageAction;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<PlayerMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, manageAction);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<PlayerMenuView> {\n\n        private final ManageAction manageAction;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, ManageAction manageAction) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    MemberManageButton.class, MemberManageButton::new);\n            this.manageAction = Objects.requireNonNull(manageAction, \"manageAction cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class MemberRoleButton extends AbstractMenuViewButton<PlayerMenuView> {\n\n    private MemberRoleButton(AbstractMenuTemplateButton<PlayerMenuView> templateButton, PlayerMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player inventoryViewer = menuView.getInventoryViewer().asPlayer();\n        SuperiorPlayer targetPlayer = menuView.getSuperiorPlayer();\n        PlayerRole playerRole = plugin.getRoles().getPlayerRoleFromId(getTemplate().playerRoleId);\n\n        if (playerRole.isLastRole()) {\n            plugin.getCommands().dispatchSubCommand(inventoryViewer, \"transfer\",\n                    targetPlayer.getName());\n        } else {\n            plugin.getCommands().dispatchSubCommand(inventoryViewer, \"setrole\",\n                    targetPlayer.getName() + \" \" + playerRole);\n        }\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<PlayerMenuView> {\n\n        private int playerRoleId;\n\n        public Builder setPlayerRole(PlayerRole playerRole) {\n            this.playerRoleId = Objects.requireNonNull(playerRole, \"playerRole cannot be null\").getId();\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<PlayerMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, playerRoleId);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<PlayerMenuView> {\n\n        private final int playerRoleId;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, int playerRoleId) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    MemberRoleButton.class, MemberRoleButton::new);\n            this.playerRoleId = playerRoleId;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MembersPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class MembersPagedObjectButton extends AbstractPagedMenuButton<MenuIslandMembers.View, SuperiorPlayer> {\n\n    private MembersPagedObjectButton(MenuTemplateButton<MenuIslandMembers.View> templateButton, MenuIslandMembers.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openMemberManage(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject);\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", pagedObject.getName())\n                .replaceAll(\"{1}\", pagedObject.getPlayerRole() + \"\")\n                .asSkullOf(pagedObject)\n                .build(pagedObject);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandMembers.View, SuperiorPlayer> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandMembers.View, SuperiorPlayer> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), MembersPagedObjectButton.class,\n                    MembersPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory;\nimport com.bgsoftware.superiorskyblock.mission.MissionData;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport org.bukkit.Material;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\nimport java.util.Optional;\n\npublic class MissionsPagedObjectButton extends AbstractPagedMenuButton<MenuMissionsCategory.View, MissionReference> {\n\n    private MissionsPagedObjectButton(MenuTemplateButton<MenuMissionsCategory.View> templateButton, MenuMissionsCategory.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Mission<?> mission = pagedObject.getMission();\n\n        if (mission == null)\n            return;\n\n        Optional<MissionData> missionDataOptional = plugin.getMissions().getMissionData(mission);\n\n        if (!missionDataOptional.isPresent())\n            return;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        MissionData missionData = missionDataOptional.get();\n        IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer;\n\n        if (missionsHolder == null)\n            return;\n\n        boolean canComplete = plugin.getMissions().canComplete(inventoryViewer, mission);\n\n        GameSound gameSound;\n\n        if (!missionsHolder.canCompleteMissionAgain(mission))\n            gameSound = getTemplate().completedSound;\n        else if (getTemplate().lockedSound != null && missionData.hasLocked()\n                && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer))\n            gameSound = getTemplate().lockedSound;\n        else if (canComplete)\n            gameSound = getTemplate().canCompleteSound;\n        else\n            gameSound = getTemplate().notCompletedSound;\n\n        GameSoundImpl.playSound(clickEvent.getWhoClicked(), gameSound);\n\n        if (!canComplete)\n            return;\n\n        plugin.getMissions().rewardMission(mission, inventoryViewer, false, false, result -> {\n            if (result)\n                menuView.refreshView();\n        });\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        Mission<?> mission = pagedObject.getMission();\n\n        if (mission == null)\n            return buttonItem;\n\n        Optional<MissionData> missionDataOptional = plugin.getMissions().getMissionData(mission);\n\n        if (!missionDataOptional.isPresent())\n            return buttonItem;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        MissionData missionData = missionDataOptional.get();\n        IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer;\n\n        if (missionsHolder == null)\n            return new ItemStack(Material.AIR);\n\n        int percentage = calculatePercentage(mission.getProgress(inventoryViewer));\n        int progressValue = mission.getProgressValue(inventoryViewer);\n        int amountCompleted = missionsHolder.getAmountMissionCompleted(mission);\n\n        ItemBuilder itemBuilder;\n\n        if (!missionsHolder.canCompleteMissionAgain(mission))\n            itemBuilder = missionData.getCompleted();\n        else if (missionData.hasLocked() && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer))\n            itemBuilder = missionData.getLocked();\n        else if (plugin.getMissions().canComplete(inventoryViewer, mission))\n            itemBuilder = missionData.getCanComplete();\n        else\n            itemBuilder = missionData.getNotCompleted();\n\n        ItemStack itemStack = itemBuilder\n                .replaceAll(\"{0}\", percentage + \"\")\n                .replaceAll(\"{1}\", progressValue + \"\")\n                .replaceAll(\"{2}\", amountCompleted + \"\")\n                .build(inventoryViewer);\n\n        mission.formatItem(inventoryViewer, itemStack);\n\n        return itemStack;\n    }\n\n    private static int calculatePercentage(double progress) {\n        return Math.round((float) Math.min(1.0, progress) * 100);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuMissionsCategory.View, MissionReference> {\n\n        private GameSound notCompletedSound = null;\n        private GameSound canCompleteSound = null;\n        private GameSound lockedSound = null;\n\n        public Builder setCompletedSound(GameSound completedSound) {\n            this.clickSound = completedSound;\n            return this;\n        }\n\n        public Builder setNotCompletedSound(GameSound notCompletedSound) {\n            this.notCompletedSound = notCompletedSound;\n            return this;\n        }\n\n        public Builder setCanCompleteSound(GameSound canCompleteSound) {\n            this.canCompleteSound = canCompleteSound;\n            return this;\n        }\n\n        public Builder setLockedSound(GameSound lockedSound) {\n            this.lockedSound = lockedSound;\n            return this;\n        }\n\n        @Override\n        public PagedMenuTemplateButton<MenuMissionsCategory.View, MissionReference> build() {\n            return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, nullItem,\n                    getButtonIndex(), clickSound, notCompletedSound, canCompleteSound, lockedSound);\n        }\n\n    }\n\n    public static class Template extends PagedMenuTemplateButtonImpl<MenuMissionsCategory.View, MissionReference> {\n\n        private final GameSound completedSound;\n        private final GameSound notCompletedSound;\n        private final GameSound canCompleteSound;\n        private final GameSound lockedSound;\n\n        Template(TemplateItem buttonItem, List<String> commands, String requiredPermission,\n                 GameSound lackPermissionSound, TemplateItem nullItem, int buttonIndex,\n                 GameSound completedSound, GameSound notCompletedSound, GameSound canCompleteSound, GameSound lockedSound) {\n            super(buttonItem, null, commands, requiredPermission, lackPermissionSound, nullItem, buttonIndex,\n                    MissionsPagedObjectButton.class, MissionsPagedObjectButton::new);\n            this.completedSound = completedSound;\n            this.notCompletedSound = notCompletedSound;\n            this.canCompleteSound = canCompleteSound;\n            this.lockedSound = lockedSound;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/NextPageButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class NextPageButton<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuViewButton<V> {\n\n    private NextPageButton(AbstractMenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        PagedMenuLayout<V> pagedMenuPattern = (PagedMenuLayout<V>) menuView.getMenu().getLayout();\n\n        if (pagedMenuPattern == null)\n            return;\n\n        int pageObjectSlotsAmount = pagedMenuPattern.getObjectsPerPageCount();\n        int currentPage = menuView.getCurrentPage();\n        int pagedObjectAmounts = menuView.getPagedObjects().size();\n\n        if (pageObjectSlotsAmount * currentPage < pagedObjectAmounts)\n            menuView.setCurrentPage(currentPage + 1);\n    }\n\n    public static class Builder<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuTemplateButton.AbstractBuilder<V> {\n\n        @Override\n        public MenuTemplateButton<V> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, NextPageButton.class, NextPageButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class OpenBankLogsButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private OpenBankLogsButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openBankLogs(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getIsland());\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, OpenBankLogsButton.class, OpenBankLogsButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class OpenMissionCategoryButton extends AbstractMenuViewButton<BaseMenuView> {\n\n    private OpenMissionCategoryButton(AbstractMenuTemplateButton<BaseMenuView> templateButton, BaseMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        if (getTemplate().requireIsland && !menuView.getInventoryViewer().hasIsland()) {\n            Message.INVALID_ISLAND.send(menuView.getInventoryViewer());\n            return;\n        }\n\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openMissionsCategory(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), getTemplate().missionCategory);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<BaseMenuView> {\n\n        private MissionCategory missionCategory;\n\n        public Builder setMissionsCategory(MissionCategory missionCategory) {\n            this.missionCategory = missionCategory;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<BaseMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, missionCategory);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<BaseMenuView> {\n\n        private final MissionCategory missionCategory;\n        private final boolean requireIsland;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, MissionCategory missionCategory) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    OpenMissionCategoryButton.class, OpenMissionCategoryButton::new);\n            this.missionCategory = Objects.requireNonNull(missionCategory, \"missionCategory cannot be null\");\n            this.requireIsland = !plugin.getMissions().isPlayerMissionCategory(missionCategory);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenUniqueVisitorsButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class OpenUniqueVisitorsButton extends AbstractMenuViewButton<MenuIslandVisitors.View> {\n\n    private OpenUniqueVisitorsButton(AbstractMenuTemplateButton<MenuIslandVisitors.View> templateButton, MenuIslandVisitors.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openUniqueVisitors(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getIsland());\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuIslandVisitors.View> {\n\n        @Override\n        public MenuTemplateButton<MenuIslandVisitors.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, OpenUniqueVisitorsButton.class, OpenUniqueVisitorsButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/PreviousPageButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class PreviousPageButton<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuViewButton<V> {\n\n    private PreviousPageButton(AbstractMenuTemplateButton<V> templateButton, V menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        int newPage = menuView.getCurrentPage() - 1;\n        if (newPage >= 1)\n            menuView.setCurrentPage(newPage);\n    }\n\n    public static class Builder<V extends PagedMenuView<V, ?, E>, E> extends AbstractMenuTemplateButton.AbstractBuilder<V> {\n\n        @Override\n        public MenuTemplateButton<V> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, PreviousPageButton.class, PreviousPageButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class RateIslandButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private RateIslandButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island island = menuView.getIsland();\n        Rating rating = getTemplate().rating;\n\n        if (rating == Rating.UNKNOWN) {\n            if (!PluginEventsFactory.callIslandRemoveRatingEvent(island, inventoryViewer, inventoryViewer))\n                return;\n\n            island.removeRating(inventoryViewer);\n        } else {\n            if (!PluginEventsFactory.callIslandRateEvent(island, inventoryViewer, inventoryViewer, rating))\n                return;\n\n            island.setRating(inventoryViewer, rating);\n        }\n\n        Message.RATE_SUCCESS.send(inventoryViewer, rating.getValue());\n\n        IslandUtils.sendMessage(island, Message.RATE_ANNOUNCEMENT, Collections.emptyList(),\n                inventoryViewer.getName(), rating.getValue());\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private Rating rating;\n\n        public Builder setRating(Rating rating) {\n            this.rating = rating;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, rating);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        private final Rating rating;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Rating rating) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    RateIslandButton.class, RateIslandButton::new);\n            this.rating = Objects.requireNonNull(rating, \"rating cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RatingsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRatings;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class RatingsPagedObjectButton extends AbstractPagedMenuButton<MenuIslandRatings.View, MenuIslandRatings.RatingInfo> {\n\n    private RatingsPagedObjectButton(MenuTemplateButton<MenuIslandRatings.View> templateButton, MenuIslandRatings.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy button\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(pagedObject.getPlayerUUID());\n\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", ratingPlayer.getName())\n                .replaceAll(\"{1}\", Formatters.RATING_FORMATTER.format(pagedObject.getRating().getValue(), ratingPlayer.getUserLocale()))\n                .asSkullOf(ratingPlayer)\n                .build(ratingPlayer);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandRatings.View, MenuIslandRatings.RatingInfo> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandRatings.View, MenuIslandRatings.RatingInfo> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), RatingsPagedObjectButton.class,\n                    RatingsPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class TopIslandsPagedObjectButton extends AbstractPagedMenuButton<MenuTopIslands.View, Island> {\n\n    private TopIslandsPagedObjectButton(MenuTemplateButton<MenuTopIslands.View> templateButton, MenuTopIslands.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        TopIslandsSelfIslandButton.onButtonClick(clickEvent, menuView, pagedObject, getTemplate().islandSound, getTemplate().islandCommands,\n                getTemplate().noIslandSound, getTemplate().noIslandCommands);\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        if (pagedObject == null) {\n            return getTemplate().getNullTemplateItem().build();\n        } else {\n            return TopIslandsSelfIslandButton.modifyViewItem(menuView, pagedObject, getTemplate().islandItem);\n        }\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuTopIslands.View, Island> {\n\n        private TemplateItem noIslandItem;\n        private GameSound noIslandSound;\n        private List<String> noIslandCommands;\n\n        public void setIslandItem(TemplateItem islandItem) {\n            this.buttonItem = islandItem;\n        }\n\n        public void setNoIslandItem(TemplateItem noIslandItem) {\n            this.noIslandItem = noIslandItem;\n        }\n\n        public void setIslandSound(GameSound islandSound) {\n            this.clickSound = islandSound;\n        }\n\n        public void setNoIslandSound(GameSound noIslandSound) {\n            this.noIslandSound = noIslandSound;\n        }\n\n        public void setIslandCommands(List<String> islandCommands) {\n            this.commands = islandCommands;\n        }\n\n        public void setNoIslandCommands(List<String> noIslandCommands) {\n            this.noIslandCommands = noIslandCommands;\n        }\n\n        @Override\n        public PagedMenuTemplateButton<MenuTopIslands.View, Island> build() {\n            return new Template(requiredPermission, lackPermissionSound, buttonItem,\n                    clickSound, commands, noIslandItem, noIslandSound, noIslandCommands, getButtonIndex());\n        }\n\n    }\n\n    public static class Template extends PagedMenuTemplateButtonImpl<MenuTopIslands.View, Island> {\n\n        private final TemplateItem islandItem;\n        private final GameSound islandSound;\n        private final GameSound noIslandSound;\n        private final List<String> islandCommands;\n        private final List<String> noIslandCommands;\n\n        Template(String requiredPermission, GameSound lackPermissionSound,\n                 TemplateItem islandItem, GameSound islandSound, List<String> islandCommands,\n                 TemplateItem noIslandItem, GameSound noIslandSound, List<String> noIslandCommands, int buttonIndex) {\n            super(null, null, null, requiredPermission, lackPermissionSound, noIslandItem,\n                    buttonIndex, TopIslandsPagedObjectButton.class, TopIslandsPagedObjectButton::new);\n            this.islandItem = islandItem;\n            this.islandSound = islandSound;\n            this.islandCommands = islandCommands == null ? Collections.emptyList() : islandCommands;\n            this.noIslandSound = noIslandSound;\n            this.noIslandCommands = noIslandCommands == null ? Collections.emptyList() : noIslandCommands;\n            if (this.getNullTemplateItem() != null)\n                this.getNullTemplateItem().getEditableBuilder().asSkullOf((SuperiorPlayer) null);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class TopIslandsSelfIslandButton extends AbstractMenuViewButton<MenuTopIslands.View> {\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private TopIslandsSelfIslandButton(MenuTemplateButton<MenuTopIslands.View> templateButton, MenuTopIslands.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        Island island = menuView.getInventoryViewer().getIsland();\n        return island == null ? getTemplate().noIslandItem.build() :\n                modifyViewItem(menuView, island, getTemplate().islandItem);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        onButtonClick(clickEvent, menuView, menuView.getInventoryViewer().getIsland(), getTemplate().islandSound,\n                getTemplate().islandCommands, getTemplate().noIslandSound, getTemplate().noIslandCommands);\n    }\n\n    public static void onButtonClick(InventoryClickEvent clickEvent, MenuTopIslands.View menuView,\n                                     @Nullable Island island, @Nullable GameSound islandSound,\n                                     List<String> islandCommands, @Nullable GameSound noIslandSound,\n                                     List<String> noIslandCommands) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        if (island != null) {\n            GameSoundImpl.playSound(player, islandSound);\n\n            if (islandCommands != null) {\n                islandCommands.forEach(command -> Bukkit.dispatchCommand(command.startsWith(\"PLAYER:\") ?\n                                player : Bukkit.getConsoleSender(),\n                        command.replace(\"PLAYER:\", \"\")\n                                .replace(\"%player%\", player.getName())\n                                .replace(\"%island%\", island.getName())\n                                .replace(\"%owner%\", island.getOwner().getName())\n                ));\n            }\n\n            menuView.setPreviousMove(false);\n\n            if (clickEvent.getClick().isRightClick()) {\n                if (Menus.MENU_GLOBAL_WARPS.isVisitorWarps()) {\n                    plugin.getCommands().dispatchSubCommand(player, \"visit\", island.getOwner().getName());\n                } else {\n                    plugin.getProviders().getMenusProvider().openWarpCategories(\n                            menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island);\n                }\n            } else if (plugin.getSettings().isValuesMenu()) {\n                plugin.getMenus().openValues(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island);\n            }\n\n            return;\n        }\n\n        GameSoundImpl.playSound(player, noIslandSound);\n\n        if (noIslandCommands != null)\n            noIslandCommands.forEach(command -> Bukkit.dispatchCommand(command.startsWith(\"PLAYER:\") ?\n                            player : Bukkit.getConsoleSender(),\n                    command.replace(\"PLAYER:\", \"\").replace(\"%player%\", player.getName())));\n    }\n\n    public static ItemStack modifyViewItem(MenuTopIslands.View menuView, Island island, @Nullable TemplateItem islandItem) {\n        if (islandItem == null)\n            return null;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        SuperiorPlayer islandOwner = island.getOwner();\n        int place = plugin.getGrid().getIslandPosition(island, menuView.getSortingType()) + 1;\n        ItemBuilder itemBuilder = islandItem.getBuilder().asSkullOf(islandOwner);\n\n        String islandName = !plugin.getSettings().getIslandNames().isIslandTop() ||\n                island.getName().isEmpty() ? islandOwner.getName() : island.getName();\n\n        itemBuilder.replaceName(\"{0}\", islandName)\n                .replaceName(\"{1}\", String.valueOf(place))\n                .replaceName(\"{2}\", Formatters.NUMBER_FORMATTER.format(island.getIslandLevel()))\n                .replaceName(\"{3}\", Formatters.NUMBER_FORMATTER.format(island.getWorth()))\n                .replaceName(\"{5}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), inventoryViewer.getUserLocale()))\n                .replaceName(\"{6}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), inventoryViewer.getUserLocale()))\n                .replaceName(\"{7}\", Formatters.NUMBER_FORMATTER.format(island.getTotalRating()))\n                .replaceName(\"{8}\", Formatters.RATING_FORMATTER.format(island.getTotalRating(), inventoryViewer.getUserLocale()))\n                .replaceName(\"{9}\", Formatters.NUMBER_FORMATTER.format(island.getRatingAmount()))\n                .replaceName(\"{10}\", Formatters.NUMBER_FORMATTER.format(island.getAllPlayersInside().size()));\n\n        ItemMeta itemMeta = itemBuilder.getItemMeta();\n\n        if (itemMeta != null && itemMeta.hasLore()) {\n            List<String> lore = new LinkedList<>();\n\n            for (String line : itemMeta.getLore()) {\n                if (line.contains(\"{4}\")) {\n                    List<SuperiorPlayer> members = new LinkedList<>(island.getIslandMembers(plugin.getSettings().isIslandTopIncludeLeader()));\n                    String memberFormat = line.split(\"\\\\{4}:\")[1];\n                    if (members.size() == 0) {\n                        lore.add(memberFormat.replace(\"{}\", \"None\"));\n                    } else {\n                        if (plugin.getSettings().getTopIslandMembersSorting() != TopIslandMembersSorting.NAMES)\n                            members.sort(plugin.getSettings().getTopIslandMembersSorting().getComparator());\n\n                        members.forEach(member -> {\n                            String onlineMessage = member.isOnline() ?\n                                    Message.ISLAND_TOP_STATUS_ONLINE.getMessage(inventoryViewer.getUserLocale()) :\n                                    Message.ISLAND_TOP_STATUS_OFFLINE.getMessage(inventoryViewer.getUserLocale());\n\n                            lore.add(placeholdersService.get().parsePlaceholders(member.asOfflinePlayer(), memberFormat\n                                    .replace(\"{}\", member.getName())\n                                    .replace(\"{0}\", member.getName())\n                                    .replace(\"{1}\", onlineMessage == null ? \"\" : onlineMessage)\n                                    .replace(\"{2}\", member.getPlayerRole().getDisplayName()))\n                            );\n                        });\n                    }\n                } else {\n                    lore.add(line\n                            .replace(\"{0}\", island.getOwner().getName())\n                            .replace(\"{1}\", String.valueOf(place))\n                            .replace(\"{2}\", Formatters.NUMBER_FORMATTER.format(island.getIslandLevel()))\n                            .replace(\"{3}\", Formatters.NUMBER_FORMATTER.format(island.getWorth()))\n                            .replace(\"{5}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), inventoryViewer.getUserLocale()))\n                            .replace(\"{6}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), inventoryViewer.getUserLocale()))\n                            .replace(\"{7}\", Formatters.NUMBER_FORMATTER.format(island.getTotalRating()))\n                            .replace(\"{8}\", Formatters.RATING_FORMATTER.format(island.getTotalRating(), inventoryViewer.getUserLocale()))\n                            .replace(\"{9}\", Formatters.NUMBER_FORMATTER.format(island.getRatingAmount()))\n                            .replace(\"{10}\", Formatters.NUMBER_FORMATTER.format(island.getAllPlayersInside().size())));\n                }\n            }\n\n            itemBuilder.withLore(lore);\n        }\n\n        return itemBuilder.build(islandOwner);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuTopIslands.View> {\n\n        private TemplateItem noIslandItem;\n        private GameSound noIslandSound;\n        private List<String> noIslandCommands;\n\n        public void setIslandItem(TemplateItem islandItem) {\n            this.buttonItem = islandItem;\n        }\n\n        public void setNoIslandItem(TemplateItem noIslandItem) {\n            this.noIslandItem = noIslandItem;\n        }\n\n        public void setIslandSound(GameSound islandSound) {\n            this.clickSound = islandSound;\n        }\n\n        public void setNoIslandSound(GameSound noIslandSound) {\n            this.noIslandSound = noIslandSound;\n        }\n\n        public void setIslandCommands(List<String> islandCommands) {\n            this.commands = islandCommands;\n        }\n\n        public void setNoIslandCommands(List<String> noIslandCommands) {\n            this.noIslandCommands = noIslandCommands;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuTopIslands.View> build() {\n            return new Template(requiredPermission, lackPermissionSound, buttonItem,\n                    clickSound, commands, noIslandItem, noIslandSound, noIslandCommands);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuTopIslands.View> {\n\n        private final TemplateItem islandItem;\n        private final TemplateItem noIslandItem;\n        @Nullable\n        private final GameSound islandSound;\n        @Nullable\n        private final GameSound noIslandSound;\n        private final List<String> islandCommands;\n        private final List<String> noIslandCommands;\n\n        Template(@Nullable String requiredPermission, @Nullable GameSound lackPermissionSound,\n                 @Nullable TemplateItem islandItem, @Nullable GameSound islandSound, @Nullable List<String> islandCommands,\n                 @Nullable TemplateItem noIslandItem, @Nullable GameSound noIslandSound,\n                 @Nullable List<String> noIslandCommands) {\n            super(null, null, null, requiredPermission, lackPermissionSound,\n                    TopIslandsSelfIslandButton.class, TopIslandsSelfIslandButton::new);\n            this.islandItem = islandItem == null ? TemplateItem.AIR : islandItem;\n            this.noIslandItem = noIslandItem == null ? TemplateItem.AIR : noIslandItem;\n            this.islandSound = islandSound;\n            this.islandCommands = islandCommands == null ? Collections.emptyList() : islandCommands;\n            this.noIslandSound = noIslandSound;\n            this.noIslandCommands = noIslandCommands == null ? Collections.emptyList() : noIslandCommands;\n            if (noIslandItem != null)\n                noIslandItem.getEditableBuilder().asSkullOf((SuperiorPlayer) null);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.List;\n\npublic class TransferButton extends AbstractMenuViewButton<MenuConfirmTransfer.View> {\n\n    private TransferButton(AbstractMenuTemplateButton<MenuConfirmTransfer.View> templateButton, MenuConfirmTransfer.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        if (getTemplate().newOwner)\n            IslandUtils.handleTransferIsland(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer());\n\n        BukkitExecutor.sync(menuView::closeView, 1L);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuConfirmTransfer.View> {\n\n        private boolean newOwner;\n\n        public Builder setNewOwner(boolean newOwner) {\n            this.newOwner = newOwner;\n            return this;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuConfirmTransfer.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newOwner);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuConfirmTransfer.View> {\n\n        private final boolean newOwner;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean newOwner) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    TransferButton.class, TransferButton::new);\n            this.newOwner = newOwner;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUniqueVisitors;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Date;\nimport java.util.Locale;\n\npublic class UniqueVisitorPagedObjectButton extends AbstractPagedMenuButton<MenuIslandUniqueVisitors.View, MenuIslandUniqueVisitors.UniqueVisitorInfo> {\n\n    private UniqueVisitorPagedObjectButton(MenuTemplateButton<MenuIslandUniqueVisitors.View> templateButton, MenuIslandUniqueVisitors.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        String subCommandToExecute;\n\n        if (clickEvent.getClick().isRightClick())\n            subCommandToExecute = \"invite\";\n        else if (clickEvent.getClick().isLeftClick())\n            subCommandToExecute = \"expel\";\n        else return;\n\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(),\n                subCommandToExecute, pagedObject.getVisitor().getName());\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        SuperiorPlayer visitor = pagedObject.getVisitor();\n        Island island = visitor.getIsland();\n        Locale locale = menuView.getInventoryViewer().getUserLocale();\n\n        String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale);\n        String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale);\n\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", visitor.getName())\n                .replaceAll(\"{1}\", islandOwner)\n                .replaceAll(\"{2}\", islandName)\n                .replaceAll(\"{3}\", Formatters.DATE_FORMATTER.format(new Date(pagedObject.getVisitTime())))\n                .asSkullOf(visitor)\n                .build(visitor);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandUniqueVisitors.View, MenuIslandUniqueVisitors.UniqueVisitorInfo> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandUniqueVisitors.View, MenuIslandUniqueVisitors.UniqueVisitorInfo> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), UniqueVisitorPagedObjectButton.class,\n                    UniqueVisitorPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel;\nimport org.bukkit.Material;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic class UpgradeButton extends AbstractMenuViewButton<IslandMenuView> {\n\n    private static final TemplateItem INVALID_ITEM = new TemplateItem(new ItemBuilder(Material.BEDROCK).withName(\"&c&lInvalid Item\"));\n\n    private UpgradeButton(AbstractMenuTemplateButton<IslandMenuView> templateButton, IslandMenuView menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        Upgrade upgrade = getTemplate().upgrade;\n\n        UpgradeLevel upgradeLevel = menuView.getIsland().getUpgradeLevel(upgrade);\n\n        SUpgradeLevel.ItemData itemData = ((SUpgradeLevel) upgradeLevel).getItemData();\n\n        if (itemData == null)\n            return null;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        UpgradeLevel nextUpgradeLevel = upgrade.getUpgradeLevel(upgradeLevel.getLevel() + 1);\n\n        UpgradeCost levelCost = upgradeLevel.getCost();\n        String permission = nextUpgradeLevel == null ? \"\" : nextUpgradeLevel.getPermission();\n        String requirements = nextUpgradeLevel == null ? \"\" : nextUpgradeLevel.checkRequirements(inventoryViewer);\n\n        boolean nextLevel = levelCost.hasEnoughBalance(inventoryViewer) &&\n                (permission.isEmpty() || inventoryViewer.hasPermission(permission)) && requirements.isEmpty();\n\n        TemplateItem buttonItem = nextLevel ? itemData.hasNextLevel : itemData.noNextLevel;\n\n        return (buttonItem == null ? INVALID_ITEM : buttonItem).getBuilder()\n                .replaceAll(\"{0}\", levelCost.getCost() + \"\")\n                .replaceAll(\"{1}\", Formatters.NUMBER_FORMATTER.format(levelCost.getCost()))\n                .replaceAll(\"{2}\", Formatters.FANCY_NUMBER_FORMATTER.format(levelCost.getCost(), inventoryViewer.getUserLocale()))\n                .build(inventoryViewer);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Upgrade upgrade = plugin.getUpgrades().getUpgrade(clickEvent.getRawSlot());\n\n        if (upgrade == null)\n            return;\n\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), \"rankup\", upgrade.getName());\n        menuView.refreshView();\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<IslandMenuView> {\n\n        private final Upgrade upgrade;\n\n        public Builder(Upgrade upgrade) {\n            this.upgrade = upgrade;\n        }\n\n        @Override\n        public MenuTemplateButton<IslandMenuView> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, upgrade);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<IslandMenuView> {\n\n        private final Upgrade upgrade;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Upgrade upgrade) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    UpgradeButton.class, UpgradeButton::new);\n            this.upgrade = Objects.requireNonNull(upgrade, \"upgrade cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ValuesButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandValues;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class ValuesButton extends AbstractMenuViewButton<MenuIslandValues.View> {\n\n    private static final BigInteger MAX_STACK = BigInteger.valueOf(64);\n\n    private ValuesButton(AbstractMenuTemplateButton<MenuIslandValues.View> templateButton, MenuIslandValues.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public Template getTemplate() {\n        return (Template) super.getTemplate();\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        // Dummy Button\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        TemplateItem buttonItem = getTemplate().getButtonTemplateItem();\n\n        if (buttonItem == null)\n            return null;\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island island = menuView.getIsland();\n\n        Key block = getTemplate().block;\n\n        BigDecimal amount = new BigDecimal(block.getGlobalKey().contains(\"SPAWNER\") ?\n                island.getExactBlockCountAsBigInteger(block) : island.getBlockCountAsBigInteger(block));\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(block);\n        BigDecimal blockWorth = blockValue.getWorth();\n        BigDecimal blockLevel = blockValue.getLevel();\n\n        ItemStack itemStack = buttonItem.getBuilder()\n                .replaceAll(\"{0}\", amount + \"\")\n                .replaceAll(\"{1}\", Formatters.NUMBER_FORMATTER.format(blockWorth.multiply(amount)))\n                .replaceAll(\"{2}\", Formatters.NUMBER_FORMATTER.format(blockLevel.multiply(amount)))\n                .replaceAll(\"{3}\", Formatters.FANCY_NUMBER_FORMATTER.format(blockWorth.multiply(amount), inventoryViewer.getUserLocale()))\n                .replaceAll(\"{4}\", Formatters.FANCY_NUMBER_FORMATTER.format(blockLevel.multiply(amount), inventoryViewer.getUserLocale()))\n                .build(inventoryViewer);\n\n        itemStack.setAmount(BigInteger.ONE.max(MAX_STACK.min(amount.toBigInteger())).intValue());\n\n        return itemStack;\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuIslandValues.View> {\n\n        private final Key block;\n\n        public Builder(Key block) {\n            this.block = block;\n        }\n\n        @Override\n        public MenuTemplateButton<MenuIslandValues.View> build() {\n            return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, block);\n        }\n\n    }\n\n    public static class Template extends MenuTemplateButtonImpl<MenuIslandValues.View> {\n\n        private final Key block;\n\n        Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List<String> commands,\n                 @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Key block) {\n            super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound,\n                    ValuesButton.class, ValuesButton::new);\n            this.block = Objects.requireNonNull(block, \"block cannot be null\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Locale;\n\npublic class VisitorPagedObjectButton extends AbstractPagedMenuButton<MenuIslandVisitors.View, SuperiorPlayer> {\n\n    private VisitorPagedObjectButton(MenuTemplateButton<MenuIslandVisitors.View> templateButton, MenuIslandVisitors.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        String subCommandToExecute;\n\n        if (clickEvent.getClick().isRightClick())\n            subCommandToExecute = \"invite\";\n        else if (clickEvent.getClick().isLeftClick())\n            subCommandToExecute = \"expel\";\n        else return;\n\n        plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), subCommandToExecute, pagedObject.getName());\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        Island island = pagedObject.getIsland();\n        Locale locale = menuView.getInventoryViewer().getUserLocale();\n\n        String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale);\n        String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale);\n\n        return new ItemBuilder(buttonItem)\n                .replaceAll(\"{0}\", pagedObject.getName())\n                .replaceAll(\"{1}\", islandOwner)\n                .replaceAll(\"{2}\", islandName)\n                .asSkullOf(pagedObject)\n                .build(pagedObject);\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuIslandVisitors.View, SuperiorPlayer> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuIslandVisitors.View, SuperiorPlayer> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), VisitorPagedObjectButton.class,\n                    VisitorPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpCategoryIconEditConfirmButton extends AbstractMenuViewButton<AbstractIconProviderMenu.View<WarpCategory>> {\n\n    private WarpCategoryIconEditConfirmButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<WarpCategory>> templateButton,\n                                              AbstractIconProviderMenu.View<WarpCategory> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        WarpCategory warpCategory = menuView.getIconProvider();\n\n        PluginEvent<PluginEventArgs.IslandChangeWarpCategoryIcon> event = PluginEventsFactory.callIslandChangeWarpCategoryIconEvent(\n                warpCategory.getIsland(), superiorPlayer, warpCategory, menuView.getIconTemplate().build());\n\n        if (event.isCancelled())\n            return;\n\n        clickEvent.getWhoClicked().closeInventory();\n\n        Message.WARP_CATEGORY_ICON_UPDATED.send(superiorPlayer);\n\n        warpCategory.setIcon(event.getArgs().icon);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<WarpCategory>> {\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<WarpCategory>> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpCategoryIconEditConfirmButton.class,\n                    WarpCategoryIconEditConfirmButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\npublic class WarpCategoryManageIconButton extends AbstractMenuViewButton<MenuWarpCategoryManage.View> {\n\n    private WarpCategoryManageIconButton(AbstractMenuTemplateButton<MenuWarpCategoryManage.View> templateButton, MenuWarpCategoryManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        WarpCategory warpCategory = menuView.getWarpCategory();\n\n        ItemBuilder itemBuilder = new ItemBuilder(warpCategory.getRawIcon());\n        ItemStack buttonItem = super.createViewItem();\n\n        if (buttonItem != null && buttonItem.hasItemMeta()) {\n            ItemMeta itemMeta = buttonItem.getItemMeta();\n            if (itemMeta.hasDisplayName())\n                itemBuilder.withName(itemMeta.getDisplayName());\n\n            if (itemMeta.hasLore())\n                itemBuilder.appendLore(itemMeta.getLore());\n        }\n\n        return itemBuilder.build(warpCategory.getIsland().getOwner());\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        WarpCategory warpCategory = menuView.getWarpCategory();\n\n        if (clickEvent.getClick().isRightClick()) {\n            menuView.setPreviousMove(false);\n            plugin.getMenus().openWarpCategoryIconEdit(inventoryViewer, MenuViewWrapper.fromView(menuView), warpCategory);\n            return;\n        }\n\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        Message.WARP_CATEGORY_SLOT.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, message -> {\n            if (!message.equalsIgnoreCase(\"-cancel\")) {\n                int rowsSize = Menus.MENU_WARP_CATEGORIES.getRowsSize();\n\n                int slot;\n\n                try {\n                    slot = Integer.parseInt(message);\n                    if (slot < 0 || slot >= rowsSize * 9)\n                        throw new IllegalArgumentException();\n                } catch (IllegalArgumentException ex) {\n                    Message.INVALID_SLOT.send(player, message);\n                    return true;\n                }\n\n                if (warpCategory.getIsland().getWarpCategory(slot) != null) {\n                    Message.WARP_CATEGORY_SLOT_ALREADY_TAKEN.send(player);\n                    return true;\n                }\n\n                PluginEvent<PluginEventArgs.IslandChangeWarpCategorySlot> event = PluginEventsFactory.callIslandChangeWarpCategorySlotEvent(\n                        warpCategory.getIsland(), inventoryViewer, warpCategory, slot, rowsSize * 9);\n\n                if (!event.isCancelled()) {\n                    warpCategory.setSlot(event.getArgs().slot);\n\n                    Message.WARP_CATEGORY_SLOT_SUCCESS.send(player, event.getArgs().slot);\n\n                    GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound());\n                }\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpCategoryManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpCategoryManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpCategoryManageIconButton.class, WarpCategoryManageIconButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpCategoryManageRenameButton extends AbstractMenuViewButton<MenuWarpCategoryManage.View> {\n\n    private WarpCategoryManageRenameButton(AbstractMenuTemplateButton<MenuWarpCategoryManage.View> templateButton, MenuWarpCategoryManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        Message.WARP_CATEGORY_RENAME.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, newName -> {\n            WarpCategory warpCategory = menuView.getWarpCategory();\n\n            if (warpCategory.getIsland().getWarpCategory(warpCategory.getName()) != null &&\n                    !newName.equalsIgnoreCase(\"-cancel\")) {\n                if (warpCategory.getIsland().getWarpCategory(newName) != null) {\n                    Message.WARP_CATEGORY_RENAME_ALREADY_EXIST.send(player);\n                    return true;\n                }\n\n                if (!IslandUtils.isWarpNameLengthValid(newName)) {\n                    Message.WARP_CATEGORY_NAME_TOO_LONG.send(player);\n                    return true;\n                }\n\n                PluginEvent<PluginEventArgs.IslandRenameWarpCategory> event = PluginEventsFactory.callIslandRenameWarpCategoryEvent(\n                        warpCategory.getIsland(), plugin.getPlayers().getSuperiorPlayer(player), warpCategory, newName);\n\n                if (!event.isCancelled()) {\n                    warpCategory.getIsland().renameCategory(warpCategory, event.getArgs().categoryName);\n\n                    Message.WARP_CATEGORY_RENAME_SUCCESS.send(player, event.getArgs().categoryName);\n\n                    GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound());\n                }\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpCategoryManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpCategoryManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpCategoryManageRenameButton.class, WarpCategoryManageRenameButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpCategoryManageWarpsButton extends AbstractMenuViewButton<MenuWarpCategoryManage.View> {\n\n    private WarpCategoryManageWarpsButton(AbstractMenuTemplateButton<MenuWarpCategoryManage.View> templateButton, MenuWarpCategoryManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openWarps(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getWarpCategory());\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpCategoryManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpCategoryManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpCategoryManageWarpsButton.class, WarpCategoryManageWarpsButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategories;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class WarpCategoryPagedObjectButton extends AbstractPagedMenuButton<MenuWarpCategories.View, WarpCategory> {\n\n    private WarpCategoryPagedObjectButton(MenuTemplateButton<MenuWarpCategories.View> templateButton, MenuWarpCategories.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        if (pagedObject == null) {\n            return TemplateItem.AIR.build();\n        }\n\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n        Island island = menuView.getIsland();\n\n        boolean isMember = island.isMember(inventoryViewer);\n        long accessAmount = pagedObject.getWarps().stream().filter(\n                islandWarp -> isMember || !islandWarp.hasPrivateFlag()\n        ).count();\n\n        if (accessAmount == 0)\n            return null;\n\n        if (!menuView.hasManagePerms() || Menus.MENU_WARP_CATEGORIES.getEditLore().isEmpty()) {\n            return pagedObject.getIcon(island.getOwner());\n        } else {\n            return new ItemBuilder(pagedObject.getIcon(null))\n                    .appendLore(Menus.MENU_WARP_CATEGORIES.getEditLore())\n                    .build(island.getOwner());\n        }\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        menuView.setPreviousMove(false);\n\n        if (menuView.hasManagePerms() && clickEvent.getClick().isRightClick()) {\n            plugin.getMenus().openWarpCategoryManage(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject);\n        } else {\n            plugin.getMenus().openWarps(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject);\n        }\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuWarpCategories.View, WarpCategory> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuWarpCategories.View, WarpCategory> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), WarpCategoryPagedObjectButton.class,\n                    WarpCategoryPagedObjectButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpIconEditConfirmButton extends AbstractMenuViewButton<AbstractIconProviderMenu.View<IslandWarp>> {\n\n    private WarpIconEditConfirmButton(AbstractMenuTemplateButton<AbstractIconProviderMenu.View<IslandWarp>> templateButton,\n                                      AbstractIconProviderMenu.View<IslandWarp> menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer inventoryViewer = menuView.getInventoryViewer();\n\n        IslandWarp islandWarp = menuView.getIconProvider();\n\n        PluginEvent<PluginEventArgs.IslandChangeWarpIcon> event = PluginEventsFactory.callIslandChangeWarpIconEvent(\n                islandWarp.getIsland(), inventoryViewer, islandWarp, menuView.getIconTemplate().build());\n\n        if (event.isCancelled())\n            return;\n\n        clickEvent.getWhoClicked().closeInventory();\n\n        Message.WARP_ICON_UPDATED.send(inventoryViewer);\n\n        islandWarp.setIcon(event.getArgs().icon);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<AbstractIconProviderMenu.View<IslandWarp>> {\n\n        @Override\n        public MenuTemplateButton<AbstractIconProviderMenu.View<IslandWarp>> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpIconEditConfirmButton.class, WarpIconEditConfirmButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageIconButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.island.warp.WarpIcons;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\n\npublic class WarpManageIconButton extends AbstractMenuViewButton<MenuWarpManage.View> {\n\n    private WarpManageIconButton(AbstractMenuTemplateButton<MenuWarpManage.View> templateButton, MenuWarpManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public ItemStack createViewItem() {\n        IslandWarp islandWarp = menuView.getIslandWarp();\n\n        ItemBuilder itemBuilder = islandWarp.getRawIcon() == null ?\n                WarpIcons.DEFAULT_WARP_ICON.getBuilder() : new ItemBuilder(islandWarp.getRawIcon());\n\n        ItemStack buttonItem = super.createViewItem();\n\n        if (buttonItem != null && buttonItem.hasItemMeta()) {\n            ItemMeta itemMeta = buttonItem.getItemMeta();\n            if (itemMeta.hasDisplayName())\n                itemBuilder.withName(itemMeta.getDisplayName());\n\n            if (itemMeta.hasLore())\n                itemBuilder.appendLore(itemMeta.getLore());\n        }\n\n        return itemBuilder.build(menuView.getInventoryViewer());\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        IslandWarp islandWarp = menuView.getIslandWarp();\n        menuView.setPreviousMove(false);\n        plugin.getMenus().openWarpIconEdit(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), islandWarp);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpManageIconButton.class, WarpManageIconButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.warp.SignWarp;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\nimport java.util.Objects;\n\npublic class WarpManageLocationButton extends AbstractMenuViewButton<MenuWarpManage.View> {\n\n    private WarpManageLocationButton(AbstractMenuTemplateButton<MenuWarpManage.View> templateButton, MenuWarpManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n        IslandWarp islandWarp = menuView.getIslandWarp();\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location playerLocation = player.getLocation(wrapper.getHandle());\n\n            if (!islandWarp.getIsland().isInsideRange(playerLocation)) {\n                Message.SET_WARP_OUTSIDE.send(player);\n                return;\n            }\n\n            PluginEvent<PluginEventArgs.IslandChangeWarpLocation> event = PluginEventsFactory.callIslandChangeWarpLocationEvent(\n                    islandWarp.getIsland(), player, islandWarp, playerLocation);\n\n            if (event.isCancelled())\n                return;\n\n            Message.WARP_LOCATION_UPDATE.send(player);\n\n            WorldPosition warpPosition = islandWarp.getPosition();\n            WorldInfo warpWorld = plugin.getGrid().getIslandsWorldInfo(islandWarp.getIsland(), islandWarp.getPositionDimension());\n\n            if (!isSameLocation(event.getArgs().location, warpWorld, warpPosition)) {\n                ChunksProvider.loadChunk(ChunkPosition.of(warpWorld, warpPosition), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> {\n                    SignWarp.trySignWarpBreak(islandWarp, player);\n                });\n            }\n\n            islandWarp.setLocation(event.getArgs().location);\n\n            GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound());\n        }\n    }\n\n    private static boolean isSameLocation(Location location, WorldInfo worldInfo, WorldPosition worldPosition) {\n        if (location.getX() != worldPosition.getX() || location.getY() != worldPosition.getY() ||\n                location.getZ() != worldPosition.getZ() || location.getYaw() != worldPosition.getYaw() ||\n                location.getPitch() != worldPosition.getPitch())\n            return false;\n        String worldName = LazyWorldLocation.getWorldName(location);\n        return Objects.equals(worldName, worldInfo.getName());\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpManageLocationButton.class, WarpManageLocationButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpManagePrivateButton extends AbstractMenuViewButton<MenuWarpManage.View> {\n\n    private WarpManagePrivateButton(AbstractMenuTemplateButton<MenuWarpManage.View> templateButton, MenuWarpManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        IslandWarp islandWarp = menuView.getIslandWarp();\n\n        boolean openToPublic = islandWarp.hasPrivateFlag();\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        if (openToPublic ? !PluginEventsFactory.callIslandOpenWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp) :\n                !PluginEventsFactory.callIslandCloseWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp))\n            return;\n\n        islandWarp.setPrivateFlag(!openToPublic);\n\n        if (openToPublic)\n            Message.WARP_PUBLIC_UPDATE.send(superiorPlayer);\n        else\n            Message.WARP_PRIVATE_UPDATE.send(superiorPlayer);\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpManagePrivateButton.class, WarpManagePrivateButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryClickEvent;\n\npublic class WarpManageRenameButton extends AbstractMenuViewButton<MenuWarpManage.View> {\n\n    private WarpManageRenameButton(AbstractMenuTemplateButton<MenuWarpManage.View> templateButton, MenuWarpManage.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        Player player = (Player) clickEvent.getWhoClicked();\n\n        Message.WARP_RENAME.send(player);\n\n        menuView.closeView();\n\n        PlayerChat.listen(player, newName -> {\n            IslandWarp islandWarp = menuView.getIslandWarp();\n\n            if (!newName.equalsIgnoreCase(\"-cancel\")) {\n                if (islandWarp.getIsland().getWarp(newName) != null) {\n                    Message.WARP_RENAME_ALREADY_EXIST.send(player);\n                    return true;\n                }\n\n                if (!IslandUtils.isWarpNameLengthValid(newName)) {\n                    Message.WARP_NAME_TOO_LONG.send(player);\n                    return true;\n                }\n\n                PluginEvent<PluginEventArgs.IslandRenameWarp> event = PluginEventsFactory.callIslandRenameWarpEvent(\n                        islandWarp.getIsland(), player, islandWarp, newName);\n\n                if (!event.isCancelled()) {\n                    islandWarp.getIsland().renameWarp(islandWarp, event.getArgs().warpName);\n\n                    Message.WARP_RENAME_SUCCESS.send(player, event.getArgs().warpName);\n\n                    GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound());\n                }\n            }\n\n            PlayerChat.remove(player);\n\n            menuView.refreshView();\n\n            return true;\n        });\n    }\n\n    public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder<MenuWarpManage.View> {\n\n        @Override\n        public MenuTemplateButton<MenuWarpManage.View> build() {\n            return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, WarpManageRenameButton.class, WarpManageRenameButton::new);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.button.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.Location;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.inventory.ItemStack;\n\npublic class WarpPagedObjectButton extends AbstractPagedMenuButton<MenuWarps.View, IslandWarp> {\n\n    private WarpPagedObjectButton(MenuTemplateButton<MenuWarps.View> templateButton, MenuWarps.View menuView) {\n        super(templateButton, menuView);\n    }\n\n    @Override\n    public void onButtonClick(InventoryClickEvent clickEvent) {\n        SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked());\n\n        if (menuView.hasManagePerms() && clickEvent.getClick().isRightClick()) {\n            menuView.setPreviousMove(false);\n            plugin.getMenus().openWarpManage(clickedPlayer, MenuViewWrapper.fromView(menuView), pagedObject);\n        } else {\n            MenuActions.simulateWarpsClick(clickedPlayer, menuView.getWarpCategory().getIsland(), pagedObject);\n            BukkitExecutor.sync(() -> menuView.setPreviousMove(false), 1L);\n        }\n    }\n\n    @Override\n    public ItemStack modifyViewItem(ItemStack buttonItem) {\n        SuperiorPlayer superiorPlayer = menuView.getInventoryViewer();\n\n        ItemStack icon = pagedObject.getIcon(superiorPlayer);\n        ItemBuilder itemBuilder = new ItemBuilder(icon == null ? buttonItem : icon);\n\n        if (menuView.hasManagePerms() && !Menus.MENU_WARPS.getEditLore().isEmpty())\n            itemBuilder.appendLore(Menus.MENU_WARPS.getEditLore());\n\n        try (ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n            return itemBuilder.replaceAll(\"{0}\", pagedObject.getName())\n                    .replaceAll(\"{1}\", Formatters.LOCATION_FORMATTER.format(pagedObject.getLocation(wrapper.getHandle())))\n                    .replaceAll(\"{2}\", pagedObject.hasPrivateFlag() ?\n                            ensureNotNull(Message.ISLAND_WARP_PRIVATE.getMessage(superiorPlayer.getUserLocale())) :\n                            ensureNotNull(Message.ISLAND_WARP_PUBLIC.getMessage(superiorPlayer.getUserLocale())))\n                    .build(superiorPlayer);\n        }\n    }\n\n    public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder<MenuWarps.View, IslandWarp> {\n\n        @Override\n        public PagedMenuTemplateButton<MenuWarps.View, IslandWarp> build() {\n            return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission,\n                    lackPermissionSound, nullItem, getButtonIndex(), WarpPagedObjectButton.class,\n                    WarpPagedObjectButton::new);\n        }\n\n    }\n\n    private static String ensureNotNull(String check) {\n        return check == null ? \"\" : check;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/converter/MenuConverter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.converter;\n\nimport com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class MenuConverter {\n\n    private MenuConverter() {\n\n    }\n\n    public static int convertFillItems(ConfigurationSection fillItemsSection, int charCounter, char[] patternChars, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) {\n        for (String itemFill : fillItemsSection.getKeys(false)) {\n            ConfigurationSection section = fillItemsSection.getConfigurationSection(itemFill);\n            String[] slots = section.getString(\"slots\").split(\",\");\n            section.set(\"slots\", null);\n\n            char itemChar = RegularMenuLayoutImpl.BUTTON_SYMBOLS[charCounter++];\n            for (String slot : slots) {\n                patternChars[Integer.parseInt(slot)] = itemChar;\n            }\n\n            convertItem(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection);\n        }\n\n        return charCounter;\n    }\n\n    public static void convertItem(ConfigurationSection section, char[] patternChars, char itemChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) {\n        if (section.contains(\"slot\")) {\n            patternChars[section.getInt(\"slot\")] = itemChar;\n            section.set(\"slot\", null);\n        }\n\n        soundsSection.set(itemChar + \"\", section.get(\"sound\"));\n        section.set(\"sound\", null);\n\n        commandsSection.set(itemChar + \"\", section.get(\"commands\"));\n        section.set(\"commands\", null);\n\n        itemsSection.set(itemChar + \"\", section);\n    }\n\n    public static void convertItemAccess(ConfigurationSection section, char[] patternChars, char itemChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) {\n        patternChars[section.getInt(\"slot\")] = itemChar;\n        section.set(\"slot\", null);\n\n        section.set(\"access\", section.getConfigurationSection(\"has-access-item\"));\n        soundsSection.set(itemChar + \".access\", section.get(\"has-access-item.sound\"));\n        commandsSection.set(itemChar + \".access\", section.get(\"has-access-item.commands\"));\n        section.set(\"has-access-item.sound\", null);\n        section.set(\"has-access-item.commands\", null);\n        section.set(\"has-access-item\", null);\n\n        section.set(\"no-access\", section.getConfigurationSection(\"no-access-item\"));\n        soundsSection.set(itemChar + \".no-access\", section.get(\"no-access-item.sound\"));\n        commandsSection.set(itemChar + \".no-access\", section.get(\"no-access-item.commands\"));\n        section.set(\"no-access-item.sound\", null);\n        section.set(\"no-access-item.commands\", null);\n        section.set(\"no-access-item\", null);\n\n        itemsSection.set(itemChar + \"\", section);\n    }\n\n    public static void convertPagedButtons(ConfigurationSection section, ConfigurationSection newMenu, char[] patternChars, char slotsChar, char previousChar, char currentChar, char nextChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) {\n        convertPagedButtons(section, null, newMenu, patternChars, slotsChar, previousChar, currentChar, nextChar, itemsSection, commandsSection, soundsSection);\n    }\n\n    public static void convertPagedButtons(ConfigurationSection section, ConfigurationSection itemSection, ConfigurationSection newMenu, char[] patternChars, char slotsChar, char previousChar, char currentChar, char nextChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) {\n        String slots = itemSection != null ? itemSection.getString(\"slots\") : section.getString(\"slots\");\n\n        if (slots != null) {\n            for (String slot : slots.split(\",\"))\n                patternChars[Integer.parseInt(slot)] = slotsChar;\n            if (itemSection != null)\n                itemSection.set(\"slots\", null);\n            else\n                section.set(\"slots\", null);\n        }\n\n        if (itemSection != null) {\n            MenuConverter.convertItem(itemSection, patternChars, slotsChar, itemsSection, commandsSection, soundsSection);\n        }\n\n        MenuConverter.convertItem(section.getConfigurationSection(\"previous-page\"), patternChars, previousChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(section.getConfigurationSection(\"current-page\"), patternChars, currentChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(section.getConfigurationSection(\"next-page\"), patternChars, nextChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"slots\", slotsChar + \"\");\n        newMenu.set(\"previous-page\", previousChar + \"\");\n        newMenu.set(\"current-page\", currentChar + \"\");\n        newMenu.set(\"next-page\", nextChar + \"\");\n    }\n\n    public static List<String> buildPattern(int size, char[] patternChars, char replaceChar) {\n        int lineLength = patternChars.length == 5 ? 5 : 9;\n        int charCount = 0;\n\n        List<String> pattern = new ArrayList<>(size);\n        StringBuilder line = new StringBuilder();\n\n        for (char ch : patternChars) {\n            charCount++;\n            line.append(\" \").append(ch);\n            if (charCount == lineLength) {\n                charCount = 0;\n                pattern.add(line.substring(1).replace('\\n', replaceChar));\n                line = new StringBuilder();\n            }\n        }\n\n        return pattern;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankLogsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankLogsSortButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.UUID;\n\npublic class MenuBankLogs extends AbstractPagedMenu<MenuBankLogs.View, IslandViewArgs, BankTransaction> {\n\n    private static final UUID CONSOLE_UUID = new UUID(0, 0);\n\n    private MenuBankLogs(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_BANK_LOGS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        this.refreshViews(view -> Objects.equals(view.island, island));\n    }\n\n    @Nullable\n    public static MenuBankLogs createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"bank-logs.yml\",\n                MenuBankLogs::convertOldGUI, new BankLogsPagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"time-sort\", menuPatternSlots),\n                new BankLogsSortButton.Builder().setSortType(BankLogsSortButton.SortType.TIME));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"money-sort\", menuPatternSlots),\n                new BankLogsSortButton.Builder().setSortType(BankLogsSortButton.SortType.MONEY));\n\n        return new MenuBankLogs(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<View, IslandViewArgs, BankTransaction> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n\n        private Comparator<BankTransaction> sorting;\n        private UUID filteredPlayer;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public SuperiorPlayer getSuperiorPlayer() {\n            return this.filteredPlayer == null || this.filteredPlayer.equals(CONSOLE_UUID) ? null :\n                    plugin.getPlayers().getSuperiorPlayer(filteredPlayer);\n        }\n\n        public void setSorting(Comparator<BankTransaction> sorting) {\n            this.sorting = sorting;\n        }\n\n        public void setFilteredPlayer(UUID filteredPlayer) {\n            this.filteredPlayer = filteredPlayer == null ? CONSOLE_UUID : filteredPlayer;\n            this.setCurrentPage(1);\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", getFilteredPlayerName(filteredPlayer));\n        }\n\n        @Override\n        protected List<BankTransaction> requestObjects() {\n            List<BankTransaction> transactions = getTransactions();\n\n            if (sorting == null) {\n                return transactions;\n            }\n\n            transactions = new LinkedList<>(transactions);\n\n            transactions.sort(sorting);\n\n            return Collections.unmodifiableList(transactions);\n        }\n\n        private List<BankTransaction> getTransactions() {\n            if (filteredPlayer == null) {\n                return island.getIslandBank().getAllTransactions();\n            } else if (filteredPlayer.equals(CONSOLE_UUID)) {\n                return island.getIslandBank().getConsoleTransactions();\n            } else {\n                return island.getIslandBank().getTransactions(plugin.getPlayers().getSuperiorPlayer(filteredPlayer));\n            }\n        }\n\n        private static String getFilteredPlayerName(UUID filteredPlayer) {\n            if (filteredPlayer == null) {\n                return \"\";\n            } else if (filteredPlayer.equals(CONSOLE_UUID)) {\n                return \"Console\";\n            } else {\n                return plugin.getPlayers().getSuperiorPlayer(filteredPlayer).getName();\n            }\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"members-panel.title\"));\n\n        int size = cfg.getInt(\"members-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"members-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"members-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"members-panel\"),\n                cfg.getConfigurationSection(\"members-panel.member-item\"), newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BiomeButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.block.Biome;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Locale;\n\npublic class MenuBiomes extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private final boolean currentBiomeGlow;\n\n    private MenuBiomes(MenuParseResult<IslandMenuView> parseResult, boolean currentBiomeGlow) {\n        super(MenuIdentifiers.MENU_BIOMES, parseResult);\n        this.currentBiomeGlow = currentBiomeGlow;\n    }\n\n    public boolean isCurrentBiomeGlow() {\n        return currentBiomeGlow;\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuBiomes createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"biomes.yml\",\n                MenuBiomes::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        boolean shouldCurrentBiomeGlow = cfg.getBoolean(\"current-biome-glow\", false);\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemSection = cfg.getConfigurationSection(\"items.\" + itemSectionName);\n\n                if (!itemSection.isString(\"biome\"))\n                    continue;\n\n                String biomeName = itemSection.getString(\"biome\");\n                Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName);;\n\n                if (biome == null) {\n                    Log.warnFromFile(\"biomes.yml\", \"Biome '\", biomeName, \"' is not valid, skipping...\");\n                    continue;\n                }\n\n                ConfigurationSection soundSection = cfg.getConfigurationSection(\"sounds.\" + itemSectionName);\n                ConfigurationSection commandSection = cfg.getConfigurationSection(\"commands.\" + itemSectionName);\n\n                BiomeButton.Builder buttonBuilder = new BiomeButton.Builder(biome);\n\n                if (itemSection.isConfigurationSection(\"access\")) {\n                    buttonBuilder.setAccessItem(MenuParserImpl.getInstance().getItemStack(\"menus/biomes.yml\",\n                            itemSection.getConfigurationSection(\"access\")));\n                }\n                if (itemSection.isConfigurationSection(\"no-access\")) {\n                    buttonBuilder.setNoAccessItem(MenuParserImpl.getInstance().getItemStack(\"menus/biomes.yml\",\n                            itemSection.getConfigurationSection(\"no-access\")));\n                }\n                if (soundSection != null) {\n                    if (soundSection.isConfigurationSection(\"access\")) {\n                        buttonBuilder.setAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"access\")));\n                    }\n                    if (soundSection.isConfigurationSection(\"no-access\")) {\n                        buttonBuilder.setNoAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"no-access\")));\n                    }\n                }\n                if (commandSection != null) {\n                    if (commandSection.isList(\"access\")) {\n                        buttonBuilder.setAccessCommands(commandSection.getStringList(\"access\"));\n                    }\n                    if (commandSection.isList(\"no-access\")) {\n                        buttonBuilder.setNoAccessCommands(commandSection.getStringList(\"no-access\"));\n                    }\n                }\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName), buttonBuilder);\n            }\n        }\n\n        return new MenuBiomes(menuParseResult, shouldCurrentBiomeGlow);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/biomes-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"biomes-gui.title\"));\n\n        int size = cfg.getInt(\"biomes-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"biomes-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"biomes-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        if (cfg.isConfigurationSection(\"biomes-gui.biomes\")) {\n            for (String biomeName : cfg.getConfigurationSection(\"biomes-gui.biomes\").getKeys(false)) {\n                ConfigurationSection section = cfg.getConfigurationSection(\"biomes-gui.biomes.\" + biomeName);\n                char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n                section.set(\"biome\", biomeName.toUpperCase(Locale.ENGLISH));\n                MenuConverter.convertItemAccess(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection);\n            }\n        }\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BorderColorButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BorderColorToggleButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuBorderColor extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private MenuBorderColor(MenuParseResult<BaseMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_BORDER_COLOR, parseResult);\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    @Nullable\n    public static MenuBorderColor createInstance() {\n        MenuParseResult<BaseMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"border-color.yml\",\n                MenuBorderColor::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<BaseMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemsSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemsSection = cfg.getConfigurationSection(\"items.\" + itemsSectionName);\n\n                if (!itemsSection.isConfigurationSection(\"enable-border\") || !itemsSection.isConfigurationSection(\"disable-border\"))\n                    continue;\n\n                patternBuilder.setButtons(menuPatternSlots.getSlots(itemsSectionName),\n                        new BorderColorToggleButton.Builder()\n                                .setEnabledItem(MenuParserImpl.getInstance().getItemStack(\"menus/border-color.yml\",\n                                        itemsSection.getConfigurationSection(\"disable-border\")))\n                                .setDisabledItem(MenuParserImpl.getInstance().getItemStack(\"menus/border-color.yml\",\n                                        itemsSection.getConfigurationSection(\"enable-border\")))\n                                .build());\n            }\n        }\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"green-color\", menuPatternSlots),\n                new BorderColorButton.Builder().setBorderColor(BorderColor.GREEN));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"red-color\", menuPatternSlots),\n                new BorderColorButton.Builder().setBorderColor(BorderColor.RED));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"blue-color\", menuPatternSlots),\n                new BorderColorButton.Builder().setBorderColor(BorderColor.BLUE));\n\n        return new MenuBorderColor(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/border-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"border-gui.title\"));\n        newMenu.set(\"type\", \"HOPPER\");\n\n        char[] patternChars = new char[5];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"border-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"border-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char greenChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char blueChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char redChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"border-gui.green_color\"), patternChars, greenChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"border-gui.blue_color\"), patternChars, blueChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"border-gui.red_color\"), patternChars, redChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"green-color\", greenChar + \"\");\n        newMenu.set(\"red-color\", redChar + \"\");\n        newMenu.set(\"blue-color\", blueChar + \"\");\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(1, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BanButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuConfirmBan extends AbstractMenu<MenuConfirmBan.View, MenuConfirmBan.Args> {\n\n    private MenuConfirmBan(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_CONFIRM_BAN, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuConfirmBan createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"confirm-ban.yml\", null);\n\n        if (menuParseResult == null)\n            return null;\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"confirm\", menuPatternSlots),\n                new BanButton.Builder().setBanPlayer(true));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"cancel\", menuPatternSlots),\n                new BanButton.Builder());\n\n        return new MenuConfirmBan(menuParseResult);\n    }\n\n    public static class Args extends IslandViewArgs {\n\n        private final SuperiorPlayer targetPlayer;\n\n        public Args(Island island, SuperiorPlayer targetPlayer) {\n            super(island);\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n        private SuperiorPlayer targetPlayer;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.targetPlayer = args.targetPlayer;\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        public SuperiorPlayer getSuperiorPlayer() {\n            return targetPlayer;\n        }\n\n        public void setTargetPlayer(SuperiorPlayer targetPlayer) {\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.DisbandButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuConfirmDisband extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private MenuConfirmDisband(MenuParseResult<IslandMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_CONFIRM_DISBAND, parseResult);\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuConfirmDisband createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"confirm-disband.yml\",\n                MenuConfirmDisband::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"confirm\", menuPatternSlots),\n                new DisbandButton.Builder().setDisbandIsland(true));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"cancel\", menuPatternSlots),\n                new DisbandButton.Builder());\n\n        return new MenuConfirmDisband(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/confirm-disband.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"disband-gui.title\"));\n        newMenu.set(\"type\", \"HOPPER\");\n\n        char[] patternChars = new char[5];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"disband-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"disband-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char confirmChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char cancelChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"disband-gui.confirm\"), patternChars, confirmChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"disband-gui.cancel\"), patternChars, cancelChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"confirm\", confirmChar + \"\");\n        newMenu.set(\"cancel\", cancelChar + \"\");\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(1, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.KickButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuConfirmKick extends AbstractMenu<MenuConfirmKick.View, MenuConfirmKick.Args> {\n\n    private MenuConfirmKick(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_CONFIRM_KICK, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuConfirmKick createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"confirm-kick.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"confirm\", menuPatternSlots),\n                new KickButton.Builder().setKickPlayer(true));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"cancel\", menuPatternSlots),\n                new KickButton.Builder());\n\n        return new MenuConfirmKick(menuParseResult);\n    }\n\n    public static class Args extends IslandViewArgs {\n\n        private final SuperiorPlayer targetPlayer;\n\n        public Args(Island island, SuperiorPlayer targetPlayer) {\n            super(island);\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n        private SuperiorPlayer targetPlayer;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.targetPlayer = args.targetPlayer;\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        public SuperiorPlayer getSuperiorPlayer() {\n            return targetPlayer;\n        }\n\n        public void setTargetPlayer(SuperiorPlayer targetPlayer) {\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmLeave.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.LeaveButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuConfirmLeave extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private MenuConfirmLeave(MenuParseResult<BaseMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_CONFIRM_LEAVE, parseResult);\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    @Nullable\n    public static MenuConfirmLeave createInstance() {\n        MenuParseResult<BaseMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"confirm-leave.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<BaseMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"confirm\", menuPatternSlots),\n                new LeaveButton.Builder().setLeaveIsland(true));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"cancel\", menuPatternSlots),\n                new LeaveButton.Builder());\n\n        return new MenuConfirmLeave(menuParseResult);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.TransferButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuConfirmTransfer extends AbstractMenu<MenuConfirmTransfer.View, MenuConfirmTransfer.Args> {\n\n    private MenuConfirmTransfer(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_CONFIRM_TRANSFER, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuConfirmTransfer createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"confirm-transfer.yml\", null);\n\n        if (menuParseResult == null)\n            return null;\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"confirm\", menuPatternSlots),\n                new TransferButton.Builder().setNewOwner(true));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"cancel\", menuPatternSlots),\n                new TransferButton.Builder());\n\n        return new MenuConfirmTransfer(menuParseResult);\n    }\n\n    public static class Args extends IslandViewArgs {\n\n        private final SuperiorPlayer targetPlayer;\n\n        public Args(Island island, SuperiorPlayer targetPlayer) {\n            super(island);\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n        private SuperiorPlayer targetPlayer;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.targetPlayer = args.targetPlayer;\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        public SuperiorPlayer getSuperiorPlayer() {\n            return targetPlayer;\n        }\n\n        public void setTargetPlayer(SuperiorPlayer targetPlayer) {\n            this.targetPlayer = targetPlayer;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.ControlPanelButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuControlPanel extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private MenuControlPanel(MenuParseResult<IslandMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_CONTROL_PANEL, parseResult);\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuControlPanel createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"control-panel.yml\",\n                MenuControlPanel::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"members\", menuPatternSlots),\n                new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_MEMBERS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"settings\", menuPatternSlots),\n                new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_SETTINGS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"visitors\", menuPatternSlots),\n                new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_VISITORS));\n\n        return new MenuControlPanel(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"main-panel.title\"));\n\n        int size = cfg.getInt(\"main-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"main-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"main-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char membersChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char settingsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char visitorsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"main-panel.members\"), patternChars, membersChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"main-panel.settings\"), patternChars, settingsChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"main-panel.visitors\"), patternChars, visitorsChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"members\", membersChar + \"\");\n        newMenu.set(\"settings\", settingsChar + \"\");\n        newMenu.set(\"visitors\", visitorsChar + \"\");\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.CoopsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\n\nimport java.util.List;\n\npublic class MenuCoops extends AbstractPagedMenu<MenuCoops.View, IslandViewArgs, SuperiorPlayer> {\n\n    private MenuCoops(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_COOPS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuCoops createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"coops.yml\",\n                null, new CoopsPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuCoops(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<MenuCoops.View, IslandViewArgs, SuperiorPlayer> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<MenuCoops.View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", String.valueOf(this.island.getCoopPlayers().size()))\n                    .replace(\"{1}\", String.valueOf(this.island.getCoopLimit()));\n        }\n\n        @Override\n        protected List<SuperiorPlayer> requestObjects() {\n            return island.getCoopPlayers();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCounts.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.CountsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.Material;\n\nimport java.math.BigInteger;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\npublic class MenuCounts extends AbstractPagedMenu<MenuCounts.View, IslandViewArgs, MenuCounts.BlockCount> {\n\n    private static final Comparator<MenuCounts.BlockCount> BLOCK_COUNT_COMPARATOR = (o1, o2) -> {\n        Material firstMaterial = getMaterialFromKey(o1.getBlockKey());\n        Material secondMaterial = getMaterialFromKey(o2.getBlockKey());\n        int compare = plugin.getNMSAlgorithms().compareMaterials(firstMaterial, secondMaterial);\n        return compare != 0 ? compare : o1.getBlockKey().compareTo(o2.getBlockKey());\n    };\n    private static final Function<Map.Entry<Key, BigInteger>, MenuCounts.BlockCount> BLOCK_COUNT_MAPPER =\n            entry -> new MenuCounts.BlockCount(entry.getKey(), entry.getValue());\n\n    private MenuCounts(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_COUNTS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuCounts createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"counts.yml\",\n                null, new CountsPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuCounts(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<View, IslandViewArgs, MenuCounts.BlockCount> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        protected List<MenuCounts.BlockCount> requestObjects() {\n            return new SequentialListBuilder<BlockCount>()\n                    .sorted(BLOCK_COUNT_COMPARATOR)\n                    .build(island.getBlockCountsAsBigInteger().entrySet(), BLOCK_COUNT_MAPPER);\n        }\n\n    }\n\n    private static Material getMaterialFromKey(Key key) {\n        if (key instanceof MaterialKey)\n            return ((MaterialKey) key).getMaterial();\n\n        return EnumHelper.getEnum(Material.class, key.getGlobalKey(), \"BEDROCK\");\n    }\n\n    public static class BlockCount {\n\n        private final Key blockKey;\n        private final BigInteger amount;\n\n        public BlockCount(Key blockKey, BigInteger amount) {\n            this.blockKey = blockKey;\n            this.amount = amount;\n        }\n\n        public Key getBlockKey() {\n            return blockKey;\n        }\n\n        public BigInteger getAmount() {\n            return amount;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.GlobalWarpsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Predicate;\n\npublic class MenuGlobalWarps extends AbstractPagedMenu<MenuGlobalWarps.View, EmptyViewArgs, Island> {\n\n    private final boolean visitorWarps;\n\n    private MenuGlobalWarps(MenuParseResult<View> parseResult, boolean visitorWarps) {\n        super(MenuIdentifiers.MENU_GLOBAL_WARPS, parseResult, false);\n        this.visitorWarps = visitorWarps;\n    }\n\n    public boolean isVisitorWarps() {\n        return visitorWarps;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this);\n    }\n\n    @Nullable\n    public static MenuGlobalWarps createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"global-warps.yml\",\n                MenuGlobalWarps::convertOldGUI, new GlobalWarpsPagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        PagedMenuLayout.Builder<View, Island> patternBuilder = (PagedMenuLayout.Builder<View, Island>) menuParseResult.getLayoutBuilder();\n\n        boolean visitorWarps = cfg.getBoolean(\"visitor-warps\", false);\n\n        List<Integer> slots = new LinkedList<>();\n\n        if (cfg.isString(\"warps\"))\n            slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"warps\", menuPatternSlots));\n        if (cfg.isString(\"slots\"))\n            slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"slots\", menuPatternSlots));\n        if (slots.isEmpty())\n            slots.add(-1);\n\n        patternBuilder.setPagedObjectSlots(slots, new GlobalWarpsPagedObjectButton.Builder());\n\n        return new MenuGlobalWarps(menuParseResult, visitorWarps);\n    }\n\n    public class View extends AbstractPagedMenuView<MenuGlobalWarps.View, EmptyViewArgs, Island> {\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, EmptyViewArgs> menu) {\n            super(inventoryViewer, previousMenuView, menu);\n        }\n\n        @Override\n        protected List<Island> requestObjects() {\n            return new SequentialListBuilder<Island>()\n                    .sorted(SortingTypes.getGlobalWarpsSorting().getComparator())\n                    .filter(ISLANDS_FILTER)\n                    .build(plugin.getGrid().getIslands());\n        }\n\n        private final Predicate<Island> ISLANDS_FILTER = island -> {\n            if (visitorWarps)\n                return island.getVisitorsPosition(null /* unused */) != null;\n            else if (island.equals(getInventoryViewer().getIsland()))\n                return !island.getIslandWarps().isEmpty();\n            else\n                return island.getIslandWarps().values().stream().anyMatch(islandWarp -> !islandWarp.hasPrivateFlag());\n        };\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/warps-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"global-gui.title\"));\n\n        int size = cfg.getInt(\"global-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"global-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"global-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"global-gui\"),\n                cfg.getConfigurationSection(\"global-gui.warp-item\"),\n                newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"visitor-warps\", cfg.getConfigurationSection(\"global-gui.visitor-warps\"));\n        newMenu.set(\"warps\", newMenu.getString(\"slots\"));\n        newMenu.set(\"slots\", null);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankBalanceButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomDepositButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomWithdrawButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankDepositButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BankWithdrawButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenBankLogsButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.List;\n\npublic class MenuIslandBank extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private MenuIslandBank(MenuParseResult<IslandMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_BANK, parseResult);\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.getIsland().equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandBank createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"island-bank.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemChar : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                if (cfg.isConfigurationSection(\"items.\" + itemChar + \".bank-action\")) {\n                    List<Integer> slots = menuPatternSlots.getSlots(itemChar);\n\n                    if (slots.isEmpty()) {\n                        continue;\n                    }\n\n                    GameSound successSound = MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + itemChar + \".success-sound\"));\n                    GameSound failSound = MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + itemChar + \".fail-sound\"));\n\n                    if (cfg.isDouble(\"items.\" + itemChar + \".bank-action.withdraw\")) {\n                        double withdrawPercentage = cfg.getDouble(\"items.\" + itemChar + \".bank-action.withdraw\");\n                        if (withdrawPercentage <= 0) {\n                            patternBuilder.mapButtons(slots, new BankCustomWithdrawButton.Builder()\n                                    .setFailSound(failSound).setSuccessSound(successSound));\n                        } else {\n                            patternBuilder.mapButtons(slots, new BankWithdrawButton.Builder(withdrawPercentage)\n                                    .setFailSound(failSound).setSuccessSound(successSound));\n                        }\n                    } else if (cfg.isList(\"items.\" + itemChar + \".bank-action.withdraw\")) {\n                        List<String> withdrawCommands = cfg.getStringList(\"items.\" + itemChar + \".bank-action.withdraw\");\n                        patternBuilder.mapButtons(slots, new BankWithdrawButton.Builder(withdrawCommands)\n                                .setFailSound(failSound).setSuccessSound(successSound));\n                    } else if (cfg.isDouble(\"items.\" + itemChar + \".bank-action.deposit\")) {\n                        double depositPercentage = cfg.getDouble(\"items.\" + itemChar + \".bank-action.deposit\");\n                        if (depositPercentage <= 0) {\n                            patternBuilder.mapButtons(slots, new BankCustomDepositButton.Builder()\n                                    .setFailSound(failSound).setSuccessSound(successSound));\n                        } else {\n                            patternBuilder.mapButtons(slots, new BankDepositButton.Builder(depositPercentage)\n                                    .setFailSound(failSound).setSuccessSound(successSound));\n                        }\n                    }\n                }\n            }\n        }\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"balance\", menuPatternSlots),\n                new BankBalanceButton.Builder());\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"logs\", menuPatternSlots),\n                new OpenBankLogsButton.Builder());\n\n        return new MenuIslandBank(menuParseResult);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.BannedPlayersPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\n\nimport java.util.List;\n\npublic class MenuIslandBannedPlayers extends AbstractPagedMenu<MenuIslandBannedPlayers.View, IslandViewArgs, SuperiorPlayer> {\n\n    private MenuIslandBannedPlayers(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_BANNED_PLAYERS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandBannedPlayers createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"banned-players.yml\",\n                null, new BannedPlayersPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuIslandBannedPlayers(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<MenuIslandBannedPlayers.View, IslandViewArgs, SuperiorPlayer> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", String.valueOf(island.getBannedPlayers().size()));\n        }\n\n        @Override\n        protected List<SuperiorPlayer> requestObjects() {\n            return island.getBannedPlayers();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandChestPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MenuIslandChest extends AbstractPagedMenu<MenuIslandChest.View, IslandViewArgs, IslandChest> {\n\n    private MenuIslandChest(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_CHEST, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandChest createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"island-chest.yml\",\n                null, new IslandChestPagedObjectButton.Builder());\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        PagedMenuLayoutImpl.Builder<View, IslandChest> patternBuilder = (PagedMenuLayoutImpl.Builder<View, IslandChest>) menuParseResult.getLayoutBuilder();\n\n        if (cfg.isString(\"slots\")) {\n            for (char slotChar : cfg.getString(\"slots\", \"\").toCharArray()) {\n                List<Integer> slots = menuPatternSlots.getSlots(slotChar);\n\n                ConfigurationSection validPageSection = cfg.getConfigurationSection(\"items.\" + slotChar + \".valid-page\");\n                ConfigurationSection invalidPageSection = cfg.getConfigurationSection(\"items.\" + slotChar + \".invalid-page\");\n\n                if (validPageSection == null) {\n                    Log.warnFromFile(\"island-chest.yml\", \"The slot char \", slotChar, \" is missing the valid-page section.\");\n                    continue;\n                }\n\n                if (invalidPageSection == null) {\n                    Log.warnFromFile(\"island-chest.yml\", \"&cThe slot char \", slotChar, \" is missing the invalid-page section.\");\n                    continue;\n                }\n\n                IslandChestPagedObjectButton.Builder buttonBuilder = new IslandChestPagedObjectButton.Builder();\n                buttonBuilder.setButtonItem(MenuParserImpl.getInstance().getItemStack(\"menus/island-chest.yml\", validPageSection));\n                buttonBuilder.setNullItem(MenuParserImpl.getInstance().getItemStack(\"menus/island-chest.yml\", invalidPageSection));\n\n                patternBuilder.mapButtons(slots, buttonBuilder);\n            }\n        }\n\n        return new MenuIslandChest(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<MenuIslandChest.View, IslandViewArgs, IslandChest> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        protected List<IslandChest> requestObjects() {\n            return new SequentialListBuilder<IslandChest>()\n                    .build(Arrays.asList(island.getChest()));\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport org.bukkit.block.Biome;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.math.BigDecimal;\nimport java.util.Arrays;\nimport java.util.Locale;\n\npublic class MenuIslandCreation extends AbstractMenu<MenuIslandCreation.View, MenuIslandCreation.Args> {\n\n    private MenuIslandCreation(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_CREATION, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuIslandCreation createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"island-creation.yml\",\n                MenuIslandCreation::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemSection = cfg.getConfigurationSection(\"items.\" + itemSectionName);\n\n                if (!itemSection.isString(\"schematic\"))\n                    continue;\n\n                Schematic schematic = plugin.getSchematics().getSchematic(itemSection.getString(\"schematic\"));\n\n                if (schematic == null) {\n                    Log.warnFromFile(\"island-creation.yml\", \"Invalid schematic for item \", itemSectionName);\n                    continue;\n                }\n\n                IslandCreationButton.Builder buttonBuilder = new IslandCreationButton.Builder(schematic);\n\n                {\n                    String biomeName = itemSection.getString(\"biome\");\n                    if (biomeName != null) {\n                        Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName);\n\n                        if (biome == null) {\n                            Log.warnFromFile(\"island-creation.yml\", \"Invalid biome name for item \",\n                                    itemSectionName, \": \", biomeName);\n                            continue;\n                        }\n\n                        buttonBuilder.setBiome(biome);\n                    }\n                }\n\n                {\n                    Object bonusWorth = itemSection.get(\"bonus\", itemSection.get(\"bonus-worth\", 0D));\n                    if (bonusWorth instanceof Double) {\n                        buttonBuilder.setBonusWorth(BigDecimal.valueOf((double) bonusWorth));\n                    } else if (bonusWorth instanceof String) {\n                        buttonBuilder.setBonusWorth(new BigDecimal((String) bonusWorth));\n                    }\n                }\n\n                {\n                    Object bonusLevel = itemSection.get(\"bonus-level\", 0D);\n                    if (bonusLevel instanceof Double) {\n                        buttonBuilder.setBonusLevel(BigDecimal.valueOf((double) bonusLevel));\n                    } else if (bonusLevel instanceof String) {\n                        buttonBuilder.setBonusLevel(new BigDecimal((String) bonusLevel));\n                    }\n                }\n\n                ConfigurationSection soundSection = cfg.getConfigurationSection(\"sounds.\" + itemSectionName);\n                if (soundSection != null) {\n                    buttonBuilder.setAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"access\")));\n                    buttonBuilder.setNoAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"no-access\")));\n                }\n\n                ConfigurationSection commandSection = cfg.getConfigurationSection(\"commands.\" + itemSectionName);\n                if (commandSection != null) {\n                    buttonBuilder.setAccessCommands(commandSection.getStringList(\"access\"));\n                    buttonBuilder.setNoAccessCommands(commandSection.getStringList(\"no-access\"));\n                }\n\n                buttonBuilder.setOffset(itemSection.getBoolean(\"offset\", false));\n\n                if (itemSection.isString(\"spawn-offset\"))\n                    buttonBuilder.setSpawnOffset(Serializers.OFFSET_SPACED_SERIALIZER.deserialize(itemSection.getString(\"spawn-offset\")));\n\n                buttonBuilder.setAccessItem(MenuParserImpl.getInstance().getItemStack(\"menus/island-creation.yml\",\n                        itemSection.getConfigurationSection(\"access\")));\n                buttonBuilder.setNoAccessItem(MenuParserImpl.getInstance().getItemStack(\"menus/island-creation.yml\",\n                        itemSection.getConfigurationSection(\"no-access\")));\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName), buttonBuilder);\n            }\n        }\n\n        return new MenuIslandCreation(menuParseResult);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final String islandName;\n\n        public Args(String islandName) {\n            this.islandName = islandName;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> {\n\n        private final String islandName;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.islandName = args.islandName;\n        }\n\n        public String getIslandName() {\n            return islandName;\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/creation-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"creation-gui.title\"));\n\n        int size = cfg.getInt(\"creation-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"creation-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"creation-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        if (cfg.isConfigurationSection(\"creation-gui.schematics\")) {\n            for (String schematicName : cfg.getConfigurationSection(\"creation-gui.schematics\").getKeys(false)) {\n                ConfigurationSection section = cfg.getConfigurationSection(\"creation-gui.schematics.\" + schematicName);\n                char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n                section.set(\"schematic\", schematicName);\n                MenuConverter.convertItemAccess(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection);\n            }\n        }\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandFlagPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class MenuIslandFlags extends AbstractPagedMenu<MenuIslandFlags.View, IslandViewArgs, MenuIslandFlags.IslandFlagInfo> {\n\n    private final List<MenuIslandFlags.IslandFlagInfo> islandFlags;\n\n    private MenuIslandFlags(MenuParseResult<View> parseResult, List<MenuIslandFlags.IslandFlagInfo> islandFlags) {\n        super(MenuIdentifiers.MENU_ISLAND_FLAGS, parseResult, false);\n        this.islandFlags = islandFlags;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandFlags createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"settings.yml\",\n                MenuIslandFlags::convertOldGUI, new IslandFlagPagedObjectButton.Builder());\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        YamlConfiguration cfg = menuParseResult.getConfig();\n\n        List<MenuIslandFlags.IslandFlagInfo> islandFlags = new LinkedList<>();\n        Set<String> detectedFlags = new HashSet<>();\n\n        Optional.ofNullable(cfg.getConfigurationSection(\"settings\")).ifPresent(settingsSection -> {\n            for (String islandFlagName : settingsSection.getKeys(false)) {\n                Optional.ofNullable(settingsSection.getConfigurationSection(islandFlagName)).ifPresent(islandFlagSection -> {\n                    if (islandFlagSection.getBoolean(\"display-menu\", true)) {\n                        islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size()));\n                    }\n                    detectedFlags.add(islandFlagName.toUpperCase(Locale.ENGLISH));\n                });\n            }\n        });\n\n        for (IslandFlag islandFlag : IslandFlag.values()) {\n            String islandFlagName = islandFlag.getName();\n            if (!detectedFlags.contains(islandFlagName)) {\n                Log.warnFromFile(\"settings.yml\", \"Potentially missing setting \", islandFlagName);\n            }\n        }\n\n        return new MenuIslandFlags(menuParseResult, islandFlags);\n    }\n\n    private static IslandFlagInfo loadIslandFlagInfo(ConfigurationSection islandFlagSection, String islandFlagName, int position) {\n        TemplateItem enabledIslandFlagItem = null;\n        TemplateItem disabledIslandFlagItem = null;\n        GameSound clickSound = null;\n\n        if (islandFlagSection != null) {\n            enabledIslandFlagItem = MenuParserImpl.getInstance().getItemStack(\"menus/settings.yml\",\n                    islandFlagSection.getConfigurationSection(\"settings-enabled\"));\n            disabledIslandFlagItem = MenuParserImpl.getInstance().getItemStack(\"menus/settings.yml\",\n                    islandFlagSection.getConfigurationSection(\"settings-disabled\"));\n            clickSound = MenuParserImpl.getInstance().getSound(islandFlagSection.getConfigurationSection(\"sound\"));\n        }\n\n        return new MenuIslandFlags.IslandFlagInfo(islandFlagName, enabledIslandFlagItem,\n                disabledIslandFlagItem, clickSound, position);\n    }\n\n    public class View extends AbstractPagedMenuView<MenuIslandFlags.View, IslandViewArgs, IslandFlagInfo> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        protected List<IslandFlagInfo> requestObjects() {\n            return Collections.unmodifiableList(islandFlags);\n        }\n\n    }\n\n    public static class IslandFlagInfo implements Comparable<MenuIslandFlags.IslandFlagInfo> {\n\n        private final LazyReference<IslandFlag> islandFlag = new LazyReference<IslandFlag>() {\n            @Override\n            protected IslandFlag create() {\n                try {\n                    return IslandFlag.getByName(IslandFlagInfo.this.islandFlagName);\n                } catch (Exception error) {\n                    return null;\n                }\n            }\n        };\n\n        private final String islandFlagName;\n        private final TemplateItem enabledIslandFlagItem;\n        private final TemplateItem disabledIslandFlagItem;\n        private final GameSound clickSound;\n        private final int position;\n\n\n        public IslandFlagInfo(String islandFlagName, TemplateItem enabledIslandFlagItem,\n                              TemplateItem disabledIslandFlagItem, GameSound clickSound, int position) {\n            this.islandFlagName = islandFlagName;\n            this.enabledIslandFlagItem = enabledIslandFlagItem;\n            this.disabledIslandFlagItem = disabledIslandFlagItem;\n            this.clickSound = clickSound;\n            this.position = position;\n        }\n\n        @Nullable\n        public IslandFlag getIslandFlag() {\n            return islandFlag.get();\n        }\n\n        public ItemBuilder getEnabledIslandFlagItem() {\n            return enabledIslandFlagItem.getBuilder();\n        }\n\n        public ItemBuilder getDisabledIslandFlagItem() {\n            return disabledIslandFlagItem.getBuilder();\n        }\n\n        public GameSound getClickSound() {\n            return clickSound;\n        }\n\n        @Override\n        public int compareTo(@NotNull MenuIslandFlags.IslandFlagInfo other) {\n            return Integer.compare(position, other.position);\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/settings-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"settings-gui.title\"));\n\n        int size = cfg.getInt(\"settings-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"settings-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"settings-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"settings-gui\"), newMenu,\n                patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"settings\", cfg.getConfigurationSection(\"settings-gui.settings\"));\n        newMenu.set(\"sounds\", null);\n        newMenu.set(\"commands\", null);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.MembersPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MenuIslandMembers extends AbstractPagedMenu<MenuIslandMembers.View, IslandViewArgs, SuperiorPlayer> {\n\n    private MenuIslandMembers(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_MEMBERS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandMembers createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"members.yml\",\n                MenuIslandMembers::convertOldGUI, new MembersPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuIslandMembers(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<MenuIslandMembers.View, IslandViewArgs, SuperiorPlayer> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", String.valueOf(island.getIslandMembers(true).size())).\n                    replace(\"{1}\", String.valueOf(island.getTeamLimit()));\n        }\n\n        @Override\n        protected List<SuperiorPlayer> requestObjects() {\n            return island.getIslandMembers(true);\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"members-panel.title\"));\n\n        int size = cfg.getInt(\"members-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"members-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"members-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"members-panel\"),\n                cfg.getConfigurationSection(\"members-panel.member-item\"), newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandPrivilegePagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class MenuIslandPrivileges extends AbstractPagedMenu<\n        MenuIslandPrivileges.View, MenuIslandPrivileges.Args, MenuIslandPrivileges.IslandPrivilegeInfo> {\n\n    private final List<MenuIslandPrivileges.IslandPrivilegeInfo> islandPrivileges;\n    private final String noRolePermission;\n    private final String exactRolePermission;\n    private final String higherRolePermission;\n\n    private MenuIslandPrivileges(MenuParseResult<View> parseResult, List<IslandPrivilegeInfo> islandPrivileges,\n                                 String noRolePermission, String exactRolePermission, String higherRolePermission) {\n        super(MenuIdentifiers.MENU_ISLAND_PRIVILEGES, parseResult, false);\n        this.islandPrivileges = islandPrivileges;\n        this.noRolePermission = noRolePermission;\n        this.exactRolePermission = exactRolePermission;\n        this.higherRolePermission = higherRolePermission;\n    }\n\n    public String getNoRolePermission() {\n        return noRolePermission;\n    }\n\n    public String getExactRolePermission() {\n        return exactRolePermission;\n    }\n\n    public String getHigherRolePermission() {\n        return higherRolePermission;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    public void refreshViews(Island island, Object permissionHolder) {\n        refreshViews(view -> view.island.equals(island) && view.permissionHolder.equals(permissionHolder));\n    }\n\n    @Nullable\n    public static MenuIslandPrivileges createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"permissions.yml\",\n                MenuIslandPrivileges::convertOldGUI, new IslandPrivilegePagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        YamlConfiguration cfg = menuParseResult.getConfig();\n\n        String noRolePermission = cfg.getString(\"messages.no-role-permission\", \"\");\n        String exactRolePermission = cfg.getString(\"messages.exact-role-permission\", \"\");\n        String higherRolePermission = cfg.getString(\"messages.higher-role-permission\", \"\");\n\n        List<MenuIslandPrivileges.IslandPrivilegeInfo> islandPrivileges = new LinkedList<>();\n        Set<String> detectedPrivileges = new HashSet<>();\n\n        Optional.ofNullable(cfg.getConfigurationSection(\"permissions\")).ifPresent(permissionsSection -> {\n            for (String islandPrivilegeName : permissionsSection.getKeys(false)) {\n                Optional.ofNullable(permissionsSection.getConfigurationSection(islandPrivilegeName)).ifPresent(islandPrivilegeSection -> {\n                    if (islandPrivilegeSection.getBoolean(\"display-menu\", true)) {\n                        islandPrivileges.add(loadIslandPrivilegeInfo(islandPrivilegeSection, islandPrivilegeName, islandPrivileges.size()));\n                    }\n                    detectedPrivileges.add(islandPrivilegeName.toUpperCase(Locale.ENGLISH));\n                });\n            }\n        });\n\n        for (IslandPrivilege islandPrivilege : IslandPrivilege.values()) {\n            String islandPrivilegeName = islandPrivilege.getName();\n            if (!detectedPrivileges.contains(islandPrivilegeName)) {\n                Log.warnFromFile(\"permissions.yml\", \"Potentially missing permission \", islandPrivilegeName);\n            }\n        }\n\n        return new MenuIslandPrivileges(menuParseResult, islandPrivileges, noRolePermission,\n                exactRolePermission, higherRolePermission);\n    }\n\n    private static IslandPrivilegeInfo loadIslandPrivilegeInfo(ConfigurationSection islandPrivilegeSection, String islandPrivilegeName, int position) {\n        TemplateItem enabledIslandPrivilegeItem = null;\n        TemplateItem disabledIslandPrivilegeItem = null;\n        TemplateItem rolePrivilegeItem = null;\n        GameSound accessSound = null;\n        GameSound noAccessSound = null;\n        List<String> accessCommands = null;\n        List<String> noAccessCommands = null;\n\n        if (islandPrivilegeSection != null) {\n            enabledIslandPrivilegeItem = MenuParserImpl.getInstance().getItemStack(\"menus/permissions.yml\",\n                    islandPrivilegeSection.getConfigurationSection(\"permission-enabled\"));\n            disabledIslandPrivilegeItem = MenuParserImpl.getInstance().getItemStack(\"menus/permissions.yml\",\n                    islandPrivilegeSection.getConfigurationSection(\"permission-disabled\"));\n            rolePrivilegeItem = MenuParserImpl.getInstance().getItemStack(\"menus/permissions.yml\",\n                    islandPrivilegeSection.getConfigurationSection(\"role-permission\"));\n            accessSound = MenuParserImpl.getInstance().getSound(islandPrivilegeSection.getConfigurationSection(\"has-access.sound\"));\n            noAccessSound = MenuParserImpl.getInstance().getSound(islandPrivilegeSection.getConfigurationSection(\"no-access.sound\"));\n            accessCommands = islandPrivilegeSection.getStringList(\"has-access.commands\");\n            noAccessCommands = islandPrivilegeSection.getStringList(\"no-access.commands\");\n        }\n\n        return new MenuIslandPrivileges.IslandPrivilegeInfo(islandPrivilegeName, enabledIslandPrivilegeItem,\n                disabledIslandPrivilegeItem, rolePrivilegeItem, accessSound, noAccessSound, accessCommands,\n                noAccessCommands, position);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final Island island;\n        private final Object permissionHolder;\n\n        public Args(Island island, Object permissionHolder) {\n            this.island = island;\n            this.permissionHolder = permissionHolder;\n        }\n\n    }\n\n    public class View extends AbstractPagedMenuView<MenuIslandPrivileges.View, MenuIslandPrivileges.Args, IslandPrivilegeInfo> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n        private final Object permissionHolder;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, MenuIslandPrivileges.Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.island;\n            this.permissionHolder = args.permissionHolder;\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        @Nullable\n        public SuperiorPlayer getSuperiorPlayer() {\n            return this.permissionHolder instanceof SuperiorPlayer ? (SuperiorPlayer) this.permissionHolder : null;\n        }\n\n        public Object getPermissionHolder() {\n            return permissionHolder;\n        }\n\n        @Override\n        protected List<IslandPrivilegeInfo> requestObjects() {\n            List<IslandPrivilegeInfo> islandPrivileges = MenuIslandPrivileges.this.islandPrivileges;\n\n            if (this.permissionHolder instanceof SuperiorPlayer &&\n                    !island.isMember((SuperiorPlayer) this.permissionHolder)) {\n                islandPrivileges = new LinkedList<>(islandPrivileges);\n                islandPrivileges.removeIf(info -> {\n                    IslandPrivilege islandPrivilege = info.getIslandPrivilege();\n                    return islandPrivilege != null && islandPrivilege.getType() == IslandPrivilege.Type.COMMAND;\n                });\n            }\n\n            return Collections.unmodifiableList(islandPrivileges);\n        }\n\n    }\n\n    public static class IslandPrivilegeInfo implements Comparable<IslandPrivilegeInfo> {\n\n        private final LazyReference<IslandPrivilege> islandPrivilege = new LazyReference<IslandPrivilege>() {\n            @Override\n            protected IslandPrivilege create() {\n                try {\n                    return IslandPrivilege.getByName(IslandPrivilegeInfo.this.islandPrivilegeName);\n                } catch (Exception error) {\n                    return null;\n                }\n            }\n        };\n\n        private final String islandPrivilegeName;\n        private final TemplateItem enabledIslandPrivilegeItem;\n        private final TemplateItem disabledIslandPrivilegeItem;\n        private final TemplateItem roleIslandPrivilegeItem;\n        private final GameSound accessSound;\n        private final GameSound noAccessSound;\n        private final List<String> accessCommands;\n        private final List<String> noAccessCommands;\n        private final int position;\n\n        public IslandPrivilegeInfo(String islandPrivilegeName, TemplateItem enabledIslandPrivilegeItem,\n                                   TemplateItem disabledIslandPrivilegeItem, TemplateItem roleIslandPrivilegeItem,\n                                   GameSound accessSound, GameSound noAccessSound, List<String> accessCommands,\n                                   List<String> noAccessCommands, int position) {\n            this.islandPrivilegeName = islandPrivilegeName;\n            this.enabledIslandPrivilegeItem = enabledIslandPrivilegeItem;\n            this.disabledIslandPrivilegeItem = disabledIslandPrivilegeItem;\n            this.roleIslandPrivilegeItem = roleIslandPrivilegeItem;\n            this.accessSound = accessSound;\n            this.noAccessSound = noAccessSound;\n            this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands;\n            this.noAccessCommands = noAccessCommands == null ? Collections.emptyList() : noAccessCommands;\n            this.position = position;\n        }\n\n        public IslandPrivilege getIslandPrivilege() {\n            return islandPrivilege.get();\n        }\n\n        public ItemBuilder getEnabledIslandPrivilegeItem() {\n            return enabledIslandPrivilegeItem.getBuilder();\n        }\n\n        public ItemBuilder getDisabledIslandPrivilegeItem() {\n            return disabledIslandPrivilegeItem.getBuilder();\n        }\n\n        @Nullable\n        public ItemBuilder getRoleIslandPrivilegeItem() {\n            return roleIslandPrivilegeItem == null ? null : roleIslandPrivilegeItem.getBuilder();\n        }\n\n        @Nullable\n        public GameSound getAccessSound() {\n            return accessSound;\n        }\n\n        @Nullable\n        public GameSound getNoAccessSound() {\n            return noAccessSound;\n        }\n\n        public List<String> getAccessCommands() {\n            return accessCommands;\n        }\n\n        public List<String> getNoAccessCommands() {\n            return noAccessCommands;\n        }\n\n        @Override\n        public int compareTo(@NotNull MenuIslandPrivileges.IslandPrivilegeInfo other) {\n            return Integer.compare(position, other.position);\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/permissions-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"permissions-gui.title\"));\n\n        int size = cfg.getInt(\"permissions-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"permissions-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"permissions-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"permissions-gui\"), newMenu,\n                patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"permissions\", cfg.getConfigurationSection(\"permissions-gui.permissions\"));\n        newMenu.set(\"sounds\", null);\n        newMenu.set(\"commands\", null);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.RateIslandButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuIslandRate extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private MenuIslandRate(MenuParseResult<IslandMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_RATE, parseResult);\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuIslandRate createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"island-rate.yml\",\n                MenuIslandRate::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"zero-stars\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.ZERO_STARS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"one-star\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.ONE_STAR));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"two-stars\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.TWO_STARS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"three-stars\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.THREE_STARS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"four-stars\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.FOUR_STARS));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"five-stars\", menuPatternSlots),\n                new RateIslandButton.Builder().setRating(Rating.FIVE_STARS));\n\n        return new MenuIslandRate(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/ratings-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"rate-gui.title\"));\n        newMenu.set(\"type\", \"HOPPER\");\n\n        char[] patternChars = new char[5];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"rate-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"rate-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char oneStarChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char twoStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char threeStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char fourStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char fiveStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"rate-gui.one_star\"), patternChars, oneStarChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"rate-gui.two_stars\"), patternChars, twoStarsChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"rate-gui.three_stars\"), patternChars, threeStarsChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"rate-gui.four_stars\"), patternChars, fourStarsChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"rate-gui.five_stars\"), patternChars, fiveStarsChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"one-star\", oneStarChar + \"\");\n        newMenu.set(\"two-stars\", twoStarsChar + \"\");\n        newMenu.set(\"three-stars\", threeStarsChar + \"\");\n        newMenu.set(\"four-stars\", fourStarsChar + \"\");\n        newMenu.set(\"five-stars\", fiveStarsChar + \"\");\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(1, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.RatingsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Function;\n\npublic class MenuIslandRatings extends AbstractPagedMenu<MenuIslandRatings.View, IslandViewArgs, MenuIslandRatings.RatingInfo> {\n\n    private static final Function<Map.Entry<UUID, Rating>, RatingInfo> RATING_INFO_MAPPER =\n            entry -> new RatingInfo(entry.getKey(), entry.getValue());\n\n    private MenuIslandRatings(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_RATINGS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandRatings createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"island-ratings.yml\",\n                MenuIslandRatings::convertOldGUI, new RatingsPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuIslandRatings(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<MenuIslandRatings.View, IslandViewArgs, MenuIslandRatings.RatingInfo> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", Formatters.NUMBER_FORMATTER.format(island.getTotalRating()));\n        }\n\n        @Override\n        protected List<RatingInfo> requestObjects() {\n            return new SequentialListBuilder<RatingInfo>()\n                    .build(island.getRatings().entrySet(), RATING_INFO_MAPPER);\n        }\n\n    }\n\n    public static class RatingInfo {\n\n        private final UUID playerUUID;\n        private final Rating rating;\n\n        public RatingInfo(UUID playerUUID, Rating rating) {\n            this.playerUUID = playerUUID;\n            this.rating = rating;\n        }\n\n        public UUID getPlayerUUID() {\n            return playerUUID;\n        }\n\n        public Rating getRating() {\n            return rating;\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/ratings-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"ratings-gui.title\"));\n\n        int size = cfg.getInt(\"ratings-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"ratings-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"ratings-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"ratings-gui\"),\n                cfg.getConfigurationSection(\"ratings-gui.rate-item\"), newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.UniqueVisitorPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\n\nimport java.util.List;\nimport java.util.function.Function;\n\npublic class MenuIslandUniqueVisitors extends AbstractPagedMenu<MenuIslandUniqueVisitors.View, IslandViewArgs, MenuIslandUniqueVisitors.UniqueVisitorInfo> {\n\n    private static final Function<Pair<SuperiorPlayer, Long>, UniqueVisitorInfo> VISITOR_INFO_MAPPER =\n            visitor -> new UniqueVisitorInfo(visitor.getKey(), visitor.getValue());\n\n    private MenuIslandUniqueVisitors(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_UNIQUE_VISITORS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandUniqueVisitors createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"unique-visitors.yml\",\n                null, new UniqueVisitorPagedObjectButton.Builder());\n        return menuParseResult == null ? null : new MenuIslandUniqueVisitors(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<View, IslandViewArgs, UniqueVisitorInfo> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", island.getUniqueVisitorsWithTimes().size() + \"\");\n        }\n\n        @Override\n        protected List<UniqueVisitorInfo> requestObjects() {\n            return new SequentialListBuilder<UniqueVisitorInfo>()\n                    .build(island.getUniqueVisitorsWithTimes(), VISITOR_INFO_MAPPER);\n        }\n\n    }\n\n    public static class UniqueVisitorInfo {\n\n        private final SuperiorPlayer visitor;\n        private final long visitTime;\n\n        public UniqueVisitorInfo(SuperiorPlayer visitor, long visitTime) {\n            this.visitor = visitor;\n            this.visitTime = visitTime;\n        }\n\n        public SuperiorPlayer getVisitor() {\n            return visitor;\n        }\n\n        public long getVisitTime() {\n            return visitTime;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.UpgradeButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MenuIslandUpgrades extends AbstractMenu<IslandMenuView, IslandViewArgs> {\n\n    private MenuIslandUpgrades(MenuParseResult<IslandMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_UPGRADES, parseResult);\n    }\n\n    @Override\n    protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new IslandMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.getIsland().equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandUpgrades createInstance() {\n        MenuParseResult<IslandMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"upgrades.yml\",\n                MenuIslandUpgrades::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<IslandMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"upgrades\")) {\n            ConfigurationSection upgradesSection = cfg.getConfigurationSection(\"upgrades\");\n            for (Upgrade upgrade : plugin.getUpgrades().getUpgrades()) {\n                ConfigurationSection upgradeSection = upgradesSection.getConfigurationSection(upgrade.getName());\n\n                if (upgradeSection == null) {\n                    continue;\n                }\n\n                List<Integer> slots = MenuParserImpl.getInstance().parseButtonSlots(upgradeSection, \"item\", menuPatternSlots);\n                upgrade.setSlots(slots);\n\n                patternBuilder.mapButtons(slots, new UpgradeButton.Builder(upgrade));\n\n                for (String levelSectionKey : upgradeSection.getKeys(false)) {\n                    int level;\n\n                    try {\n                        level = Integer.parseInt(levelSectionKey);\n                    } catch (NumberFormatException error) {\n                        // Not a number, skipping.\n                        continue;\n                    }\n\n                    if (slots.isEmpty()) {\n                        Log.warnFromFile(\"upgrades.yml\", \"The item of the upgrade \", upgrade.getName(),\n                                \" (level \", level, \") is not inside the pattern, skipping...\");\n                        continue;\n                    }\n\n                    SUpgradeLevel upgradeLevel = (SUpgradeLevel) upgrade.getUpgradeLevel(level);\n\n                    if (upgradeLevel != null) {\n                        TemplateItem hasNextLevel = MenuParserImpl.getInstance().getItemStack(\"menus/upgrades.yml\",\n                                upgradeSection.getConfigurationSection(level + \".has-next-level\"));\n                        if (hasNextLevel == null) {\n                            Log.warnFromFile(\"upgrades.yml\", \"The upgrade \", upgrade.getName(),\n                                    \" (level \", level, \") is missing has-next-level item.\");\n                        }\n\n                        TemplateItem noNextLevel = MenuParserImpl.getInstance().getItemStack(\"menus/upgrades.yml\",\n                                upgradeSection.getConfigurationSection(level + \".no-next-level\"));\n                        if (noNextLevel == null) {\n                            Log.warnFromFile(\"upgrades.yml\", \"&cThe upgrade \", upgrade.getName(),\n                                    \" (level \", level, \") is missing no-next-level item.\");\n                        }\n\n                        GameSound hasNextLevelSound = MenuParserImpl.getInstance().getSound(upgradeSection.getConfigurationSection(level + \".has-next-level.sound\"));\n                        GameSound noNextLevelSound = MenuParserImpl.getInstance().getSound(upgradeSection.getConfigurationSection(level + \".no-next-level.sound\"));\n                        List<String> hasNextLevelCommands = upgradeSection.getStringList(level + \".has-next-level.commands\");\n                        List<String> noNextLevelCommands = upgradeSection.getStringList(level + \".no-next-level.commands\");\n                        upgradeLevel.setItemData(hasNextLevel, noNextLevel, hasNextLevelSound, noNextLevelSound, hasNextLevelCommands, noNextLevelCommands);\n                    }\n                }\n            }\n        }\n\n        return new MenuIslandUpgrades(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/upgrades-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"upgrades-gui.title\"));\n\n        int size = cfg.getInt(\"upgrades-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"upgrades-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"upgrades-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        if (cfg.isConfigurationSection(\"upgrades-gui.upgrades\")) {\n            for (String upgradeName : cfg.getConfigurationSection(\"upgrades-gui.upgrades\").getKeys(false)) {\n                ConfigurationSection section = cfg.getConfigurationSection(\"upgrades-gui.upgrades.\" + upgradeName);\n                char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n                section.set(\"item\", itemChar + \"\");\n                patternChars[section.getInt(\"1.slot\")] = itemChar;\n                for (String upgradeLevel : section.getKeys(false)) {\n                    section.set(upgradeLevel + \".slot\", null);\n                }\n            }\n        }\n\n        newMenu.set(\"upgrades\", cfg.getConfigurationSection(\"upgrades-gui.upgrades\"));\n        newMenu.set(\"sounds\", null);\n        newMenu.set(\"commands\", null);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.ValuesButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Locale;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\npublic class MenuIslandValues extends AbstractMenu<MenuIslandValues.View, IslandViewArgs> {\n\n    private MenuIslandValues(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_VALUES, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandValues createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"values.yml\",\n                MenuIslandValues::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        KeySet keysToUpdate = KeySets.createHashSet(KeyIndicator.MATERIAL);\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemsSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemsSection = cfg.getConfigurationSection(\"items.\" + itemsSectionName);\n\n                String block = itemsSection.getString(\"block\");\n\n                if (block == null)\n                    continue;\n\n                Key blockKey = Keys.ofMaterialAndData(block);\n                keysToUpdate.add(blockKey);\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName), new ValuesButton.Builder(blockKey));\n            }\n        }\n\n        plugin.getBlockValues().registerMenuValueBlocks(keysToUpdate);\n\n        return new MenuIslandValues(menuParseResult);\n    }\n\n    public static class View extends AbstractMenuView<View, IslandViewArgs> implements IIslandMenuView, IPlayerMenuView {\n\n        private final Island island;\n        private SuperiorPlayer targetPlayer;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.targetPlayer = args.getIsland().getOwner();\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        public SuperiorPlayer getSuperiorPlayer() {\n            return targetPlayer;\n        }\n\n        public void setTargetPlayer(SuperiorPlayer targetPlayer) {\n            this.targetPlayer = targetPlayer;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", island.getOwner().getName())\n                    .replace(\"{1}\", Formatters.NUMBER_FORMATTER.format(island.getWorth()))\n                    .replace(\"{2}\", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), getInventoryViewer().getUserLocale()));\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/values-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"values-gui.title\"));\n\n        int size = cfg.getInt(\"values-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"values-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"values-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        ConfigurationSection blockItemSection = cfg.getConfigurationSection(\"values-gui.block-item\");\n\n        for (String material : cfg.getStringList(\"values-gui.materials\")) {\n            char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n            ConfigurationSection section = itemsSection.createSection(itemChar + \"\");\n            String[] materialSections = material.split(\":\");\n            String block = materialSections.length == 2 ? materialSections[0] : materialSections[0] + \":\" + materialSections[1];\n            int slot = Integer.parseInt(materialSections.length == 2 ? materialSections[1] : materialSections[2]);\n            copySection(blockItemSection, section, str ->\n                    str.replace(\"{0}\", Formatters.CAPITALIZED_FORMATTER.format(block)).replace(\"{1}\", \"{0}\"));\n            section.set(\"block\", block);\n            convertType(section, block);\n            patternChars[slot] = itemChar;\n        }\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n    private static void copySection(ConfigurationSection source, ConfigurationSection destination, Function<String, String> stringReplacer) {\n        for (String key : source.getKeys(false)) {\n            if (source.isConfigurationSection(key)) {\n                copySection(source.getConfigurationSection(key), destination.createSection(key), stringReplacer);\n            } else if (source.isList(key)) {\n                destination.set(key, source.getStringList(key).stream().map(stringReplacer).collect(Collectors.toList()));\n            } else if (source.isString(key)) {\n                destination.set(key, stringReplacer.apply(source.getString(key)));\n            } else {\n                destination.set(key, source.getString(key));\n            }\n        }\n    }\n\n    private static void convertType(ConfigurationSection section, String block) {\n        String[] materialSections = block.split(\":\");\n        String spawnerType = materialSections[0],\n                entityType = (materialSections.length >= 2 ? materialSections[1] : \"PIG\").toUpperCase(Locale.ENGLISH);\n        if (spawnerType.equals(Materials.SPAWNER.toBukkitType() + \"\")) {\n            String texture = ItemSkulls.getTexture(entityType);\n            if (!texture.isEmpty()) {\n                section.set(\"type\", Materials.PLAYER_HEAD.toBukkitType().name());\n                if (section.getString(\"type\").equalsIgnoreCase(\"SKULL_ITEM\"))\n                    section.set(\"data\", 3);\n                section.set(\"skull\", texture);\n                return;\n            }\n        }\n\n        section.set(\"type\", spawnerType.equals(Materials.SPAWNER.toBukkitType() + \"\") ? spawnerType : block);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenUniqueVisitorsButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.VisitorPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MenuIslandVisitors extends AbstractPagedMenu<MenuIslandVisitors.View, IslandViewArgs, SuperiorPlayer> {\n\n    private MenuIslandVisitors(MenuParseResult<View> parseResult) {\n        super(MenuIdentifiers.MENU_ISLAND_VISITORS, parseResult, false);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    @Nullable\n    public static MenuIslandVisitors createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"visitors.yml\",\n                MenuIslandVisitors::convertOldGUI, new VisitorPagedObjectButton.Builder());\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"unique-visitors\", menuPatternSlots),\n                new OpenUniqueVisitorsButton.Builder());\n\n        return new MenuIslandVisitors(menuParseResult);\n    }\n\n    public static class View extends AbstractPagedMenuView<View, IslandViewArgs, SuperiorPlayer> implements IIslandMenuView {\n\n        private final Island island;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", String.valueOf(island.getIslandVisitors(false).size()));\n        }\n\n        @Override\n        protected List<SuperiorPlayer> requestObjects() {\n            return island.getIslandVisitors(false);\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"visitors-panel.title\"));\n\n        int size = cfg.getInt(\"visitors-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"visitors-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"visitors-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"visitors-panel\"),\n                cfg.getConfigurationSection(\"visitors-panel.visitor-item\"), newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.MemberManageButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuMemberManage extends AbstractMenu<PlayerMenuView, PlayerViewArgs> {\n\n    private MenuMemberManage(MenuParseResult<PlayerMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_MEMBER_MANAGE, parseResult);\n    }\n\n    @Override\n    protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new PlayerMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void closeViews(SuperiorPlayer islandMember) {\n        closeViews(view -> view.getSuperiorPlayer().equals(islandMember));\n    }\n\n    @Nullable\n    public static MenuMemberManage createInstance() {\n        MenuParseResult<PlayerMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"member-manage.yml\",\n                MenuMemberManage::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<PlayerMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"roles\", menuPatternSlots),\n                new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.SET_ROLE));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"ban\", menuPatternSlots),\n                new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.BAN_MEMBER));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"kick\", menuPatternSlots),\n                new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.KICK_MEMBER));\n\n        return new MenuMemberManage(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"players-panel.title\"));\n\n        int size = cfg.getInt(\"players-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"players-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"players-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char rolesChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char banChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char kickChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"players-panel.roles\"), patternChars, rolesChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"players-panel.ban\"), patternChars, banChar,\n                itemsSection, commandsSection, soundsSection);\n        MenuConverter.convertItem(cfg.getConfigurationSection(\"players-panel.kick\"), patternChars, kickChar,\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"roles\", rolesChar + \"\");\n        newMenu.set(\"ban\", banChar + \"\");\n        newMenu.set(\"kick\", kickChar + \"\");\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.MemberRoleButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\n\npublic class MenuMemberRole extends AbstractMenu<PlayerMenuView, PlayerViewArgs> {\n\n    private MenuMemberRole(MenuParseResult<PlayerMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_MEMBER_ROLE, parseResult);\n    }\n\n    @Override\n    protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args,\n                                                @Nullable MenuView<?, ?> previousMenuView) {\n        return new PlayerMenuView(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void closeViews(SuperiorPlayer islandMember) {\n        closeViews(view -> view.getSuperiorPlayer().equals(islandMember));\n    }\n\n    @Nullable\n    public static MenuMemberRole createInstance() {\n        MenuParseResult<PlayerMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"member-role.yml\",\n                MenuMemberRole::convertOldGUI);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<PlayerMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemsSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemsSection = cfg.getConfigurationSection(\"items.\" + itemsSectionName);\n\n                Object roleObject = itemsSection.get(\"role\");\n\n                PlayerRole playerRole = null;\n\n                if (roleObject instanceof String) {\n                    try {\n                        playerRole = SPlayerRole.of((String) roleObject);\n                    } catch (IllegalArgumentException error) {\n                        Log.warnFromFile(\"member-role.yml\", \"Invalid role name: \", roleObject);\n                        continue;\n                    }\n                } else if (roleObject instanceof Integer) {\n                    playerRole = SPlayerRole.of((Integer) roleObject);\n                    if (playerRole == null) {\n                        Log.warnFromFile(\"member-role.yml\", \"&cInvalid role id: \", roleObject);\n                        continue;\n                    }\n                }\n\n                if (playerRole == null)\n                    continue;\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName),\n                        new MemberRoleButton.Builder().setPlayerRole(playerRole));\n            }\n        }\n\n        return new MenuMemberRole(menuParseResult);\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/panel-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"roles-panel.title\"));\n\n        int size = cfg.getInt(\"roles-panel.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"roles-panel.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"roles-panel.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        if (cfg.isConfigurationSection(\"roles-panel.roles\")) {\n            for (String roleName : cfg.getConfigurationSection(\"roles-panel.roles\").getKeys(false)) {\n                ConfigurationSection section = cfg.getConfigurationSection(\"roles-panel.roles.\" + roleName);\n                char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n                section.set(\"role\", Formatters.CAPITALIZED_FORMATTER.format(roleName));\n                MenuConverter.convertItem(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection);\n            }\n        }\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenMissionCategoryButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\n\npublic class MenuMissions extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private MenuMissions(MenuParseResult<BaseMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_MISSIONS, parseResult);\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    @Nullable\n    public static MenuMissions createInstance() {\n        MenuParseResult<BaseMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"missions.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuLayout.Builder<BaseMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        plugin.getMissions().getMissionCategories().forEach(\n                missionCategory -> patternBuilder.mapButton(missionCategory.getSlot(),\n                        new OpenMissionCategoryButton.Builder().setMissionsCategory(missionCategory)));\n\n        return new MenuMissions(menuParseResult);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.MissionsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\npublic class MenuMissionsCategory extends AbstractPagedMenu<MenuMissionsCategory.View, MenuMissionsCategory.Args, MissionReference> {\n\n    private final boolean sortByCompletion;\n    private final boolean removeCompleted;\n\n    private MenuMissionsCategory(MenuParseResult<View> parseResult, boolean sortByCompletion, boolean removeCompleted) {\n        super(MenuIdentifiers.MENU_MISSIONS_CATEGORY, parseResult, false);\n        this.sortByCompletion = sortByCompletion;\n        this.removeCompleted = removeCompleted;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(MissionCategory missionCategory) {\n        refreshViews(view -> missionCategory.equals(view.missionCategory));\n    }\n\n    @Nullable\n    public static MenuMissionsCategory createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"missions-category.yml\", null,\n                new MissionsPagedObjectButton.Builder());\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        PagedMenuLayout.Builder<View, MissionReference> patternBuilder = (PagedMenuLayout.Builder<View, MissionReference>) menuParseResult.getLayoutBuilder();\n\n        boolean sortByCompletion = cfg.getBoolean(\"sort-by-completion\", false);\n        boolean removeCompleted = cfg.getBoolean(\"remove-completed\", false);\n\n        ConfigurationSection soundsSection = cfg.getConfigurationSection(\"sounds\");\n        if (soundsSection != null) {\n            for (char slotChar : cfg.getString(\"slots\", \"\").toCharArray()) {\n                ConfigurationSection soundSection = soundsSection.getConfigurationSection(slotChar + \"\");\n\n                if (soundSection == null)\n                    continue;\n\n                GameSound completedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"completed\"));\n                GameSound notCompletedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"not-completed\"));\n                GameSound canCompleteSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"can-complete\"));\n                GameSound lockedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection(\"locked\"));\n\n                patternBuilder.setPagedObjectSlots(menuPatternSlots.getSlots(slotChar), new MissionsPagedObjectButton.Builder()\n                        .setCompletedSound(completedSound)\n                        .setNotCompletedSound(notCompletedSound)\n                        .setCanCompleteSound(canCompleteSound)\n                        .setLockedSound(lockedSound));\n            }\n        }\n\n        return new MenuMissionsCategory(menuParseResult, sortByCompletion, removeCompleted);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final MissionCategory missionCategory;\n\n        public Args(MissionCategory missionCategory) {\n            this.missionCategory = missionCategory;\n        }\n\n    }\n\n    public class View extends AbstractPagedMenuView<View, Args, MissionReference> {\n\n        private final MissionCategory missionCategory;\n        private final List<MissionReference> missions;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n\n            this.missionCategory = args.missionCategory;\n\n            if (inventoryViewer == null) {\n                this.missions = Collections.emptyList();\n            } else {\n                SequentialListBuilder<Mission<?>> listBuilder = new SequentialListBuilder<>();\n\n                if (sortByCompletion)\n                    listBuilder.sorted(Comparator.comparingInt(this::getCompletionStatus));\n\n                this.missions = listBuilder\n                        .filter(mission -> plugin.getMissions().canDisplayMission(mission, inventoryViewer, removeCompleted))\n                        .map(args.missionCategory.getMissions(), MissionReference::new);\n            }\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", missionCategory.getName());\n        }\n\n        @Override\n        protected List<MissionReference> requestObjects() {\n            return missions;\n        }\n\n        private int getCompletionStatus(Mission<?> mission) {\n            SuperiorPlayer inventoryViewer = getInventoryViewer();\n            IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer;\n            return missionsHolder == null ? 0 :\n                    !missionsHolder.canCompleteMissionAgain(mission) ? 2 :\n                            plugin.getMissions().canComplete(inventoryViewer, mission) ? 1 : 0;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.LanguageButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuPlayerLanguage extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private MenuPlayerLanguage(MenuParseResult<BaseMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_PLAYER_LANGUAGE, parseResult);\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    @Nullable\n    public static MenuPlayerLanguage createInstance() {\n        MenuParseResult<BaseMenuView> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"player-language.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<BaseMenuView> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemsSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemSection = cfg.getConfigurationSection(\"items.\" + itemsSectionName);\n\n                String languageName = itemSection.getString(\"language\");\n\n                if (languageName == null)\n                    continue;\n\n                java.util.Locale locale = null;\n\n                try {\n                    locale = PlayerLocales.getLocale(languageName);\n                    if (!PlayerLocales.isValidLocale(locale))\n                        locale = null;\n                } catch (IllegalArgumentException ignored) {\n                }\n\n                if (locale == null) {\n                    Log.warnFromFile(\"player-language.yml\", \"The language \", languageName, \" is not valid.\");\n                    continue;\n                }\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName),\n                        new LanguageButton.Builder().setLanguage(locale));\n            }\n        }\n\n        return new MenuPlayerLanguage(menuParseResult);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.ChangeSortingTypeButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.TopIslandsPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.TopIslandsSelfIslandButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\n\npublic class MenuTopIslands extends AbstractPagedMenu<MenuTopIslands.View, MenuTopIslands.Args, Island> {\n\n    private final boolean sortGlowWhenSelected;\n\n    private MenuTopIslands(MenuParseResult<View> parseResult, boolean sortGlowWhenSelected) {\n        super(MenuIdentifiers.MENU_TOP_ISLANDS, parseResult, false);\n        this.sortGlowWhenSelected = sortGlowWhenSelected;\n    }\n\n    public boolean isSortGlowWhenSelected() {\n        return sortGlowWhenSelected;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Override\n    public CompletableFuture<View> refreshView(View view) {\n        CompletableFuture<View> res = new CompletableFuture<>();\n        plugin.getGrid().sortIslands(view.sortingType, () -> super.refreshView(view).whenComplete((v, err) -> {\n            if (err != null) {\n                res.completeExceptionally(err);\n            } else {\n                res.complete(v);\n            }\n        }));\n        return res;\n    }\n\n    public void refreshViews(SortingType sortingType) {\n        refreshViews(view -> view.sortingType.equals(sortingType));\n    }\n\n    @Nullable\n    public static MenuTopIslands createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"top-islands.yml\",\n                MenuTopIslands::convertOldGUI, new TopIslandsPagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        boolean sortGlowWhenSelected = cfg.getBoolean(\"sort-glow-when-selected\", false);\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"worth-sort\", menuPatternSlots),\n                new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_WORTH));\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"level-sort\", menuPatternSlots),\n                new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_LEVEL));\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"rating-sort\", menuPatternSlots),\n                new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_RATING));\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"players-sort\", menuPatternSlots),\n                new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_PLAYERS));\n\n        if (cfg.isConfigurationSection(\"items\")) {\n            for (String itemSectionName : cfg.getConfigurationSection(\"items\").getKeys(false)) {\n                ConfigurationSection itemSection = cfg.getConfigurationSection(\"items.\" + itemSectionName);\n\n                if (!itemSection.isString(\"sorting-type\"))\n                    continue;\n\n                SortingType sortingType = SortingType.getByName(itemSection.getString(\"sorting-type\"));\n\n                if (sortingType == null) {\n                    Log.warnFromFile(\"top-islands.yml\", \"The sorting type is invalid for the item \", itemSectionName);\n                    continue;\n                }\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName),\n                        new ChangeSortingTypeButton.Builder().setSortingType(sortingType));\n            }\n        }\n\n        if (cfg.isString(\"slots\")) {\n            boolean configuredSelfPlayerButton = false;\n\n            for (char slotsChar : cfg.getString(\"slots\", \"\").toCharArray()) {\n                ConfigurationSection itemsSection = cfg.getConfigurationSection(\"items.\" + slotsChar);\n\n                if (itemsSection == null)\n                    continue;\n\n                TopIslandsPagedObjectButton.Builder slotsBuilder = new TopIslandsPagedObjectButton.Builder();\n                slotsBuilder.setIslandItem(MenuParserImpl.getInstance().getItemStack(\"menus/top-islands.yml\", itemsSection.getConfigurationSection(\"island\")));\n                slotsBuilder.setNoIslandItem(MenuParserImpl.getInstance().getItemStack(\"menus/top-islands.yml\", itemsSection.getConfigurationSection(\"no-island\")));\n                slotsBuilder.setIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + slotsChar + \".island\")));\n                slotsBuilder.setNoIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + slotsChar + \".no-island\")));\n                slotsBuilder.setIslandCommands(cfg.getStringList(\"commands.\" + slotsChar + \".island\"));\n                slotsBuilder.setNoIslandCommands(cfg.getStringList(\"commands.\" + slotsChar + \".no-island\"));\n\n                patternBuilder.mapButtons(menuPatternSlots.getSlots(slotsChar), slotsBuilder);\n\n                if (!configuredSelfPlayerButton) {\n                    configuredSelfPlayerButton = true;\n\n                    TopIslandsSelfIslandButton.Builder selfIslandBuilder = new TopIslandsSelfIslandButton.Builder();\n                    selfIslandBuilder.setIslandItem(MenuParserImpl.getInstance().getItemStack(\"menus/top-islands.yml\", itemsSection.getConfigurationSection(\"island\")));\n                    selfIslandBuilder.setNoIslandItem(MenuParserImpl.getInstance().getItemStack(\"menus/top-islands.yml\", itemsSection.getConfigurationSection(\"no-island\")));\n                    selfIslandBuilder.setIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + slotsChar + \".island\")));\n                    selfIslandBuilder.setNoIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"sounds.\" + slotsChar + \".no-island\")));\n                    selfIslandBuilder.setIslandCommands(cfg.getStringList(\"commands.\" + slotsChar + \".island\"));\n                    selfIslandBuilder.setNoIslandCommands(cfg.getStringList(\"commands.\" + slotsChar + \".no-island\"));\n\n                    patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"player-island\", menuPatternSlots),\n                            selfIslandBuilder);\n                }\n            }\n        }\n\n\n        return new MenuTopIslands(menuParseResult, sortGlowWhenSelected);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final SortingType sortingType;\n\n        public Args(SortingType sortingType) {\n            this.sortingType = sortingType;\n        }\n\n    }\n\n    public static class View extends AbstractPagedMenuView<View, Args, Island> {\n\n        private final Set<SortingType> alreadySorted = new HashSet<>();\n        private SortingType sortingType;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.sortingType = args.sortingType;\n        }\n\n        public SortingType getSortingType() {\n            return sortingType;\n        }\n\n        public boolean setSortingType(SortingType sortingType) {\n            this.sortingType = sortingType;\n            this.updatePagedObjects();\n            return this.alreadySorted.add(sortingType);\n        }\n\n        @Override\n        protected List<Island> requestObjects() {\n            return plugin.getGrid().getIslands(sortingType);\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/top-islands.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"top-islands.title\"));\n\n        int size = cfg.getInt(\"top-islands.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"top-islands.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"top-islands.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char worthChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char levelChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char ratingChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char playersChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n        char playerIslandChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        for (String slot : cfg.getString(\"top-islands.slots\").split(\",\"))\n            patternChars[Integer.parseInt(slot)] = slotsChar;\n\n        ConfigurationSection islandItemSection = cfg.getConfigurationSection(\"top-islands.island-item\");\n        newMenu.set(\"items.\" + slotsChar + \".island\", islandItemSection);\n        newMenu.set(\"sounds.\" + slotsChar + \".island\", islandItemSection.getConfigurationSection(\"sound\"));\n        islandItemSection.set(\"sound\", null);\n\n        ConfigurationSection noIslandItemSection = cfg.getConfigurationSection(\"top-islands.no-island-item\");\n        newMenu.set(\"items.\" + slotsChar + \".no-island\", noIslandItemSection);\n        newMenu.set(\"sounds.\" + slotsChar + \".no-island\", noIslandItemSection.getConfigurationSection(\"sound\"));\n        noIslandItemSection.set(\"sound\", null);\n\n        if (cfg.isConfigurationSection(\"top-islands.worth-sort\")) {\n            MenuConverter.convertItem(cfg.getConfigurationSection(\"top-islands.worth-sort\"), patternChars, worthChar,\n                    itemsSection, commandsSection, soundsSection);\n        }\n        if (cfg.isConfigurationSection(\"top-islands.level-sort\")) {\n            MenuConverter.convertItem(cfg.getConfigurationSection(\"top-islands.level-sort\"), patternChars, levelChar,\n                    itemsSection, commandsSection, soundsSection);\n        }\n        if (cfg.isConfigurationSection(\"top-islands.rating-sort\")) {\n            MenuConverter.convertItem(cfg.getConfigurationSection(\"top-islands.rating-sort\"), patternChars, ratingChar,\n                    itemsSection, commandsSection, soundsSection);\n        }\n        if (cfg.isConfigurationSection(\"top-islands.players-sort\")) {\n            MenuConverter.convertItem(cfg.getConfigurationSection(\"top-islands.players-sort\"), patternChars, playersChar,\n                    itemsSection, commandsSection, soundsSection);\n        }\n\n        if (cfg.isInt(\"player-island-slot\"))\n            patternChars[cfg.getInt(\"player-island-slot\")] = playerIslandChar;\n\n        newMenu.set(\"worth-sort\", worthChar);\n        newMenu.set(\"level-sort\", levelChar);\n        newMenu.set(\"rating-sort\", ratingChar);\n        newMenu.set(\"players-sort\", playersChar);\n        newMenu.set(\"player-island\", playerIslandChar);\n        newMenu.set(\"sort-glow-when-selected\", false);\n\n        char invalidChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        newMenu.set(\"slots\", slotsChar);\n        newMenu.set(\"previous-page\", invalidChar);\n        newMenu.set(\"current-page\", invalidChar);\n        newMenu.set(\"next-page\", invalidChar);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.DynamicArray;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.List;\n\npublic class MenuWarpCategories extends AbstractPagedMenu<MenuWarpCategories.View, IslandViewArgs, WarpCategory> {\n\n    private final List<String> editLore;\n    private final int rowsSize;\n\n    private MenuWarpCategories(MenuParseResult<View> parseResult, List<String> editLore, int rowsSize) {\n        super(MenuIdentifiers.MENU_WARP_CATEGORIES, parseResult, true);\n        this.editLore = editLore;\n        this.rowsSize = rowsSize;\n    }\n\n    public List<String> getEditLore() {\n        return editLore;\n    }\n\n    public int getRowsSize() {\n        return rowsSize;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(Island island) {\n        refreshViews(view -> view.island.equals(island));\n    }\n\n    public void closeViews(Island island) {\n        closeViews(view -> view.getIsland().equals(island));\n    }\n\n    @Nullable\n    public static MenuWarpCategories createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"warp-categories.yml\",\n                MenuWarpCategories::convertOldGUI, new WarpCategoryPagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        YamlConfiguration cfg = menuParseResult.getConfig();\n\n        List<String> editLore = cfg.getStringList(\"edit-lore\");\n        int rowsSize = cfg.getStringList(\"pattern\").size();\n\n        return new MenuWarpCategories(menuParseResult, editLore, rowsSize);\n    }\n\n    public static class View extends AbstractPagedMenuView<View, IslandViewArgs, WarpCategory> implements IIslandMenuView {\n\n        private final Island island;\n        private final boolean hasManagePerms;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, IslandViewArgs> menu, IslandViewArgs args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.hasManagePerms = island.isMember(inventoryViewer) &&\n                    island.hasPermission(inventoryViewer, IslandPrivileges.SET_WARP);\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        protected List<WarpCategory> requestObjects() {\n            DynamicArray<WarpCategory> warpCategories = new DynamicArray<>();\n            island.getWarpCategories().values().forEach(warpCategory -> warpCategory.getWarps()\n                    .stream()\n                    .filter(islandWarp -> island.isMember(getInventoryViewer()) || !islandWarp.hasPrivateFlag())\n                    .findAny()\n                    .ifPresent(unused -> warpCategories.set(warpCategory.getSlot(), warpCategory)));\n            return warpCategories.toList();\n        }\n\n        public boolean hasManagePerms() {\n            return hasManagePerms;\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        if (newMenu.isString(\"slots\") || !newMenu.isConfigurationSection(\"items\"))\n            return false;\n\n        String itemChar = newMenu.getConfigurationSection(\"items\")\n                .getKeys(false).stream()\n                .findFirst()\n                .orElse(null);\n\n        if (itemChar == null)\n            return false;\n\n        newMenu.set(\"slots\", itemChar);\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconDisplayButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditLoreButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditTypeButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconRenameButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryIconEditConfirmButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuWarpCategoryIconEdit extends AbstractMenu<AbstractIconProviderMenu.View<WarpCategory>, AbstractIconProviderMenu.Args<WarpCategory>> {\n\n    private MenuWarpCategoryIconEdit(MenuParseResult<AbstractIconProviderMenu.View<WarpCategory>> parseResult) {\n        super(MenuIdentifiers.MENU_WARP_CATEGORIES_ICON_EDIT, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, AbstractIconProviderMenu.Args<WarpCategory> args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuWarpCategoryIconEdit createInstance() {\n        MenuParseResult<AbstractIconProviderMenu.View<WarpCategory>> menuParseResult = MenuParserImpl.getInstance().loadMenu(\n                \"warp-category-icon-edit.yml\", null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<AbstractIconProviderMenu.View<WarpCategory>> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-type\", menuPatternSlots),\n                new IconEditTypeButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_TYPE));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-rename\", menuPatternSlots),\n                new IconRenameButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_NAME));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-relore\", menuPatternSlots),\n                new IconEditLoreButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_LORE));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-confirm\", menuPatternSlots),\n                new WarpCategoryIconEditConfirmButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-slots\", menuPatternSlots),\n                new IconDisplayButton.Builder<>());\n\n        return new MenuWarpCategoryIconEdit(menuParseResult);\n    }\n\n    public static class Args extends AbstractIconProviderMenu.Args<WarpCategory> {\n\n        public Args(WarpCategory warpCategory) {\n            super(warpCategory, warpCategory == null ? null : new TemplateItem(new ItemBuilder(warpCategory.getRawIcon())));\n        }\n\n    }\n\n    public static class View extends AbstractIconProviderMenu.View<WarpCategory> {\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<AbstractIconProviderMenu.View<WarpCategory>, AbstractIconProviderMenu.Args<WarpCategory>> menu,\n             AbstractIconProviderMenu.Args<WarpCategory> args) {\n            super(inventoryViewer, previousMenuView, menu, args);\n        }\n\n        @Override\n        public Island getIsland() {\n            return getIconProvider().getIsland();\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", getIconProvider().getName());\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageIconButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageRenameButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageWarpsButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuWarpCategoryManage extends AbstractMenu<MenuWarpCategoryManage.View, MenuWarpCategoryManage.Args> {\n\n    private final GameSound successUpdateSound;\n\n    private MenuWarpCategoryManage(MenuParseResult<View> parseResult, @Nullable GameSound successUpdateSound) {\n        super(MenuIdentifiers.MENU_WARP_CATEGORIES_MANAGE, parseResult);\n        this.successUpdateSound = successUpdateSound;\n    }\n\n    @Nullable\n    public GameSound getSuccessUpdateSound() {\n        return successUpdateSound;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(WarpCategory warpCategory) {\n        refreshViews(view -> view.warpCategory.equals(warpCategory));\n    }\n\n    @Nullable\n    public static MenuWarpCategoryManage createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"warp-category-manage.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        GameSound successUpdateSound = cfg.isConfigurationSection(\"success-update-sound\") ?\n                MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"success-update-sound\")) : null;\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"category-rename\", menuPatternSlots),\n                new WarpCategoryManageRenameButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"category-icon\", menuPatternSlots),\n                new WarpCategoryManageIconButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"category-warps\", menuPatternSlots),\n                new WarpCategoryManageWarpsButton.Builder());\n\n        return new MenuWarpCategoryManage(menuParseResult, successUpdateSound);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final WarpCategory warpCategory;\n\n        public Args(WarpCategory warpCategory) {\n            this.warpCategory = warpCategory;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> implements IIslandMenuView {\n\n        private final WarpCategory warpCategory;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.warpCategory = args.warpCategory;\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.warpCategory.getIsland();\n        }\n\n        public WarpCategory getWarpCategory() {\n            return warpCategory;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", warpCategory.getName());\n        }\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconDisplayButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditLoreButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditTypeButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IconRenameButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpIconEditConfirmButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.warp.WarpIcons;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuWarpIconEdit extends AbstractMenu<AbstractIconProviderMenu.View<IslandWarp>, AbstractIconProviderMenu.Args<IslandWarp>> {\n\n    private MenuWarpIconEdit(MenuParseResult<AbstractIconProviderMenu.View<IslandWarp>> parseResult) {\n        super(MenuIdentifiers.MENU_WARP_ICON_EDIT, parseResult);\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, AbstractIconProviderMenu.Args<IslandWarp> args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    @Nullable\n    public static MenuWarpIconEdit createInstance() {\n        MenuParseResult<AbstractIconProviderMenu.View<IslandWarp>> menuParseResult = MenuParserImpl.getInstance().loadMenu(\n                \"warp-icon-edit.yml\", null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<AbstractIconProviderMenu.View<IslandWarp>> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-type\", menuPatternSlots),\n                new IconEditTypeButton.Builder<>(Message.WARP_ICON_NEW_TYPE));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-rename\", menuPatternSlots),\n                new IconRenameButton.Builder<>(Message.WARP_ICON_NEW_NAME));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-relore\", menuPatternSlots),\n                new IconEditLoreButton.Builder<>(Message.WARP_ICON_NEW_LORE));\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-confirm\", menuPatternSlots),\n                new WarpIconEditConfirmButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"icon-slots\", menuPatternSlots),\n                new IconDisplayButton.Builder<>());\n\n        return new MenuWarpIconEdit(menuParseResult);\n    }\n\n    public static class Args extends AbstractIconProviderMenu.Args<IslandWarp> {\n\n        public Args(IslandWarp islandWarp) {\n            super(islandWarp, islandWarp == null ? null : islandWarp.getRawIcon() == null ?\n                    WarpIcons.DEFAULT_WARP_ICON : new TemplateItem(new ItemBuilder(islandWarp.getRawIcon())));\n        }\n\n    }\n\n    public static class View extends AbstractIconProviderMenu.View<IslandWarp> {\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<AbstractIconProviderMenu.View<IslandWarp>, AbstractIconProviderMenu.Args<IslandWarp>> menu,\n             AbstractIconProviderMenu.Args<IslandWarp> args) {\n            super(inventoryViewer, previousMenuView, menu, args);\n        }\n\n        @Override\n        public Island getIsland() {\n            return getIconProvider().getIsland();\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", getIconProvider().getName());\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageIconButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageLocationButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManagePrivateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageRenameButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\npublic class MenuWarpManage extends AbstractMenu<MenuWarpManage.View, MenuWarpManage.Args> {\n\n    private final GameSound successUpdateSound;\n\n    private MenuWarpManage(MenuParseResult<View> parseResult, GameSound successUpdateSound) {\n        super(MenuIdentifiers.MENU_WARP_MANAGE, parseResult);\n        this.successUpdateSound = successUpdateSound;\n    }\n\n    public GameSound getSuccessUpdateSound() {\n        return successUpdateSound;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView<?, ?> previousMenu) {\n        return new View(superiorPlayer, previousMenu, this, args);\n    }\n\n    public void refreshViews(IslandWarp islandWarp) {\n        refreshViews(view -> view.islandWarp.equals(islandWarp));\n    }\n\n    @Nullable\n    public static MenuWarpManage createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"warp-manage.yml\",\n                null);\n\n        if (menuParseResult == null) {\n            return null;\n        }\n\n        MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots();\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        MenuLayout.Builder<View> patternBuilder = menuParseResult.getLayoutBuilder();\n\n        GameSound successUpdateSound = cfg.isConfigurationSection(\"success-update-sound\") ?\n                MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection(\"success-update-sound\")) : null;\n\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"warp-rename\", menuPatternSlots),\n                new WarpManageRenameButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"warp-icon\", menuPatternSlots),\n                new WarpManageIconButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"warp-location\", menuPatternSlots),\n                new WarpManageLocationButton.Builder());\n        patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, \"warp-private\", menuPatternSlots),\n                new WarpManagePrivateButton.Builder());\n\n        return new MenuWarpManage(menuParseResult, successUpdateSound);\n    }\n\n    public static class Args implements ViewArgs {\n\n        private final IslandWarp islandWarp;\n\n        public Args(IslandWarp islandWarp) {\n            this.islandWarp = islandWarp;\n        }\n\n    }\n\n    public static class View extends AbstractMenuView<View, Args> implements IIslandMenuView {\n\n        private final IslandWarp islandWarp;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView, Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.islandWarp = args.islandWarp;\n        }\n\n        @Override\n        public Island getIsland() {\n            return this.islandWarp.getIsland();\n        }\n\n        public IslandWarp getIslandWarp() {\n            return islandWarp;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return title.replace(\"{0}\", islandWarp.getName());\n        }\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.warp.WarpIcons;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MenuWarps extends AbstractPagedMenu<MenuWarps.View, MenuWarps.Args, IslandWarp> {\n\n    private final List<String> editLore;\n\n    private MenuWarps(MenuParseResult<View> parseResult, List<String> editLore) {\n        super(MenuIdentifiers.MENU_WARPS, parseResult, false);\n        this.editLore = editLore;\n    }\n\n    public List<String> getEditLore() {\n        return editLore;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void refreshViews(WarpCategory warpCategory) {\n        refreshViews(view -> view.warpCategory.equals(warpCategory));\n    }\n\n    public void closeViews(WarpCategory warpCategory) {\n        closeViews(view -> view.getWarpCategory().equals(warpCategory));\n    }\n\n    @Nullable\n    public static MenuWarps createInstance() {\n        MenuParseResult<View> menuParseResult = MenuParserImpl.getInstance().loadMenu(\"warps.yml\",\n                MenuWarps::convertOldGUI, new WarpPagedObjectButton.Builder());\n\n        if (menuParseResult == null)\n            return null;\n\n        YamlConfiguration cfg = menuParseResult.getConfig();\n\n        List<String> editLore = cfg.getStringList(\"edit-lore\");\n\n        ItemStack defaultWarpIcon = menuParseResult.getLayoutBuilder().build().getButtons().stream()\n                .filter(button -> button.getViewButtonType().equals(WarpPagedObjectButton.class))\n                .findFirst().map(MenuTemplateButton::getButtonItem)\n                .orElse(null);\n        WarpIcons.DEFAULT_WARP_ICON = new TemplateItem(defaultWarpIcon == null ? new ItemBuilder(Material.AIR) : new ItemBuilder(defaultWarpIcon));\n\n        return new MenuWarps(menuParseResult, editLore);\n    }\n\n    public static class Args extends IslandViewArgs {\n\n        private final WarpCategory warpCategory;\n\n        public Args(WarpCategory warpCategory) {\n            super(warpCategory.getIsland());\n            this.warpCategory = warpCategory;\n        }\n\n    }\n\n    public static class View extends AbstractPagedMenuView<View, Args, IslandWarp> implements IIslandMenuView {\n\n        private final Island island;\n        private final WarpCategory warpCategory;\n        private final boolean hasManagePerms;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.island = args.getIsland();\n            this.warpCategory = args.warpCategory;\n            this.hasManagePerms = warpCategory.getIsland().isMember(inventoryViewer) &&\n                    warpCategory.getIsland().hasPermission(inventoryViewer, IslandPrivileges.SET_WARP);\n        }\n\n        @Override\n        public Island getIsland() {\n            return island;\n        }\n\n        @Override\n        protected List<IslandWarp> requestObjects() {\n            boolean isMember = warpCategory.getIsland().isMember(getInventoryViewer());\n            return new SequentialListBuilder<IslandWarp>()\n                    .filter(islandWarp -> isMember || !islandWarp.hasPrivateFlag())\n                    .build(warpCategory.getWarps());\n        }\n\n        public WarpCategory getWarpCategory() {\n            return warpCategory;\n        }\n\n        public boolean hasManagePerms() {\n            return hasManagePerms;\n        }\n\n    }\n\n    private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) {\n        File oldFile = new File(plugin.getDataFolder(), \"guis/warps-gui.yml\");\n\n        if (!oldFile.exists())\n            return false;\n\n        //We want to reset the items of newMenu.\n        ConfigurationSection itemsSection = newMenu.createSection(\"items\");\n        ConfigurationSection soundsSection = newMenu.createSection(\"sounds\");\n        ConfigurationSection commandsSection = newMenu.createSection(\"commands\");\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile);\n\n        newMenu.set(\"title\", cfg.getString(\"warps-gui.title\"));\n\n        int size = cfg.getInt(\"warps-gui.size\");\n\n        char[] patternChars = new char[size * 9];\n        Arrays.fill(patternChars, '\\n');\n\n        int charCounter = 0;\n\n        if (cfg.isConfigurationSection(\"warps-gui.fill-items\")) {\n            charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection(\"warps-gui.fill-items\"),\n                    charCounter, patternChars, itemsSection, commandsSection, soundsSection);\n        }\n\n        char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++];\n\n        MenuConverter.convertPagedButtons(cfg.getConfigurationSection(\"warps-gui\"),\n                cfg.getConfigurationSection(\"warps-gui.warp-item\"),\n                newMenu, patternChars,\n                slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++],\n                itemsSection, commandsSection, soundsSection);\n\n        newMenu.set(\"pattern\", MenuConverter.buildPattern(size, patternChars,\n                AbstractMenuLayout.BUTTON_SYMBOLS[charCounter]));\n\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuBlank.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl.internal;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Material;\nimport org.bukkit.Sound;\n\nimport java.util.Arrays;\n\npublic class MenuBlank extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private MenuBlank(MenuParseResult<BaseMenuView> parseResult) {\n        super(MenuIdentifiers.MENU_BLANK, parseResult);\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    public static MenuBlank createInstance() {\n        Sound sound;\n\n        try {\n            sound = Sound.valueOf(\"BLOCK_ANVIL_PLACE\");\n        } catch (Throwable error) {\n            sound = Sound.ANVIL_LAND;\n        }\n\n        RegularMenuLayoutImpl.Builder<BaseMenuView> patternBuilder = RegularMenuLayoutImpl.newBuilder();\n\n        patternBuilder.setTitle(\"\" + ChatColor.RED + ChatColor.BOLD + \"ERROR\");\n        patternBuilder.setRowsCount(3);\n\n        DummyButton.Builder<BaseMenuView> button = new DummyButton.Builder<>();\n        button.setButtonItem(new TemplateItem(new ItemBuilder(Material.BEDROCK)\n                .withName(\"&cUnloaded Menu\")\n                .withLore(Arrays.asList(\n                        \"&7There was an issue with loading the menu.\",\n                        \"&7Contact administrator to fix the issue.\")\n                )));\n        button.setClickSound(new GameSoundImpl(sound, 0.2f, 0.2f));\n        patternBuilder.setButton(13, button.build());\n\n        return new MenuBlank(new MenuParseResult<>(patternBuilder));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuConfigEditor.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl.internal;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.ConfigEditorPagedObjectButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.ConfigEditorSaveButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Material;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class MenuConfigEditor extends AbstractPagedMenu<MenuConfigEditor.View, MenuConfigEditor.Args, ItemStack> {\n\n    private final File configFile;\n    private final CommentedConfiguration config = new CommentedConfiguration();\n    private final String[] ignorePaths;\n\n    private MenuConfigEditor(MenuParseResult<View> parseResult, File configFile, String[] ignorePaths) {\n        super(MenuIdentifiers.MENU_CONFIG_EDITOR, parseResult, true);\n        this.configFile = configFile;\n        this.ignorePaths = ignorePaths;\n        this.reloadConfig();\n    }\n\n    public CommentedConfiguration getConfig() {\n        return config;\n    }\n\n    @Override\n    protected View createViewInternal(SuperiorPlayer superiorPlayer, MenuConfigEditor.Args args,\n                                      @Nullable MenuView<?, ?> previousMenuView) {\n        return new View(superiorPlayer, previousMenuView, this, args);\n    }\n\n    public void saveConfig(SaveCallback onSave) {\n        try {\n            config.save(this.configFile);\n            onSave.accept(this.config);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while saving config file:\");\n        }\n    }\n\n    public void reloadConfig() {\n        try {\n            config.load(this.configFile);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while reloading config file:\");\n        }\n    }\n\n    public void updateConfig(Player player, String path, Object value) {\n        config.set(path, value);\n        player.sendMessage(\"\" + ChatColor.YELLOW + ChatColor.BOLD + \"SuperiorSkyblock\" + ChatColor.GRAY +\n                \" Changed value of \" + path + \" to \" + value);\n    }\n\n    public static MenuConfigEditor createInstance() {\n        PagedMenuLayoutImpl.Builder<MenuConfigEditor.View, ItemStack> patternBuilder = PagedMenuLayoutImpl.newBuilder();\n\n        patternBuilder.setTitle(ChatColor.BOLD + \"Settings Editor\");\n        patternBuilder.setInventoryType(InventoryType.CHEST);\n        patternBuilder.setRowsCount(6);\n\n        patternBuilder.setButton(47, new DummyButton.Builder<View>()\n                .setButtonItem(new TemplateItem(new ItemBuilder(Material.PAPER).withName(\"{0}Previous Page\")))\n                .build());\n        patternBuilder.setPreviousPageSlots(Collections.singletonList(47));\n\n        patternBuilder.setButton(49, new DummyButton.Builder<View>()\n                .setButtonItem(new TemplateItem(new ItemBuilder(Materials.SUNFLOWER.toBukkitType())\n                        .withName(\"&aCurrent Page\").withLore(\"&7Page {0}\")))\n                .build());\n        patternBuilder.setCurrentPageSlots(Collections.singletonList(49));\n\n        patternBuilder.setButton(51, new DummyButton.Builder<View>()\n                .setButtonItem(new TemplateItem(new ItemBuilder(Material.PAPER).withName(\"{0}Next Page\")))\n                .build());\n        patternBuilder.setNextPageSlots(Collections.singletonList(51));\n\n        patternBuilder.setPagedObjectSlots(IntStream.range(0, 36).boxed().collect(Collectors.toList()),\n                new ConfigEditorPagedObjectButton.Builder());\n\n        patternBuilder.setButtons(IntStream.range(36, 45).boxed().collect(Collectors.toList()),\n                new DummyButton.Builder<View>().setButtonItem(new TemplateItem(\n                                new ItemBuilder(Materials.BLACK_STAINED_GLASS_PANE.toBukkitItem()).withName(\" \")))\n                        .build());\n\n        patternBuilder.setButton(40, new ConfigEditorSaveButton.Builder().build());\n\n        return new MenuConfigEditor(new MenuParseResult<>(patternBuilder),\n                new File(plugin.getDataFolder(), \"config.yml\"),\n                new String[]{\"database\", \"max-island-size\", \"island-roles\", \"worlds.normal-world\", \"commands-cooldown\", \"starter-chest\", \"event-commands\"});\n    }\n\n    public interface SaveCallback {\n\n        void accept(CommentedConfiguration config) throws Exception;\n\n    }\n\n    public static class Args implements ViewArgs {\n\n        public static final Args ROOT = new Args(\"\");\n\n        private final String path;\n\n        public Args(String path) {\n            this.path = path;\n        }\n\n    }\n\n    public class View extends AbstractPagedMenuView<View, Args, ItemStack> {\n\n        private final List<String> pathSlots = new LinkedList<>();\n        private final String path;\n\n        View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n             Menu<View, Args> menu, Args args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.path = args.path;\n        }\n\n        public List<String> getPathSlots() {\n            return pathSlots;\n        }\n\n        public String getPath() {\n            return path;\n        }\n\n        @Override\n        public String replaceTitle(String title) {\n            return path.isEmpty() ? title : ChatColor.BOLD + \"Section: \" + path;\n        }\n\n        @Override\n        protected List<ItemStack> requestObjects() {\n            LinkedList<ItemStack> itemStacks = new LinkedList<>();\n            buildFromSection(itemStacks, config.getConfigurationSection(this.path));\n            return Collections.unmodifiableList(itemStacks);\n        }\n\n        private void buildFromSection(List<ItemStack> itemStacks, ConfigurationSection section) {\n            pathSlots.clear();\n\n            for (String path : section.getKeys(false)) {\n                String fullPath = section.getCurrentPath().isEmpty() ? path : section.getCurrentPath() + \".\" + path;\n\n                if (Arrays.stream(ignorePaths).anyMatch(fullPath::contains))\n                    continue;\n\n                ItemBuilder itemBuilder = new ItemBuilder(Materials.CLOCK.toBukkitItem()).withName(\"&6\" +\n                        Formatters.CAPITALIZED_FORMATTER.format(path.replace(\"-\", \"_\")\n                                .replace(\".\", \"_\").replace(\" \", \"_\"))\n                );\n\n                if (section.isBoolean(path))\n                    itemBuilder.withLore(\"&7Value: \" + section.getBoolean(path));\n                else if (section.isInt(path))\n                    itemBuilder.withLore(\"&7Value: \" + section.getInt(path));\n                else if (section.isDouble(path))\n                    itemBuilder.withLore(\"&7Value: \" + section.getDouble(path));\n                else if (section.isString(path))\n                    itemBuilder.withLore(\"&7Value: \" + section.getString(path));\n                else if (section.isList(path))\n                    itemBuilder.withLore(\"&7Value:\", section.getStringList(path));\n                else if (section.isConfigurationSection(path))\n                    itemBuilder.withLore(\"&7Click to edit section.\");\n\n                pathSlots.add(path);\n                itemStacks.add(itemBuilder.build());\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl.internal;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.service.message.MessagesService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class MenuCustom extends AbstractMenu<BaseMenuView, EmptyViewArgs> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<MessagesService> messagesService = new LazyReference<MessagesService>() {\n        @Override\n        protected MessagesService create() {\n            return plugin.getServices().getService(MessagesService.class);\n        }\n    };\n\n    private MenuCustom(MenuParseResult<BaseMenuView> parseResult, String fileName, @Nullable CommandArgs commandArgs) {\n        super(MenuIdentifiers.MENU_CUSTOM_PREFIX + fileName, parseResult);\n        if (commandArgs != null)\n            plugin.getCommands().registerCommand(new CustomMenuCommand(commandArgs));\n    }\n\n    @Override\n    protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused,\n                                              @Nullable MenuView<?, ?> previousMenuView) {\n        return new BaseMenuView(superiorPlayer, previousMenuView, this);\n    }\n\n    public static MenuCustom createInstance(File menuFile) {\n        String fileName = menuFile.getName();\n\n        MenuParseResult<BaseMenuView> menuParseResult = MenuParserImpl.getInstance().loadCustomMenu(fileName, null);\n\n        if (menuParseResult == null)\n            return null;\n\n        YamlConfiguration cfg = menuParseResult.getConfig();\n        CommandArgs args = null;\n\n        if (cfg.isConfigurationSection(\"command\")) {\n            ConfigurationSection commandsSection = cfg.getConfigurationSection(\"command\");\n\n            if (commandsSection == null) {\n                Log.warnFromFile(fileName, \"Custom menu doesn't have it's command section configured correctly, skipping...\");\n                return null;\n            }\n\n            List<String> aliases = commandsSection.isList(\"aliases\") ?\n                    commandsSection.getStringList(\"aliases\") :\n                    Arrays.asList(commandsSection.getString(\"aliases\", \"\").split(\", \"));\n            String permission = commandsSection.getString(\"permission\", \"\");\n            Map<Locale, IMessageComponent> descriptions = new ArrayMap<>();\n            if (commandsSection.isConfigurationSection(\"description\")) {\n                ConfigurationSection description = commandsSection.getConfigurationSection(\"description\");\n                for (String locale : description.getKeys(false)) {\n                    descriptions.put(PlayerLocales.getLocale(locale),\n                            messagesService.get().parseComponent(cfg, description.getCurrentPath() + \".\" + locale));\n                }\n            }\n            boolean displayCommand = commandsSection.getBoolean(\"display-command\", false);\n            boolean requireIsland = commandsSection.getBoolean(\"require-island\", false);\n\n            args = new CommandArgs(aliases, permission, descriptions, displayCommand, requireIsland);\n        }\n\n        return new MenuCustom(menuParseResult, fileName, args);\n    }\n\n    private static class CommandArgs {\n\n        private final List<String> aliases;\n        private final String permission;\n        private final Map<Locale, IMessageComponent> descriptions;\n        private final boolean displayCommand;\n        private final boolean requireIsland;\n\n        CommandArgs(List<String> aliases, String permission, Map<Locale, IMessageComponent> descriptions, boolean displayCommand, boolean requireIsland) {\n            this.aliases = aliases;\n            this.permission = permission;\n            this.descriptions = descriptions;\n            this.displayCommand = displayCommand;\n            this.requireIsland = requireIsland;\n        }\n\n    }\n\n    private class CustomMenuCommand implements ISuperiorCommand {\n\n        private final CommandArgs args;\n\n        public CustomMenuCommand(CommandArgs args) {\n            this.args = args;\n        }\n\n        @Override\n        public List<String> getAliases() {\n            return this.args.aliases;\n        }\n\n        @Override\n        public String getPermission() {\n            return this.args.permission;\n        }\n\n        @Override\n        public String getUsage(Locale locale) {\n            return this.args.aliases.get(0);\n        }\n\n        @Override\n        public String getDescription(Locale locale) {\n            return this.args.descriptions.getOrDefault(locale, EmptyMessageComponent.getInstance()).getMessage();\n        }\n\n        @Override\n        public int getMinArgs() {\n            return 1;\n        }\n\n        @Override\n        public int getMaxArgs() {\n            return 1;\n        }\n\n        @Override\n        public boolean canBeExecutedByConsole() {\n            return false;\n        }\n\n        @Override\n        public boolean displayCommand() {\n            return this.args.displayCommand;\n        }\n\n        @Override\n        public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n            if (this.args.requireIsland && !superiorPlayer.hasIsland()) {\n                Message.INVALID_ISLAND.send(superiorPlayer);\n                return;\n            }\n\n            MenuCustom.this.createView(superiorPlayer, EmptyViewArgs.INSTANCE);\n        }\n\n        @Override\n        public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n            return Collections.emptyList();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/StackedBlocksDepositMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.impl.internal;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.ItemStack;\n\npublic class StackedBlocksDepositMenu implements InventoryHolder {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<StackedBlocksInteractionService> stackedBlocksInteractionService = new LazyReference<StackedBlocksInteractionService>() {\n        @Override\n        protected StackedBlocksInteractionService create() {\n            return plugin.getServices().getService(StackedBlocksInteractionService.class);\n        }\n    };\n\n    private final Inventory inventory;\n    private final Location stackedBlock;\n\n    public StackedBlocksDepositMenu(Location stackedBlock) {\n        this.inventory = Bukkit.createInventory(this, 36, plugin.getSettings().getStackedBlocks().getDepositMenu().getTitle());\n        this.stackedBlock = stackedBlock;\n    }\n\n    @Override\n    public Inventory getInventory() {\n        return inventory;\n    }\n\n    public void onInteract(InventoryClickEvent e) {\n        ItemStack itemToDeposit = null;\n\n        switch (e.getAction()) {\n            case HOTBAR_SWAP:\n                itemToDeposit = e.getView().getBottomInventory().getItem(e.getHotbarButton());\n                break;\n            case PLACE_ALL:\n            case PLACE_ONE:\n            case PLACE_SOME:\n                itemToDeposit = e.getCursor();\n                break;\n            case MOVE_TO_OTHER_INVENTORY:\n                itemToDeposit = e.getCurrentItem();\n                break;\n        }\n\n        if (itemToDeposit == null || itemToDeposit.getType() == Material.AIR)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getWhoClicked());\n        InteractionResult interactionResult = stackedBlocksInteractionService.get().checkStackedBlockInteraction(\n                superiorPlayer, stackedBlock.getBlock(), itemToDeposit);\n        if (interactionResult != InteractionResult.SUCCESS)\n            e.setCancelled(true);\n    }\n\n    public void onClose(InventoryCloseEvent e) {\n        int depositAmount = 0;\n        ItemStack blockItem = null;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer());\n        Block block = stackedBlock.getBlock();\n\n        for (ItemStack itemStack : e.getInventory().getContents()) {\n            if (itemStack != null && itemStack.getType() != Material.AIR) {\n                InteractionResult interactionResult = stackedBlocksInteractionService.get()\n                        .checkStackedBlockInteraction(superiorPlayer, block, itemStack);\n                if (interactionResult == InteractionResult.SUCCESS) {\n                    depositAmount += itemStack.getAmount();\n                    blockItem = itemStack;\n                } else {\n                    stackedBlock.getWorld().dropItemNaturally(stackedBlock, itemStack);\n                }\n            }\n        }\n\n        if (depositAmount > 0) {\n            int finalDepositAmount = depositAmount;\n            ItemStack finalBlockItem = blockItem;\n\n            InteractionResult interactionResult = stackedBlocksInteractionService.get().\n                    handleStackedBlockPlace(superiorPlayer, block, finalDepositAmount, amount -> {\n                        int leftOvers = finalDepositAmount - amount;\n                        if (leftOvers > 0) {\n                            ItemStack toAddBack = finalBlockItem.clone();\n                            toAddBack.setAmount(leftOvers);\n                            BukkitItems.addItem(toAddBack, e.getPlayer().getInventory(), stackedBlock);\n                        }\n                    });\n\n            if (interactionResult == InteractionResult.SUCCESS)\n                plugin.getNMSWorld().playPlaceSound(stackedBlock);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/AbstractMenuLayout.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.layout;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.InventoryHolder;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\npublic abstract class AbstractMenuLayout<V extends MenuView<V, ?>> implements MenuLayout<V> {\n\n    public static final char[] BUTTON_SYMBOLS = new char[]{\n            '!', '@', '#', '$', '%', '^', '&', '*', '-', '_', '+', '=',\n            '~', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '>',\n            '<', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',\n            'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',\n            'X', 'Y', 'Z'\n    };\n\n    private static final ReflectField<Object> INVENTORY = new ReflectField<>(\n            new ClassInfo(\"inventory.CraftInventory\", ClassInfo.PackageType.CRAFTBUKKIT),\n            Object.class, \"inventory\").removeFinal();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    protected final String title;\n    protected final InventoryType inventoryType;\n    protected final MenuTemplateButton<V>[] buttons;\n\n    protected AbstractMenuLayout(String title, InventoryType inventoryType, MenuTemplateButton<V>[] buttons) {\n        this.title = title;\n        this.inventoryType = inventoryType;\n        this.buttons = buttons;\n    }\n\n    @Override\n    public final MenuTemplateButton<V> getButton(int slot) {\n        return slot < 0 || slot >= this.buttons.length ? DummyButton.EMPTY_BUTTON : this.buttons[slot];\n    }\n\n    @Override\n    public Collection<MenuTemplateButton<V>> getButtons() {\n        return new SequentialListBuilder<MenuTemplateButton<V>>().build(Arrays.asList(buttons));\n    }\n\n    @Override\n    public int getRowsCount() {\n        return this.buttons.length / 9;\n    }\n\n    @Override\n    public final Inventory buildInventory(V menuView) {\n        String title = placeholdersService.get().parsePlaceholders(menuView.getInventoryViewer().asOfflinePlayer(),\n                menuView instanceof AbstractMenuView ? ((AbstractMenuView<?, ?>) menuView).replaceTitle(this.title) : this.title);\n\n        Inventory inventory = createInventory(menuView, title);\n\n        populateInventory(inventory, menuView);\n\n        return inventory;\n    }\n\n    protected abstract void populateInventory(Inventory inventory, V menuView);\n\n    private Inventory createInventory(InventoryHolder holder, String title) {\n        Inventory inventory;\n\n        if (this.inventoryType != InventoryType.CHEST) {\n            inventory = Bukkit.createInventory(holder, this.inventoryType, title);\n        } else {\n            inventory = Bukkit.createInventory(holder, this.buttons.length, title);\n        }\n\n        if (inventory.getHolder() == null) {\n            Object menuHolder = plugin.getNMSAlgorithms().createMenuInventoryHolder(this.inventoryType, holder, title);\n            if (menuHolder != null)\n                INVENTORY.set(inventory, menuHolder);\n        }\n\n        return inventory;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static abstract class AbstractBuilder<V extends MenuView<V, ?>> implements MenuLayout.Builder<V> {\n\n        protected String title = \"\";\n        protected InventoryType inventoryType = InventoryType.CHEST;\n        protected MenuTemplateButton<V>[] buttons;\n        private int rowsSize = 6;\n\n        protected AbstractBuilder() {\n        }\n\n        @Override\n        public AbstractBuilder<V> setTitle(String title) {\n            this.title = title;\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> setInventoryType(InventoryType inventoryType) {\n            this.inventoryType = inventoryType;\n            updateButtons();\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> setRowsCount(int rowsCount) {\n            this.rowsSize = rowsCount;\n            updateButtons();\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> setButton(int slot, MenuTemplateButton<V> button) {\n            if (slot >= 0 && slot < this.buttons.length)\n                this.buttons[slot] = button;\n\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> setButtons(MenuTemplateButton<V>[] buttons) {\n            setRowsCount(buttons.length / 9);\n\n            for (int slot = 0; slot < this.buttons.length && slot < buttons.length; ++slot)\n                this.buttons[slot] = buttons[slot];\n\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> setButtons(List<Integer> slots, MenuTemplateButton<V> button) {\n            for (int slot : slots) {\n                if (slot >= 0 && slot < this.buttons.length)\n                    this.buttons[slot] = button;\n            }\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> mapButton(int slot, MenuTemplateButton.Builder<V> buttonBuilder) {\n            if (slot >= 0 && slot < this.buttons.length) {\n                if (this.buttons[slot] == null) {\n                    this.buttons[slot] = buttonBuilder.build();\n                } else {\n                    this.buttons[slot] = ((AbstractMenuTemplateButton<V>) this.buttons[slot]).applyToBuilder(buttonBuilder).build();\n                }\n            }\n            return this;\n        }\n\n        @Override\n        public AbstractBuilder<V> mapButtons(List<Integer> slots, MenuTemplateButton.Builder<V> buttonBuilder) {\n            for (int slot : slots) {\n                if (slot >= 0 && slot < this.buttons.length) {\n                    if (this.buttons[slot] == null) {\n                        this.buttons[slot] = buttonBuilder.build();\n                    } else {\n                        this.buttons[slot] = ((AbstractMenuTemplateButton<V>) this.buttons[slot]).applyToBuilder(buttonBuilder).build();\n                    }\n                }\n            }\n            return this;\n        }\n\n        @Override\n        public abstract MenuLayout<V> build();\n\n        private void updateButtons() {\n            switch (inventoryType) {\n                case CHEST:\n                    rowsSize = Math.max(Math.min(rowsSize, 6), 1);\n                    this.buttons = new MenuTemplateButton[rowsSize * 9];\n                    break;\n                default:\n                    this.buttons = new MenuTemplateButton[inventoryType.getDefaultSize()];\n                    break;\n            }\n\n            Arrays.fill(this.buttons, DummyButton.EMPTY_BUTTON);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.layout;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.CurrentPageButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.NextPageButton;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.PreviousPageButton;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.order.CustomPagedLayoutOrder;\nimport com.bgsoftware.superiorskyblock.core.menu.layout.order.PagedLayoutOrder;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableInt;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class PagedMenuLayoutImpl<V extends MenuView<V, ?>, E> extends AbstractMenuLayout<V> implements PagedMenuLayout<V> {\n\n    @Nullable\n    private final PagedLayoutOrder<V> customLayoutOrder;\n    private final int objectsPerPageCount;\n\n    private PagedMenuLayoutImpl(String title, InventoryType inventoryType, MenuTemplateButton<V>[] buttons, @Nullable PagedLayoutOrder<V> layoutOrder) {\n        super(title, inventoryType, buttons);\n        this.customLayoutOrder = layoutOrder;\n        this.objectsPerPageCount = layoutOrder == null ? countPagedButtons(buttons) : layoutOrder.getObjectsPerPageCount();\n        if (this.customLayoutOrder != null) {\n            // Update button indexes with the custom layout order\n            PagedLayoutOrder.MenuButtonsIterator<V> buttonsIterator = this.customLayoutOrder.createIterator(this.buttons);\n            int buttonIndex = 0;\n            while (buttonsIterator.hasNext()) {\n                MenuTemplateButton<V> templateButton = buttonsIterator.next();\n\n                if (templateButton instanceof PagedMenuTemplateButton)\n                    ((PagedMenuTemplateButton<V, ?>) templateButton).setButtonIndex(buttonIndex++);\n            }\n        }\n    }\n\n    @Override\n    public int getObjectsPerPageCount() {\n        return this.objectsPerPageCount;\n    }\n\n    @Override\n    protected void populateInventory(Inventory inventory, V menuView) {\n        if (!(menuView instanceof PagedMenuView))\n            return;\n\n        // noinspection unchecked\n        PagedMenuView<V, ?, E> pagedMenuView = (PagedMenuView<V, ?, E>) menuView;\n\n        MutableInt pagedObjectSlot = new MutableInt(0);\n\n        // Set all regular buttons in the menu\n        for (int slot = 0; slot < this.buttons.length; ++slot) {\n            MenuViewButton<V> button = this.buttons[slot].createViewButton(menuView);\n\n            if (this.customLayoutOrder != null && button instanceof PagedMenuViewButton)\n                continue;\n\n            populateInventoryWithButton(inventory, button, slot, pagedMenuView, pagedObjectSlot);\n        }\n\n        if (this.customLayoutOrder == null)\n            return;\n\n        PagedLayoutOrder.MenuButtonsIterator<V> buttonsIterator = this.customLayoutOrder.createIterator(this.buttons);\n        while (buttonsIterator.hasNext()) {\n            MenuTemplateButton<V> templateButton = buttonsIterator.next();\n\n            if (!(templateButton instanceof PagedMenuTemplateButton))\n                continue;\n\n            MenuViewButton<V> button = templateButton.createViewButton(menuView);\n            int slot = buttonsIterator.getSlot();\n\n            populateInventoryWithButton(inventory, button, slot, pagedMenuView, pagedObjectSlot);\n        }\n\n    }\n\n    private void populateInventoryWithButton(Inventory inventory, MenuViewButton<V> button, int slot,\n                                             PagedMenuView<V, ?, E> menuView, MutableInt pagedObjectSlot) {\n        int currentPage = menuView.getCurrentPage();\n        List<E> pagedObjects = menuView.getPagedObjects();\n\n        if (button instanceof PagedMenuViewButton) {\n            PagedMenuViewButton<V, E> pagedMenuButton = (PagedMenuViewButton<V, E>) button;\n            int objectIndex = pagedObjectSlot.get() + (this.objectsPerPageCount * (currentPage - 1));\n\n            pagedObjectSlot.set(pagedObjectSlot.get() + 1);\n\n            if (objectIndex >= pagedObjects.size()) {\n                inventory.setItem(slot, ((PagedMenuTemplateButton<V, E>) pagedMenuButton.getTemplate()).getNullItem());\n                return;\n            } else {\n                pagedMenuButton.updateObject(pagedObjects.get(objectIndex));\n            }\n        }\n\n        ItemStack buttonItem;\n\n        try {\n            buttonItem = button.createViewItem();\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", slot);\n            Log.error(error, \"An unexpected error occurred while setting up menu:\");\n            return;\n        }\n\n        if (buttonItem == null)\n            return;\n\n        if (button instanceof PreviousPageButton) {\n            inventory.setItem(slot, new ItemBuilder(buttonItem)\n                    .replaceAll(\"{0}\", (currentPage == 1 ? \"&c\" : \"&a\"))\n                    .build(menuView.getInventoryViewer()));\n        } else if (button instanceof NextPageButton) {\n            inventory.setItem(slot, new ItemBuilder(buttonItem)\n                    .replaceAll(\"{0}\", (pagedObjects.size() > currentPage * this.objectsPerPageCount ? \"&a\" : \"&c\"))\n                    .build(menuView.getInventoryViewer()));\n        } else if (button instanceof CurrentPageButton) {\n            inventory.setItem(slot, new ItemBuilder(buttonItem)\n                    .replaceAll(\"{0}\", currentPage + \"\")\n                    .build(menuView.getInventoryViewer()));\n        } else {\n            inventory.setItem(slot, buttonItem);\n        }\n    }\n\n    private static int countPagedButtons(MenuTemplateButton<?>[] buttons) {\n        return (int) Arrays.stream(buttons).filter(button -> button instanceof PagedMenuTemplateButton).count();\n    }\n\n    public static <V extends PagedMenuView<V, ?, E>, E> Builder<V, E> newBuilder() {\n        return new Builder<>();\n    }\n\n    public static class Builder<V extends PagedMenuView<V, ?, E>, E>\n            extends AbstractBuilder<V>\n            implements PagedMenuLayout.Builder<V, E> {\n\n        @Nullable\n        private PagedLayoutOrder<V> layoutOrder;\n\n        @Override\n        public Builder<V, E> setPreviousPageSlots(List<Integer> slots) {\n            mapButtons(slots, new PreviousPageButton.Builder<>());\n            return this;\n        }\n\n        @Override\n        public Builder<V, E> setNextPageSlots(List<Integer> slots) {\n            mapButtons(slots, new NextPageButton.Builder<>());\n            return this;\n        }\n\n        @Override\n        public Builder<V, E> setCurrentPageSlots(List<Integer> slots) {\n            mapButtons(slots, new CurrentPageButton.Builder<>());\n            return this;\n        }\n\n        @Override\n        public Builder<V, E> setPagedObjectSlots(List<Integer> slots, PagedMenuTemplateButton.Builder<V, E> buttonBuilder) {\n            mapButtons(slots, buttonBuilder);\n            return this;\n        }\n\n        @Override\n        public PagedMenuLayout.Builder<V, E> setCustomLayoutOrder(List<Integer> slotsOrder) {\n            slotsOrder.removeIf(slot -> !(super.buttons[slot] instanceof PagedMenuTemplateButton));\n            if (!slotsOrder.isEmpty())\n                this.layoutOrder = new CustomPagedLayoutOrder<>(slotsOrder);\n            return this;\n        }\n\n        @Override\n        public PagedMenuLayoutImpl<V, E> build() {\n            return new PagedMenuLayoutImpl<>(super.title, super.inventoryType, super.buttons, this.layoutOrder);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/RegularMenuLayoutImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.layout;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton;\nimport com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\n\npublic class RegularMenuLayoutImpl<V extends MenuView<V, ?>> extends AbstractMenuLayout<V> implements MenuLayout<V> {\n\n    private RegularMenuLayoutImpl(String title, InventoryType inventoryType, MenuTemplateButton<V>[] buttons) {\n        super(title, inventoryType, buttons);\n    }\n\n    @Override\n    protected void populateInventory(Inventory inventory, V menuView) {\n        // Set all buttons in the menu\n        for (int slot = 0; slot < this.buttons.length; ++slot) {\n            MenuViewButton<V> button = this.buttons[slot].createViewButton(menuView);\n            ItemStack buttonItem = button.createViewItem();\n            if (buttonItem != null) {\n                inventory.setItem(slot, buttonItem);\n            }\n        }\n    }\n\n    public static <V extends MenuView<V, ?>> Builder<V> newBuilder() {\n        return new Builder<>();\n    }\n\n    public static class Builder<V extends MenuView<V, ?>> extends AbstractBuilder<V> implements MenuLayout.Builder<V> {\n\n        @Override\n        public RegularMenuLayoutImpl<V> build() {\n            return new RegularMenuLayoutImpl<>(super.title, super.inventoryType, super.buttons);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/order/CustomPagedLayoutOrder.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.layout.order;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CustomPagedLayoutOrder<T extends MenuView<T, ?>> implements PagedLayoutOrder<T> {\n\n    private final List<Integer> slotsOrder;\n\n    public CustomPagedLayoutOrder(List<Integer> slotsOrder) {\n        this.slotsOrder = new ArrayList<>(slotsOrder);\n    }\n\n    @Override\n    public int getObjectsPerPageCount() {\n        return this.slotsOrder.size();\n    }\n\n    @Override\n    public MenuButtonsIterator<T> createIterator(MenuTemplateButton<T>[] buttons) {\n        return new IteratorImpl(buttons);\n    }\n\n    private class IteratorImpl implements MenuButtonsIterator<T> {\n\n        private final MenuTemplateButton<T>[] buttons;\n        private int cursor = 0;\n        private int currentSlot;\n\n        private IteratorImpl(MenuTemplateButton<T>[] buttons) {\n            this.buttons = buttons;\n        }\n\n        @Override\n        public int getSlot() {\n            return this.currentSlot;\n        }\n\n        @Override\n        public boolean hasNext() {\n            if (this.cursor >= slotsOrder.size())\n                return false;\n\n            int slot = slotsOrder.get(this.cursor);\n            return slot >= 0 && slot < this.buttons.length;\n        }\n\n        @Override\n        public MenuTemplateButton<T> next() {\n            this.currentSlot = slotsOrder.get(this.cursor++);\n            return this.buttons[this.currentSlot];\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/order/PagedLayoutOrder.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.layout.order;\n\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\n\nimport java.util.Iterator;\n\npublic interface PagedLayoutOrder<T extends MenuView<T, ?>> {\n\n    int getObjectsPerPageCount();\n\n    MenuButtonsIterator<T> createIterator(MenuTemplateButton<T>[] buttons);\n\n    interface MenuButtonsIterator<T extends MenuView<T, ?>> extends Iterator<MenuTemplateButton<T>> {\n\n        int getSlot();\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\n\npublic class AbstractIconProviderMenu {\n\n    public static class Args<E> implements ViewArgs {\n\n        private final E iconProvider;\n        private final TemplateItem iconTemplate;\n\n        public Args(E iconProvider, TemplateItem iconTemplate) {\n            this.iconProvider = iconProvider;\n            this.iconTemplate = iconTemplate;\n        }\n\n    }\n\n    public abstract static class View<E> extends AbstractMenuView<View<E>, Args<E>> implements IIslandMenuView {\n\n        private final E iconProvider;\n        private final TemplateItem iconTemplate;\n\n        protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                       Menu<View<E>, Args<E>> menu, Args<E> args) {\n            super(inventoryViewer, previousMenuView, menu);\n            this.iconProvider = args.iconProvider;\n            this.iconTemplate = args.iconTemplate;\n        }\n\n        public E getIconProvider() {\n            return iconProvider;\n        }\n\n        public TemplateItem getIconTemplate() {\n            return iconTemplate;\n        }\n\n        @Override\n        public abstract Island getIsland();\n\n        @Override\n        public abstract String replaceTitle(String title);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.BaseMenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.AbstractMenu;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuBlank;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.Inventory;\n\nimport java.util.Arrays;\n\npublic abstract class AbstractMenuView<V extends MenuView<V, A>, A extends ViewArgs> extends BaseMenuView<V, A> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private Inventory inventory;\n\n    private boolean closeButton = false;\n    private boolean nextMove = false;\n    private boolean closed = false;\n    private boolean refreshing = false;\n\n    protected AbstractMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView, Menu<V, A> menu) {\n        super(inventoryViewer, menu, previousMenuView);\n    }\n\n    @Override\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    public void refreshView() {\n        if (refreshing)\n            return;\n\n        refreshing = true;\n        previousMove = false;\n\n        ((AbstractMenu) menu).refreshView(this).whenComplete((view, error) -> {\n            if (error != null) {\n                ((Throwable) error).printStackTrace();\n            } else {\n                refreshing = false;\n                previousMove = true;\n            }\n        });\n    }\n\n    @Override\n    public void closeView() {\n        inventoryViewer.runIfOnline(player -> {\n            previousMove = false;\n            player.closeInventory();\n        });\n    }\n\n    @Override\n    public Inventory getInventory() {\n        return this.inventory;\n    }\n\n    public void setInventory(Inventory inventory) {\n        if (closed || this.inventory != inventory) {\n            this.inventory = inventory;\n            this.openView();\n        }\n    }\n\n    public boolean isRefreshing() {\n        return refreshing;\n    }\n\n    public void setClickedCloseButton() {\n        closeButton = true;\n    }\n\n    public String replaceTitle(String title) {\n        return title;\n    }\n\n    private void openView() {\n        boolean success = openViewInternal();\n        if (!success) {\n            AbstractMenu menu = (AbstractMenu) getMenu();\n            menu.removeView(this);\n        }\n    }\n\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    private boolean openViewInternal() {\n        Player player = inventoryViewer.asPlayer();\n\n        if (player == null)\n            return false;\n\n        if (player.isSleeping()) {\n            Message.OPEN_MENU_WHILE_SLEEPING.send(inventoryViewer);\n            return false;\n        }\n\n        AbstractMenu menu = (AbstractMenu) getMenu();\n\n        if (!PluginEventsFactory.callPlayerOpenMenuEvent(inventoryViewer, this))\n            return false;\n\n        Log.debug(Debug.OPEN_MENU, inventoryViewer.getName());\n\n        if (inventory == null || menu.getLayout() == null) {\n            if (!(menu instanceof MenuBlank)) {\n                Menus.MENU_BLANK.createView(inventoryViewer, EmptyViewArgs.INSTANCE, previousMenuView);\n            }\n            return false;\n        }\n\n        MenuView<?, ?> currentOpenedView = inventoryViewer.getOpenedView();\n        if (currentOpenedView instanceof AbstractMenuView) {\n            ((AbstractMenuView<?, ?>) currentOpenedView).nextMove = true;\n        }\n\n        if (Arrays.equals(player.getOpenInventory().getTopInventory().getContents(), inventory.getContents()))\n            return false;\n\n        if (previousMenuView != null)\n            previousMenuView.setPreviousMove(false);\n\n        if (currentOpenedView != null && previousMenuView != currentOpenedView)\n            currentOpenedView.setPreviousMove(false);\n\n        player.openInventory(inventory);\n\n        if (closed) {\n            // If the view was closed before, we want to register it again.\n            closed = false;\n            menu.addView(this);\n        }\n\n        GameSoundImpl.playSound(player, menu.getOpeningSound());\n\n        this.previousMenuView = previousMenuView != null ? previousMenuView : previousMove ? currentOpenedView : null;\n\n        return true;\n    }\n\n    public void onClose() {\n        closed = true;\n\n        if (!nextMove && !closeButton && plugin.getSettings().isOnlyBackButton()) {\n            BukkitExecutor.sync(this::openView);\n        } else if (this.previousMenuView != null && this.menu.isPreviousMoveAllowed()) {\n            PluginEvent<PluginEventArgs.PlayerCloseMenu> event = PluginEventsFactory.callPlayerCloseMenuEvent(\n                    this.inventoryViewer, this, previousMove ? this.previousMenuView : null);\n\n            if (previousMove) {\n                if (!event.isCancelled()) {\n                    MenuView<?, ?> newMenu = event.getArgs().newMenuView;\n                    if (newMenu != null)\n                        BukkitExecutor.sync(newMenu::refreshView);\n\n                }\n            } else if (event.isCancelled()) {\n                BukkitExecutor.sync(this::openView);\n            } else {\n                previousMove = true;\n            }\n        }\n\n        closeButton = false;\n        nextMove = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractPagedMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic abstract class AbstractPagedMenuView<V extends MenuView<V, A>, A extends ViewArgs, E>\n        extends AbstractMenuView<V, A> implements PagedMenuView<V, A, E> {\n\n    private List<E> objects;\n    private int currentPage = 1;\n\n    public AbstractPagedMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView, Menu<V, A> menu) {\n        super(inventoryViewer, previousMenuView, menu);\n    }\n\n    @Override\n    public void setCurrentPage(int currentPage) {\n        Preconditions.checkArgument(currentPage >= 1, \"invalid page \" + currentPage);\n\n        if (this.currentPage == currentPage)\n            return;\n\n        this.currentPage = currentPage;\n\n        setPreviousMove(false);\n        refreshView();\n    }\n\n    @Override\n    public int getCurrentPage() {\n        return currentPage;\n    }\n\n    @Override\n    public List<E> getPagedObjects() {\n        if (this.objects == null)\n            updatePagedObjects();\n\n        return Collections.unmodifiableList(this.objects);\n    }\n\n    @Override\n    public void updatePagedObjects() {\n        this.objects = requestObjects();\n    }\n\n    @Override\n    public void refreshView() {\n        updatePagedObjects();\n        super.refreshView();\n    }\n\n    protected abstract List<E> requestObjects();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/BaseMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\n\npublic class BaseMenuView extends AbstractMenuView<BaseMenuView, EmptyViewArgs> {\n\n    public BaseMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                        Menu<BaseMenuView, EmptyViewArgs> menu) {\n        super(inventoryViewer, previousMenuView, menu);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\npublic interface IIslandMenuView {\n\n    Island getIsland();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic interface IPlayerMenuView {\n\n    @Nullable\n    SuperiorPlayer getSuperiorPlayer();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/MenuViewWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport org.bukkit.inventory.Inventory;\n\npublic class MenuViewWrapper implements ISuperiorMenu {\n\n    private final MenuView<?, ?> menuView;\n\n    @SuppressWarnings(\"deprecation\")\n    public static ISuperiorMenu fromView(@Nullable MenuView<?, ?> menuView) {\n        return menuView == null || menuView instanceof ISuperiorMenu ? (ISuperiorMenu) menuView : new MenuViewWrapper(menuView);\n    }\n\n    private MenuViewWrapper(MenuView<?, ?> menuView) {\n        this.menuView = menuView;\n    }\n\n    @Override\n    public void cloneAndOpen(@Nullable ISuperiorMenu previousMenu) {\n        this.menuView.setPreviousMenuView(previousMenu, false);\n        this.menuView.refreshView();\n    }\n\n    @Nullable\n    @Override\n    public ISuperiorMenu getPreviousMenu() {\n        return new MenuViewWrapper(menuView.getPreviousMenuView());\n    }\n\n    @Override\n    public SuperiorPlayer getInventoryViewer() {\n        return menuView.getInventoryViewer();\n    }\n\n    @Nullable\n    @Override\n    public MenuView<?, ?> getPreviousMenuView() {\n        return menuView.getPreviousMenuView();\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    @Override\n    public void setPreviousMenuView(@Nullable MenuView previousMenuView, boolean keepOlderViews) {\n        menuView.setPreviousMenuView(previousMenuView, keepOlderViews);\n    }\n\n    @Override\n    public Menu<?, ?> getMenu() {\n        return menuView.getMenu();\n    }\n\n    @Override\n    public void setPreviousMove(boolean previousMove) {\n        menuView.setPreviousMove(previousMove);\n    }\n\n    @Override\n    public boolean isPreviousMenu() {\n        return menuView.isPreviousMenu();\n    }\n\n    @Override\n    public Inventory getInventory() {\n        return menuView.getInventory();\n    }\n\n    @Override\n    public void refreshView() {\n        this.menuView.refreshView();\n    }\n\n    @Override\n    public void closeView() {\n        this.menuView.closeView();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/EmptyViewArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view.args;\n\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\n\npublic class EmptyViewArgs implements ViewArgs {\n\n    public static final EmptyViewArgs INSTANCE = new EmptyViewArgs();\n\n    private EmptyViewArgs() {\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/IslandViewArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view.args;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\n\npublic class IslandViewArgs implements ViewArgs {\n\n    private final Island island;\n\n    public IslandViewArgs(Island island) {\n        this.island = island;\n    }\n\n    public Island getIsland() {\n        return island;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/PlayerViewArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view.args;\n\nimport com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\npublic class PlayerViewArgs implements ViewArgs {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    public PlayerViewArgs(SuperiorPlayer superiorPlayer) {\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    public SuperiorPlayer getSuperiorPlayer() {\n        return superiorPlayer;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/IslandMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\n\npublic class IslandMenuView extends AbstractMenuView<IslandMenuView, IslandViewArgs> implements IIslandMenuView {\n\n    private final Island island;\n\n    public IslandMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                          Menu<IslandMenuView, IslandViewArgs> menu, IslandViewArgs args) {\n        super(inventoryViewer, previousMenuView, menu);\n        this.island = args.getIsland();\n    }\n\n    @Override\n    public Island getIsland() {\n        return island;\n    }\n\n    @Override\n    public String replaceTitle(String title) {\n        return title.replace(\"{}\", this.island.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/PlayerMenuView.java",
    "content": "package com.bgsoftware.superiorskyblock.core.menu.view.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.menu.Menu;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs;\n\npublic class PlayerMenuView extends AbstractMenuView<PlayerMenuView, PlayerViewArgs> implements IPlayerMenuView {\n\n    private final SuperiorPlayer superiorPlayer;\n\n    public PlayerMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView<?, ?> previousMenuView,\n                          Menu<PlayerMenuView, PlayerViewArgs> menu, PlayerViewArgs args) {\n        super(inventoryViewer, previousMenuView, menu);\n        this.superiorPlayer = args.getSuperiorPlayer();\n    }\n\n    @Override\n    public SuperiorPlayer getSuperiorPlayer() {\n        return this.superiorPlayer;\n    }\n\n    @Override\n    public String replaceTitle(String title) {\n        return title.replace(\"{}\", this.superiorPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.service.message.MessagesService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl;\nimport net.md_5.bungee.api.chat.BaseComponent;\nimport net.md_5.bungee.api.chat.ClickEvent;\nimport net.md_5.bungee.api.chat.HoverEvent;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.Collection;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\npublic enum Message {\n\n    ADMIN_ADD_PLAYER,\n    ADMIN_ADD_PLAYER_NAME,\n    ADMIN_DEPOSIT_MONEY,\n    ADMIN_DEPOSIT_MONEY_NAME,\n    ADMIN_HELP_FOOTER,\n    ADMIN_HELP_HEADER,\n    ADMIN_HELP_LINE,\n    ADMIN_HELP_NEXT_PAGE,\n    ALREADY_IN_ISLAND,\n    ALREADY_IN_ISLAND_OTHER,\n    BANK_DEPOSIT_COMPLETED,\n    BANK_DEPOSIT_CUSTOM,\n    BANK_LIMIT_EXCEED,\n    BANK_WITHDRAW_COMPLETED,\n    BANK_WITHDRAW_CUSTOM,\n    BANNED_FROM_ISLAND,\n    BAN_ANNOUNCEMENT,\n    BAN_PLAYERS_WITH_LOWER_ROLE,\n    BLOCK_COUNTS_CHECK,\n    BLOCK_COUNTS_CHECK_EMPTY,\n    BLOCK_COUNTS_CHECK_MATERIAL,\n    BLOCK_COUNT_CHECK,\n    BLOCK_LEVEL,\n    BLOCK_LEVEL_WORTHLESS,\n    BLOCK_VALUE,\n    BLOCK_VALUE_WORTHLESS,\n    BONUS_SYNC_ALL,\n    BONUS_SYNC_NAME,\n    BONUS_SYNC,\n    BORDER_PLAYER_COLOR_NAME_BLUE,\n    BORDER_PLAYER_COLOR_NAME_GREEN,\n    BORDER_PLAYER_COLOR_NAME_RED,\n    BORDER_PLAYER_COLOR_UPDATED,\n    BUILD_OUTSIDE_ISLAND,\n    CANNOT_SET_ROLE,\n    CHANGED_BANK_LIMIT,\n    CHANGED_BANK_LIMIT_ALL,\n    CHANGED_BANK_LIMIT_NAME,\n    CHANGED_BIOME,\n    CHANGED_BIOME_ALL,\n    CHANGED_BIOME_NAME,\n    CHANGED_BIOME_OTHER,\n    CHANGED_BLOCK_AMOUNT,\n    CHANGED_BLOCK_LIMIT,\n    CHANGED_BLOCK_LIMIT_ALL,\n    CHANGED_BLOCK_LIMIT_NAME,\n    CHANGED_BONUS_LEVEL,\n    CHANGED_BONUS_LEVEL_ALL,\n    CHANGED_BONUS_LEVEL_NAME,\n    CHANGED_BONUS_WORTH,\n    CHANGED_BONUS_WORTH_ALL,\n    CHANGED_BONUS_WORTH_NAME,\n    CHANGED_CHEST_SIZE,\n    CHANGED_CHEST_SIZE_ALL,\n    CHANGED_CHEST_SIZE_NAME,\n    CHANGED_COOP_LIMIT,\n    CHANGED_COOP_LIMIT_ALL,\n    CHANGED_COOP_LIMIT_NAME,\n    CHANGED_CROP_GROWTH,\n    CHANGED_CROP_GROWTH_ALL,\n    CHANGED_CROP_GROWTH_NAME,\n    CHANGED_DISCORD,\n    CHANGED_ENTITY_LIMIT,\n    CHANGED_ENTITY_LIMIT_ALL,\n    CHANGED_ENTITY_LIMIT_NAME,\n    CHANGED_ISLAND_EFFECT_LEVEL,\n    CHANGED_ISLAND_EFFECT_LEVEL_ALL,\n    CHANGED_ISLAND_EFFECT_LEVEL_NAME,\n    CHANGED_ISLAND_SIZE,\n    CHANGED_ISLAND_SIZE_ALL,\n    CHANGED_ISLAND_SIZE_BUILD_OUTSIDE,\n    CHANGED_ISLAND_SIZE_NAME,\n    CHANGED_LANGUAGE,\n    CHANGED_MOB_DROPS,\n    CHANGED_MOB_DROPS_ALL,\n    CHANGED_MOB_DROPS_NAME,\n    CHANGED_NAME,\n    CHANGED_NAME_OTHER,\n    CHANGED_NAME_OTHER_NAME,\n    CHANGED_PAYPAL,\n    CHANGED_ROLE_LIMIT,\n    CHANGED_ROLE_LIMIT_ALL,\n    CHANGED_ROLE_LIMIT_NAME,\n    CHANGED_SPAWNER_RATES,\n    CHANGED_SPAWNER_RATES_ALL,\n    CHANGED_SPAWNER_RATES_NAME,\n    CHANGED_TEAM_LIMIT,\n    CHANGED_TEAM_LIMIT_ALL,\n    CHANGED_TEAM_LIMIT_NAME,\n    CHANGED_TELEPORT_LOCATION,\n    CHANGED_WARPS_LIMIT,\n    CHANGED_WARPS_LIMIT_ALL,\n    CHANGED_WARPS_LIMIT_NAME,\n    CHANGE_PERMISSION_FOR_HIGHER_ROLE,\n    COMMAND_ARGUMENT_ALL_ISLANDS(\"*\"),\n    COMMAND_ARGUMENT_ALL_MATERIALS(\"*\"),\n    COMMAND_ARGUMENT_ALL_MISSIONS(\"*\"),\n    COMMAND_ARGUMENT_ALL_PLAYERS(\"*\"),\n    COMMAND_ARGUMENT_AMOUNT(\"amount\"),\n    COMMAND_ARGUMENT_BIOME(\"biome\"),\n    COMMAND_ARGUMENT_BORDER_COLOR(\"border-color\"),\n    COMMAND_ARGUMENT_COMMAND(\"command...\"),\n    COMMAND_ARGUMENT_DIMENSION(\"dimension\"),\n    COMMAND_ARGUMENT_DISCORD(\"discord...\"),\n    COMMAND_ARGUMENT_EFFECT(\"effect\"),\n    COMMAND_ARGUMENT_EMAIL(\"email\"),\n    COMMAND_ARGUMENT_ENTITY(\"entity\"),\n    COMMAND_ARGUMENT_ISLAND_NAME(\"island-name\"),\n    COMMAND_ARGUMENT_ISLAND_ROLE(\"island-role\"),\n    COMMAND_ARGUMENT_LEADER(\"leader\"),\n    COMMAND_ARGUMENT_LEVEL(\"level\"),\n    COMMAND_ARGUMENT_LIMIT(\"limit\"),\n    COMMAND_ARGUMENT_MATERIAL(\"material\"),\n    COMMAND_ARGUMENT_MENU(\"menu-name\"),\n    COMMAND_ARGUMENT_MESSAGE(\"message...\"),\n    COMMAND_ARGUMENT_MISSION_CATEGORY(\"mission-category\"),\n    COMMAND_ARGUMENT_MISSION_NAME(\"mission-name\"),\n    COMMAND_ARGUMENT_MODULE_NAME(\"module-name\"),\n    COMMAND_ARGUMENT_MULTIPLIER(\"multiplier\"),\n    COMMAND_ARGUMENT_NEW_LEADER(\"new-leader\"),\n    COMMAND_ARGUMENT_PAGE(\"page\"),\n    COMMAND_ARGUMENT_PATH(\"path\"),\n    COMMAND_ARGUMENT_PERMISSION(\"permission\"),\n    COMMAND_ARGUMENT_PLAYER_NAME(\"player-name\"),\n    COMMAND_ARGUMENT_PRIVATE(\"private\"),\n    COMMAND_ARGUMENT_RATING(\"rating\"),\n    COMMAND_ARGUMENT_ROWS(\"rows\"),\n    COMMAND_ARGUMENT_SCHEMATIC_NAME(\"schematic-name\"),\n    COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR(\"save-air\"),\n    COMMAND_ARGUMENT_SETTINGS(\"settings\"),\n    COMMAND_ARGUMENT_SIZE(\"size\"),\n    COMMAND_ARGUMENT_TIME(\"time\"),\n    COMMAND_ARGUMENT_TITLE_DURATION(\"duration\"),\n    COMMAND_ARGUMENT_TITLE_FADE_IN(\"fade-in\"),\n    COMMAND_ARGUMENT_TITLE_FADE_OUT(\"fade-out\"),\n    COMMAND_ARGUMENT_UPGRADE_NAME(\"upgrade-name\"),\n    COMMAND_ARGUMENT_VALUE(\"value\"),\n    COMMAND_ARGUMENT_WARP_CATEGORY(\"warp-category\"),\n    COMMAND_ARGUMENT_WARP_NAME(\"warp-name\"),\n    COMMAND_ARGUMENT_WORLD(\"world\"),\n    COMMAND_COOLDOWN_FORMAT,\n    COMMAND_DESCRIPTION_ACCEPT,\n    COMMAND_DESCRIPTION_ADMIN,\n    COMMAND_DESCRIPTION_ADMIN_ADD,\n    COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_BONUS,\n    COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH,\n    COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR,\n    COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS,\n    COMMAND_DESCRIPTION_ADMIN_ADD_SIZE,\n    COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES,\n    COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_BONUS,\n    COMMAND_DESCRIPTION_ADMIN_BYPASS,\n    COMMAND_DESCRIPTION_ADMIN_CHEST,\n    COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR,\n    COMMAND_DESCRIPTION_ADMIN_CLOSE,\n    COMMAND_DESCRIPTION_ADMIN_CMD_ALL,\n    COMMAND_DESCRIPTION_ADMIN_COUNT,\n    COMMAND_DESCRIPTION_ADMIN_DATA,\n    COMMAND_DESCRIPTION_ADMIN_DEBUG,\n    COMMAND_DESCRIPTION_ADMIN_DEL_WARP,\n    COMMAND_DESCRIPTION_ADMIN_DEMOTE,\n    COMMAND_DESCRIPTION_ADMIN_DEPOSIT,\n    COMMAND_DESCRIPTION_ADMIN_DISBAND,\n    COMMAND_DESCRIPTION_ADMIN_FLY,\n    COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS,\n    COMMAND_DESCRIPTION_ADMIN_IGNORE,\n    COMMAND_DESCRIPTION_ADMIN_JOIN,\n    COMMAND_DESCRIPTION_ADMIN_KICK,\n    COMMAND_DESCRIPTION_ADMIN_MISSION,\n    COMMAND_DESCRIPTION_ADMIN_MODULES,\n    COMMAND_DESCRIPTION_ADMIN_MSG,\n    COMMAND_DESCRIPTION_ADMIN_MSG_ALL,\n    COMMAND_DESCRIPTION_ADMIN_NAME,\n    COMMAND_DESCRIPTION_ADMIN_OPEN,\n    COMMAND_DESCRIPTION_ADMIN_OPEN_MENU,\n    COMMAND_DESCRIPTION_ADMIN_PROMOTE,\n    COMMAND_DESCRIPTION_ADMIN_PURGE,\n    COMMAND_DESCRIPTION_ADMIN_RANKUP,\n    COMMAND_DESCRIPTION_ADMIN_RECALC,\n    COMMAND_DESCRIPTION_ADMIN_RELOAD,\n    COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS,\n    COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS,\n    COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS,\n    COMMAND_DESCRIPTION_ADMIN_RESET_WORLD,\n    COMMAND_DESCRIPTION_ADMIN_SCHEMATIC,\n    COMMAND_DESCRIPTION_ADMIN_SETTINGS,\n    COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_BIOME,\n    COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT,\n    COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW,\n    COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH,\n    COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS,\n    COMMAND_DESCRIPTION_ADMIN_SET_EFFECT,\n    COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR,\n    COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW,\n    COMMAND_DESCRIPTION_ADMIN_SET_LEADER,\n    COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS,\n    COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION,\n    COMMAND_DESCRIPTION_ADMIN_SET_RATE,\n    COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS,\n    COMMAND_DESCRIPTION_ADMIN_SET_SIZE,\n    COMMAND_DESCRIPTION_ADMIN_SET_SPAWN,\n    COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES,\n    COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE,\n    COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT,\n    COMMAND_DESCRIPTION_ADMIN_SHOW,\n    COMMAND_DESCRIPTION_ADMIN_SPAWN,\n    COMMAND_DESCRIPTION_ADMIN_SPY,\n    COMMAND_DESCRIPTION_ADMIN_STATS,\n    COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS,\n    COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES,\n    COMMAND_DESCRIPTION_ADMIN_TELEPORT,\n    COMMAND_DESCRIPTION_ADMIN_TITLE,\n    COMMAND_DESCRIPTION_ADMIN_TITLE_ALL,\n    COMMAND_DESCRIPTION_ADMIN_UNIGNORE,\n    COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD,\n    COMMAND_DESCRIPTION_ADMIN_WITHDRAW,\n    COMMAND_DESCRIPTION_BALANCE,\n    COMMAND_DESCRIPTION_BAN,\n    COMMAND_DESCRIPTION_BANK,\n    COMMAND_DESCRIPTION_BANS,\n    COMMAND_DESCRIPTION_BIOME,\n    COMMAND_DESCRIPTION_BORDER,\n    COMMAND_DESCRIPTION_CHEST,\n    COMMAND_DESCRIPTION_CLOSE,\n    COMMAND_DESCRIPTION_COOP,\n    COMMAND_DESCRIPTION_COOPS,\n    COMMAND_DESCRIPTION_COUNTS,\n    COMMAND_DESCRIPTION_CREATE,\n    COMMAND_DESCRIPTION_DEL_WARP,\n    COMMAND_DESCRIPTION_DEMOTE,\n    COMMAND_DESCRIPTION_DEPOSIT,\n    COMMAND_DESCRIPTION_DISBAND,\n    COMMAND_DESCRIPTION_EXPEL,\n    COMMAND_DESCRIPTION_FLY,\n    COMMAND_DESCRIPTION_HELP,\n    COMMAND_DESCRIPTION_INVITE,\n    COMMAND_DESCRIPTION_KICK,\n    COMMAND_DESCRIPTION_LANG,\n    COMMAND_DESCRIPTION_LEAVE,\n    COMMAND_DESCRIPTION_MEMBERS,\n    COMMAND_DESCRIPTION_MISSION,\n    COMMAND_DESCRIPTION_MISSIONS,\n    COMMAND_DESCRIPTION_NAME,\n    COMMAND_DESCRIPTION_OPEN,\n    COMMAND_DESCRIPTION_PANEL,\n    COMMAND_DESCRIPTION_PARDON,\n    COMMAND_DESCRIPTION_PERMISSIONS,\n    COMMAND_DESCRIPTION_PROMOTE,\n    COMMAND_DESCRIPTION_RANKUP,\n    COMMAND_DESCRIPTION_RATE,\n    COMMAND_DESCRIPTION_RATINGS,\n    COMMAND_DESCRIPTION_RECALC,\n    COMMAND_DESCRIPTION_SETTINGS,\n    COMMAND_DESCRIPTION_SET_DISCORD,\n    COMMAND_DESCRIPTION_SET_PAYPAL,\n    COMMAND_DESCRIPTION_SET_ROLE,\n    COMMAND_DESCRIPTION_SET_TELEPORT,\n    COMMAND_DESCRIPTION_SET_WARP,\n    COMMAND_DESCRIPTION_SHOW,\n    COMMAND_DESCRIPTION_TEAM,\n    COMMAND_DESCRIPTION_TEAM_CHAT,\n    COMMAND_DESCRIPTION_TELEPORT,\n    COMMAND_DESCRIPTION_TOGGLE,\n    COMMAND_DESCRIPTION_TOP,\n    COMMAND_DESCRIPTION_TRANSFER,\n    COMMAND_DESCRIPTION_UNCOOP,\n    COMMAND_DESCRIPTION_UPGRADE,\n    COMMAND_DESCRIPTION_VALUE,\n    COMMAND_DESCRIPTION_VALUES,\n    COMMAND_DESCRIPTION_VISIT,\n    COMMAND_DESCRIPTION_VISITORS,\n    COMMAND_DESCRIPTION_WARP,\n    COMMAND_DESCRIPTION_WARPS,\n    COMMAND_DESCRIPTION_WITHDRAW,\n    COMMAND_USAGE,\n    COOP_ANNOUNCEMENT,\n    COOP_BANNED_PLAYER,\n    COOP_LIMIT_EXCEED,\n    CREATE_ISLAND,\n    CREATE_ISLAND_FAILURE,\n    CREATE_WORLD_FAILURE,\n    DEBUG_MODE_DISABLED,\n    DEBUG_MODE_ENABLED,\n    DEBUG_MODE_FILTER_ADD,\n    DEBUG_MODE_FILTER_CLEAR,\n    DEBUG_MODE_FILTER_REMOVE,\n    DELETE_WARP,\n    DELETE_WARP_SIGN_BROKE,\n    DEMOTED_MEMBER,\n    DEMOTE_LEADER,\n    DEMOTE_PLAYERS_WITH_LOWER_ROLE,\n    DEPOSIT_ANNOUNCEMENT,\n    DEPOSIT_ERROR,\n    DESTROY_OUTSIDE_ISLAND,\n    DISBANDED_ISLAND,\n    DISBANDED_ISLAND_OTHER,\n    DISBANDED_ISLAND_OTHER_NAME,\n    DISBAND_ANNOUNCEMENT,\n    DISBAND_GIVE,\n    DISBAND_GIVE_ALL,\n    DISBAND_GIVE_OTHER,\n    DISBAND_ISLAND_BALANCE_REFUND,\n    DISBAND_SET,\n    DISBAND_SET_ALL,\n    DISBAND_SET_OTHER,\n    ENTER_PVP_ISLAND,\n    EXPELLED_PLAYER,\n    FORMAT_BILLION,\n    FORMAT_DAYS_NAME,\n    FORMAT_DAY_NAME,\n    FORMAT_HOURS_NAME,\n    FORMAT_HOUR_NAME,\n    FORMAT_MILLION,\n    FORMAT_MINUTES_NAME,\n    FORMAT_MINUTE_NAME,\n    FORMAT_QUAD,\n    FORMAT_SECONDS_NAME,\n    FORMAT_SECOND_NAME,\n    FORMAT_THOUSANDS,\n    FORMAT_TRILLION,\n    GENERATOR_CLEARED,\n    GENERATOR_CLEARED_ALL,\n    GENERATOR_CLEARED_NAME,\n    GENERATOR_UPDATED,\n    GENERATOR_UPDATED_ALL,\n    GENERATOR_UPDATED_NAME,\n    GLOBAL_COMMAND_EXECUTED,\n    GLOBAL_COMMAND_EXECUTED_NAME,\n    GLOBAL_MESSAGE_SENT,\n    GLOBAL_MESSAGE_SENT_NAME,\n    GLOBAL_TITLE_SENT,\n    GLOBAL_TITLE_SENT_NAME,\n    GOT_BANNED,\n    GOT_DEMOTED,\n    GOT_EXPELLED,\n    GOT_INVITE {\n        @Override\n        public void send(CommandSender sender, Locale locale, Object... args) {\n            if (!(sender instanceof Player)) {\n                super.send(sender, locale, args);\n            } else {\n                String message = getMessage(locale);\n\n                if (message == null)\n                    return;\n\n                BaseComponent[] baseComponents = TextComponent.fromLegacyText(message);\n                if (!GOT_INVITE_TOOLTIP.isEmpty(locale)) {\n                    for (BaseComponent baseComponent : baseComponents)\n                        baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{new TextComponent(GOT_INVITE_TOOLTIP.getMessage(locale))}));\n                }\n\n                for (BaseComponent baseComponent : baseComponents)\n                    baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, \"/\" + plugin.getCommands().getLabel() + \" accept \" + args[0]));\n\n                IMessageComponent messageComponent = ComplexMessageComponent.of(baseComponents);\n                if (messageComponent != null) {\n                    PluginEvent<PluginEventArgs.SendMessage> event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args);\n                    if (!event.isCancelled())\n                        event.getArgs().messageComponent.sendMessage(sender, args);\n                }\n            }\n        }\n    },\n    GOT_INVITE_TOOLTIP,\n    GOT_KICKED,\n    GOT_PROMOTED,\n    GOT_REVOKED,\n    GOT_UNBANNED,\n    HIT_ISLAND_MEMBER,\n    HIT_PLAYER_IN_ISLAND,\n    IGNORED_ISLAND,\n    IGNORED_ISLAND_NAME,\n    INTERACT_OUTSIDE_ISLAND,\n    INVALID_AMOUNT,\n    INVALID_BIOME,\n    INVALID_BLOCK,\n    INVALID_BORDER_COLOR,\n    INVALID_COMMAND,\n    INVALID_EFFECT,\n    INVALID_ENTITY,\n    INVALID_ENVIRONMENT,\n    INVALID_INTERVAL,\n    INVALID_ISLAND,\n    INVALID_ISLAND_LOCATION,\n    INVALID_ISLAND_OTHER,\n    INVALID_ISLAND_OTHER_NAME,\n    INVALID_ISLAND_PERMISSION,\n    INVALID_LEVEL,\n    INVALID_LIMIT,\n    INVALID_MATERIAL,\n    INVALID_MATERIAL_DATA,\n    INVALID_MENU,\n    INVALID_MISSION,\n    INVALID_MISSION_CATEGORY,\n    INVALID_MODULE,\n    INVALID_MULTIPLIER,\n    INVALID_PAGE,\n    INVALID_PERCENTAGE,\n    INVALID_PLAYER,\n    INVALID_RATE,\n    INVALID_ROLE,\n    INVALID_ROWS,\n    INVALID_SCHEMATIC,\n    INVALID_SETTINGS,\n    INVALID_SIZE,\n    INVALID_SLOT,\n    INVALID_TITLE,\n    INVALID_TOGGLE_MODE,\n    INVALID_UPGRADE,\n    INVALID_VISIT_LOCATION,\n    INVALID_VISIT_LOCATION_BYPASS,\n    INVALID_WARP,\n    INVALID_WORLD,\n    INVITE_ANNOUNCEMENT,\n    INVITE_BANNED_PLAYER,\n    INVITE_TO_FULL_ISLAND,\n    ISLAND_ALREADY_CLOSED,\n    ISLAND_ALREADY_EXIST,\n    ISLAND_ALREADY_OPENED,\n    ISLAND_BANK_EMPTY,\n    ISLAND_BANK_SHOW,\n    ISLAND_BANK_SHOW_OTHER,\n    ISLAND_BANK_SHOW_OTHER_NAME,\n    ISLAND_BEING_CALCULATED,\n    ISLAND_CLOSED,\n    ISLAND_CREATE_PROCCESS_REQUEST,\n    ISLAND_CREATE_PROCESS_FAIL,\n    ISLAND_DESCRIPTION_NONE,\n    ISLAND_FLY_DISABLED,\n    ISLAND_FLY_ENABLED,\n    ISLAND_GOT_DELETED_WHILE_INSIDE,\n    ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE,\n    ISLAND_HELP_FOOTER,\n    ISLAND_HELP_HEADER,\n    ISLAND_HELP_LINE,\n    ISLAND_HELP_NEXT_PAGE,\n    ISLAND_INFO_ADMIN_BANK_LIMIT,\n    ISLAND_INFO_ADMIN_BLOCKS_LIMITS,\n    ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE,\n    ISLAND_INFO_ADMIN_COOP_LIMIT,\n    ISLAND_INFO_ADMIN_CROPS_MULTIPLIER,\n    ISLAND_INFO_ADMIN_DROPS_MULTIPLIER,\n    ISLAND_INFO_ADMIN_ENTITIES_LIMITS,\n    ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE,\n    ISLAND_INFO_ADMIN_GENERATOR_RATES,\n    ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE,\n    ISLAND_INFO_ADMIN_ISLAND_EFFECTS,\n    ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE,\n    ISLAND_INFO_ADMIN_ROLE_LIMITS,\n    ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE,\n    ISLAND_INFO_ADMIN_SIZE,\n    ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER,\n    ISLAND_INFO_ADMIN_TEAM_LIMIT,\n    ISLAND_INFO_ADMIN_UPGRADES,\n    ISLAND_INFO_ADMIN_UPGRADE_LINE,\n    ISLAND_INFO_ADMIN_VALUE_SYNCED,\n    ISLAND_INFO_ADMIN_WARPS_LIMIT,\n    ISLAND_INFO_BANK,\n    ISLAND_INFO_BONUS,\n    ISLAND_INFO_BONUS_LEVEL,\n    ISLAND_INFO_CREATION_TIME,\n    ISLAND_INFO_DISCORD,\n    ISLAND_INFO_FOOTER,\n    ISLAND_INFO_HEADER,\n    ISLAND_INFO_LAST_TIME_UPDATED,\n    ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE,\n    ISLAND_INFO_LEVEL,\n    ISLAND_INFO_LOCATION,\n    ISLAND_INFO_NAME,\n    ISLAND_INFO_OWNER,\n    ISLAND_INFO_PAYPAL,\n    ISLAND_INFO_PLAYER_LINE,\n    ISLAND_INFO_RATE,\n    ISLAND_INFO_RATE_EMPTY_SYMBOL,\n    ISLAND_INFO_RATE_FIVE_COLOR,\n    ISLAND_INFO_RATE_FOUR_COLOR,\n    ISLAND_INFO_RATE_ONE_COLOR,\n    ISLAND_INFO_RATE_SYMBOL,\n    ISLAND_INFO_RATE_THREE_COLOR,\n    ISLAND_INFO_RATE_TWO_COLOR,\n    ISLAND_INFO_ROLES,\n    ISLAND_INFO_VISITORS_COUNT,\n    ISLAND_INFO_WORTH,\n    ISLAND_NAME_NONE,\n    ISLAND_OPENED,\n    ISLAND_OWNER_NONE,\n    ISLAND_PREVIEW_BLOCK_COMMAND,\n    ISLAND_PREVIEW_CANCEL,\n    ISLAND_PREVIEW_CANCEL_DISTANCE,\n    ISLAND_PREVIEW_CANCEL_TEXT,\n    ISLAND_PREVIEW_CONFIRM_TEXT,\n    ISLAND_PREVIEW_SET,\n    ISLAND_PREVIEW_START,\n    ISLAND_PROTECTED,\n    ISLAND_PROTECTED_OPPED,\n    ISLAND_TEAM_STATUS_FOOTER,\n    ISLAND_TEAM_STATUS_HEADER,\n    ISLAND_TEAM_STATUS_OFFLINE,\n    ISLAND_TEAM_STATUS_ONLINE,\n    ISLAND_TEAM_STATUS_ROLES,\n    ISLAND_TOP_STATUS_OFFLINE,\n    ISLAND_TOP_STATUS_ONLINE,\n    ISLAND_WARP_PRIVATE,\n    ISLAND_WARP_PUBLIC,\n    ISLAND_WAS_CLOSED,\n    ISLAND_WORTH_ERROR,\n    ISLAND_WORTH_RESULT,\n    ISLAND_WORTH_TIME_OUT,\n    JOINED_ISLAND,\n    JOINED_ISLAND_AS_COOP,\n    JOINED_ISLAND_AS_COOP_NAME,\n    JOINED_ISLAND_NAME,\n    JOIN_ADMIN_ANNOUNCEMENT,\n    JOIN_ANNOUNCEMENT,\n    JOIN_FULL_ISLAND,\n    JOIN_WHILE_IN_ISLAND,\n    KICK_ANNOUNCEMENT,\n    KICK_ISLAND_LEADER,\n    KICK_PLAYERS_WITH_LOWER_ROLE,\n    LACK_CHANGE_PERMISSION,\n    LAST_ROLE_DEMOTE,\n    LAST_ROLE_PROMOTE,\n    LEAVE_ANNOUNCEMENT,\n    LEAVE_ISLAND_AS_LEADER,\n    LEFT_ISLAND,\n    LEFT_ISLAND_COOP,\n    LEFT_ISLAND_COOP_NAME,\n    LOCK_WORLD_ANNOUNCEMENT_ALL,\n    LOCK_WORLD_ANNOUNCEMENT_NAME,\n    LOCK_WORLD_ANNOUNCEMENT,\n    MATERIAL_NOT_SOLID,\n    MAXIMUM_LEVEL,\n    MESSAGE_SENT,\n    MISSION_CANNOT_COMPLETE,\n    MISSION_NOT_COMPLETE_REQUIRED_MISSIONS,\n    MISSION_NO_AUTO_REWARD,\n    MISSION_STATUS_COMPLETE,\n    MISSION_STATUS_COMPLETE_ALL,\n    MISSION_STATUS_RESET,\n    MISSION_STATUS_RESET_ALL,\n    MODULES_LIST,\n    MODULES_LIST_MODULE_NAME,\n    MODULES_LIST_SEPARATOR,\n    MODULE_ALREADY_INITIALIZED,\n    MODULE_INFO,\n    MODULE_LOADED_FAILURE,\n    MODULE_LOADED_SUCCESS,\n    MODULE_UNLOADED_SUCCESS,\n    NAME_ANNOUNCEMENT,\n    NAME_ANNOUNCEMENT_OTHER,\n    NAME_ANNOUNCEMENT_OTHER_NAME,\n    NAME_BLACKLISTED,\n    NAME_CHAT_FORMAT,\n    NAME_SAME_AS_PLAYER,\n    NAME_TOO_LONG,\n    NAME_TOO_SHORT,\n    NOT_ENOUGH_MONEY_TO_DEPOSIT,\n    NOT_ENOUGH_MONEY_TO_UPGRADE,\n    NOT_ENOUGH_MONEY_TO_WARP,\n    NO_BAN_PERMISSION,\n    NO_CLOSE_BYPASS,\n    NO_CLOSE_PERMISSION,\n    NO_COMMAND_PERMISSION,\n    NO_COOP_PERMISSION,\n    NO_DELETE_WARP_PERMISSION,\n    NO_DEMOTE_PERMISSION,\n    NO_DEPOSIT_PERMISSION,\n    NO_DISBAND_PERMISSION,\n    NO_EXPEL_PERMISSION,\n    NO_INVITE_PERMISSION,\n    NO_ISLANDS_TO_PURGE,\n    NO_ISLAND_CHEST_PERMISSION,\n    NO_ISLAND_INVITE,\n    NO_KICK_PERMISSION,\n    NO_MORE_DISBANDS,\n    NO_MORE_WARPS,\n    NO_NAME_PERMISSION,\n    NO_OPEN_PERMISSION,\n    NO_PERMISSION_CHECK_PERMISSION,\n    NO_PROMOTE_PERMISSION,\n    NO_RANKUP_PERMISSION,\n    NO_RATINGS_PERMISSION,\n    NO_SET_BIOME_PERMISSION,\n    NO_SET_DISCORD_PERMISSION,\n    NO_SET_HOME_PERMISSION,\n    NO_SET_PAYPAL_PERMISSION,\n    NO_SET_ROLE_PERMISSION,\n    NO_SET_SETTINGS_PERMISSION,\n    NO_SET_WARP_PERMISSION,\n    NO_TRANSFER_PERMISSION,\n    NO_UNCOOP_PERMISSION,\n    NO_UPGRADE_PERMISSION,\n    NO_WITHDRAW_PERMISSION,\n    OPEN_MENU_WHILE_SLEEPING,\n    PANEL_TOGGLE_OFF,\n    PANEL_TOGGLE_ON,\n    PERMISSIONS_RESET,\n    PERMISSIONS_RESET_ALL,\n    PERMISSIONS_RESET_NAME,\n    PERMISSIONS_RESET_PLAYER,\n    PERMISSIONS_RESET_ROLES,\n    PERMISSION_CHANGED,\n    PERMISSION_CHANGED_ALL,\n    PERMISSION_CHANGED_NAME,\n    PERSISTENT_DATA_EMPTY,\n    PERSISTENT_DATA_MODIFY,\n    PERSISTENT_DATA_SHOW,\n    PERSISTENT_DATA_SHOW_PATH,\n    PERSISTENT_DATA_SHOW_VALUE,\n    PERSISTENT_DATA_SHOW_SPACER,\n    PERSISTENT_DATA_REMOVED,\n    PLACEHOLDER_NO,\n    PLACEHOLDER_YES,\n    PLAYER_ALREADY_BANNED,\n    PLAYER_ALREADY_COOP,\n    PLAYER_ALREADY_IN_ISLAND,\n    PLAYER_ALREADY_IN_ROLE,\n    PLAYER_EXPEL_BYPASS,\n    PLAYER_JOIN_ANNOUNCEMENT,\n    PLAYER_NOT_BANNED,\n    PLAYER_NOT_COOP,\n    PLAYER_NOT_INSIDE_ISLAND,\n    PLAYER_NOT_ONLINE,\n    PLAYER_QUIT_ANNOUNCEMENT,\n    PROMOTED_MEMBER,\n    PROMOTE_PLAYERS_WITH_LOWER_ROLE,\n    PURGED_ISLANDS,\n    PURGE_CLEAR,\n    RANKUP_SUCCESS,\n    RANKUP_SUCCESS_ALL,\n    RANKUP_SUCCESS_NAME,\n    RATE_ANNOUNCEMENT,\n    RATE_ALREADY_GIVEN,\n    RATE_CHANGE_OTHER,\n    RATE_OWN_ISLAND,\n    RATE_REMOVE_ALL,\n    RATE_REMOVE_ALL_ISLANDS,\n    RATE_SUCCESS,\n    REACHED_BLOCK_LIMIT,\n    REACHED_ENTITY_LIMIT,\n    RECALC_ALL_ISLANDS,\n    RECALC_ALL_ISLANDS_DONE,\n    RECALC_ALREADY_RUNNING,\n    RECALC_ALREADY_RUNNING_OTHER,\n    RECALC_PROCCESS_REQUEST,\n    RELOAD_COMPLETED,\n    RELOAD_PROCCESS_REQUEST,\n    RESET_WORLD_SUCCEED,\n    RESET_WORLD_SUCCEED_ALL,\n    RESET_WORLD_SUCCEED_NAME,\n    REVOKE_INVITE_ANNOUNCEMENT,\n    SAME_NAME_CHANGE,\n    SCHEMATIC_LEFT_SELECT,\n    SCHEMATIC_NOT_ADDED,\n    SCHEMATIC_NOT_READY,\n    SCHEMATIC_PROCCESS_REQUEST,\n    SCHEMATIC_READY_TO_CREATE,\n    SCHEMATIC_RIGHT_SELECT,\n    SCHEMATIC_SAVED,\n    SELF_ROLE_CHANGE,\n    SETTINGS_RESET,\n    SETTINGS_RESET_ALL,\n    SETTINGS_RESET_NAME,\n    SETTINGS_RESET_SELF,\n    SETTINGS_UPDATED,\n    SETTINGS_UPDATED_ALL,\n    SETTINGS_UPDATED_NAME,\n    SET_UPGRADE_LEVEL,\n    SET_UPGRADE_LEVEL_ALL,\n    SET_UPGRADE_LEVEL_NAME,\n    SET_WARP,\n    SET_WARP_OUTSIDE,\n    SIZE_BIGGER_MAX,\n    SPAWN_PROTECTED,\n    SPAWN_PROTECTED_OPPED,\n    SPAWN_SET_SUCCESS,\n    SPAWN_TELEPORT_SUCCESS,\n    SPY_TEAM_CHAT_FORMAT,\n    SYNC_UPGRADES,\n    SYNC_UPGRADES_ALL,\n    SYNC_UPGRADES_NAME,\n    TEAM_CHAT_FORMAT,\n    TELEPORTED_FAILED,\n    TELEPORTED_SUCCESS,\n    TELEPORTED_TO_WARP,\n    TELEPORTED_TO_WARP_ANNOUNCEMENT,\n    TELEPORT_LOCATION_OUTSIDE_ISLAND,\n    TELEPORT_OUTSIDE_ISLAND,\n    TELEPORT_WARMUP,\n    TELEPORT_WARMUP_CANCEL,\n    TITLE_SENT,\n    TOGGLED_BYPASS_OFF,\n    TOGGLED_BYPASS_ON,\n    TOGGLED_FLY_OFF,\n    TOGGLED_FLY_ON,\n    TOGGLED_FLY_OFF_OTHER,\n    TOGGLED_FLY_ON_OTHER,\n    TOGGLED_SCHEMATIC_OFF,\n    TOGGLED_SCHEMATIC_ON,\n    TOGGLED_SPY_OFF,\n    TOGGLED_SPY_ON,\n    TOGGLED_STACKED_BLOCKS_OFF,\n    TOGGLED_STACKED_BLOCKS_ON,\n    TOGGLED_TEAM_CHAT_OFF,\n    TOGGLED_TEAM_CHAT_ON,\n    TOGGLED_WORLD_BORDER_OFF,\n    TOGGLED_WORLD_BORDER_ON,\n    TRANSFER_ADMIN,\n    TRANSFER_ADMIN_ALREADY_LEADER,\n    TRANSFER_ADMIN_DIFFERENT_ISLAND,\n    TRANSFER_ADMIN_NOT_LEADER,\n    TRANSFER_ALREADY_LEADER,\n    TRANSFER_BROADCAST,\n    UNBAN_ANNOUNCEMENT,\n    UNCOOP_ANNOUNCEMENT,\n    UNCOOP_AUTO_ANNOUNCEMENT,\n    UNCOOP_LEFT_ANNOUNCEMENT,\n    UNIGNORED_ISLAND,\n    UNIGNORED_ISLAND_NAME,\n    UNLOCK_WORLD_ANNOUNCEMENT_ALL,\n    UNLOCK_WORLD_ANNOUNCEMENT_NAME,\n    UNLOCK_WORLD_ANNOUNCEMENT,\n    UNSAFE_WARP,\n    UPDATED_PERMISSION,\n    UPDATED_SETTINGS,\n    UPGRADE_COOLDOWN_FORMAT,\n    VAULT_NOT_INSTALLED,\n    VISITOR_BLOCK_COMMAND,\n    WARP_ALREADY_EXIST,\n    WARP_CATEGORY_ICON_NEW_LORE,\n    WARP_CATEGORY_ICON_NEW_NAME,\n    WARP_CATEGORY_ICON_NEW_TYPE,\n    WARP_CATEGORY_ICON_UPDATED,\n    WARP_CATEGORY_ILLEGAL_NAME,\n    WARP_CATEGORY_NAME_TOO_LONG,\n    WARP_CATEGORY_RENAME,\n    WARP_CATEGORY_RENAME_ALREADY_EXIST,\n    WARP_CATEGORY_RENAME_SUCCESS,\n    WARP_CATEGORY_SLOT,\n    WARP_CATEGORY_SLOT_ALREADY_TAKEN,\n    WARP_CATEGORY_SLOT_SUCCESS,\n    WARP_ICON_NEW_LORE,\n    WARP_ICON_NEW_NAME,\n    WARP_ICON_NEW_TYPE,\n    WARP_ICON_UPDATED,\n    WARP_ILLEGAL_NAME,\n    WARP_LOCATION_UPDATE,\n    WARP_NAME_TOO_LONG,\n    WARP_PRIVATE_UPDATE,\n    WARP_PUBLIC_UPDATE,\n    WARP_RENAME,\n    WARP_RENAME_ALREADY_EXIST,\n    WARP_RENAME_SUCCESS,\n    WITHDRAWN_MONEY,\n    WITHDRAWN_MONEY_NAME,\n    WITHDRAW_ALL_MONEY,\n    WITHDRAW_ANNOUNCEMENT,\n    WITHDRAW_ERROR,\n    WORLD_NOT_ENABLED,\n    WORLD_NOT_UNLOCKED,\n\n    CUSTOM(true) {\n        @Override\n        public void send(CommandSender sender, Locale locale, Object... args) {\n            String message = args.length == 0 ? null : args[0] == null ? null : args[0].toString();\n\n            if (Text.isBlank(message))\n                return;\n\n            boolean translateColors = args.length >= 2 && args[1] instanceof Boolean && (boolean) args[1];\n\n            if (translateColors) {\n                message = Formatters.COLOR_FORMATTER.format(message);\n            }\n\n            for (MessagesServiceImpl.CustomComponentParser parser : messagesService.get().getCustomComponentParsers()) {\n                Optional<IMessageComponent> component = parser.parse(message);\n                if (component.isPresent()) {\n                    component.get().sendMessage(sender);\n                    return;\n                }\n            }\n\n            sender.sendMessage(message);\n        }\n\n    };\n\n    private static final Object[] EMPTY_ARGS = new Object[0];\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<MessagesServiceImpl> messagesService = new LazyReference<MessagesServiceImpl>() {\n        @Override\n        protected MessagesServiceImpl create() {\n            return (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class);\n        }\n    };\n\n    private final String defaultMessage;\n    private final boolean isCustom;\n    private final Map<Locale, IMessageComponent> messages = new ArrayMap<>();\n    @Nullable\n    private Collection<UUID> delayedMessages;\n\n    Message() {\n        this(null);\n    }\n\n    Message(boolean isCustom) {\n        this(null, isCustom, 0L, null);\n    }\n\n    Message(String defaultMessage) {\n        this(defaultMessage, false, 0L, null);\n    }\n\n    Message(String defaultMessage, boolean isCustom, long delay, @Nullable TimeUnit delayUnit) {\n        this.defaultMessage = defaultMessage;\n        this.isCustom = isCustom;\n        if (delay > 0 && delayUnit != null)\n            delayedMessages = AutoRemovalCollection.newHashSet(delay, delayUnit);\n    }\n\n    public static void reload() {\n        Log.info(\"Loading messages started...\");\n        long startTime = System.currentTimeMillis();\n\n        convertOldFile();\n        PlayerLocales.clearLocales();\n\n        File langFolder = new File(plugin.getDataFolder(), \"lang\");\n\n        if (!langFolder.exists()) {\n            plugin.saveResource(\"lang/de-DE.yml\", false);\n            plugin.saveResource(\"lang/en-US.yml\", false);\n            plugin.saveResource(\"lang/es-ES.yml\", false);\n            plugin.saveResource(\"lang/fr-FR.yml\", false);\n            plugin.saveResource(\"lang/it-IT.yml\", false);\n            plugin.saveResource(\"lang/iw-IL.yml\", false);\n            plugin.saveResource(\"lang/pl-PL.yml\", false);\n            plugin.saveResource(\"lang/pt-BR.yml\", false);\n            plugin.saveResource(\"lang/ru-RU.yml\", false);\n            plugin.saveResource(\"lang/tr-TR.yml\", false);\n            plugin.saveResource(\"lang/vi-VN.yml\", false);\n            plugin.saveResource(\"lang/zh-CN.yml\", false);\n        }\n\n        int messagesAmount = 0;\n        boolean countMessages = true;\n\n        for (File langFile : Files.listFolderFiles(langFolder, false)) {\n            String fileName = langFile.getName().split(\"\\\\.\")[0];\n            Locale fileLocale;\n\n            try {\n                fileLocale = PlayerLocales.getLocale(fileName);\n            } catch (IllegalArgumentException ex) {\n                Log.warn(\"The language \", fileName, \" is invalid, skipping...\");\n                continue;\n            }\n\n            PlayerLocales.registerLocale(fileLocale);\n\n            if (plugin.getSettings().getDefaultLanguage().equalsIgnoreCase(fileName))\n                PlayerLocales.setDefaultLocale(fileLocale);\n\n            CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(langFile);\n\n            try (InputStream langResourceStream = plugin.getResource(\"lang/\" + langFile.getName())) {\n                cfg.syncWithConfig(langFile, langResourceStream == null ? plugin.getResource(\"lang/en-US.yml\") : langResourceStream, \"lang/en-US.yml\");\n            } catch (Exception error) {\n                Log.error(error, \"An unexpected error occurred while saving lang file \", langFile.getName(), \":\");\n            }\n\n            for (Message locale : values()) {\n                if (!locale.isCustom()) {\n                    locale.setMessage(fileLocale, messagesService.get().parseComponent(cfg, locale.name()));\n                    if (countMessages)\n                        messagesAmount++;\n                }\n            }\n\n            countMessages = false;\n        }\n\n        Log.info(\" - Found \" + messagesAmount + \" messages in the language files.\");\n        Log.info(\"Loading messages done (Took \" + (System.currentTimeMillis() - startTime) + \"ms)\");\n    }\n\n    public boolean isCustom() {\n        return isCustom;\n    }\n\n    public boolean isEmpty(Locale locale) {\n        IMessageComponent messageContainer = getComponent(locale);\n        return messageContainer == null || messageContainer.getType() == IMessageComponent.Type.EMPTY ||\n                messageContainer.getMessage().isEmpty();\n    }\n\n    @Nullable\n    public IMessageComponent getComponent(Locale locale) {\n        return messages.get(locale);\n    }\n\n    @Nullable\n    public String getMessage(Locale locale) {\n        return getMessage(locale, EMPTY_ARGS);\n    }\n\n    @Nullable\n    public String getMessage(Locale locale, Object... args) {\n        return isEmpty(locale) ? defaultMessage : messages.get(locale).getMessage(args);\n    }\n\n    public final void send(SuperiorPlayer superiorPlayer) {\n        send(superiorPlayer, EMPTY_ARGS);\n    }\n\n    public final void send(SuperiorPlayer superiorPlayer, Object... args) {\n        if (PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args))\n            superiorPlayer.runIfOnline(player -> send(player, superiorPlayer.getUserLocale(), args));\n    }\n\n    public final void send(CommandSender sender) {\n        send(sender, EMPTY_ARGS);\n    }\n\n    public final void send(CommandSender sender, Object... args) {\n        if (sender instanceof Player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n            if (!PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args))\n                return;\n        }\n\n        send(sender, PlayerLocales.getLocale(sender), args);\n    }\n\n    public void send(CommandSender sender, Locale locale) {\n        send(sender, locale, EMPTY_ARGS);\n    }\n\n    public void send(CommandSender sender, Locale locale, Object... args) {\n        IMessageComponent messageComponent = getComponent(locale);\n        if (messageComponent == null)\n            return;\n\n        if (sender instanceof Player) {\n            UUID playerUUID = ((Player) sender).getUniqueId();\n            if (delayedMessages != null && !delayedMessages.add(playerUUID))\n                return;\n        }\n\n        PluginEvent<PluginEventArgs.SendMessage> event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args);\n        if (!event.isCancelled()) {\n            event.getArgs().messageComponent.sendMessage(sender, args);\n            if (!(sender instanceof Player) && Log.isDebugged(Debug.SHOW_STACKTRACE)) {\n                Thread.dumpStack();\n            }\n        }\n    }\n\n    private void setMessage(Locale locale, IMessageComponent messageComponent) {\n        messages.put(locale, messageComponent);\n    }\n\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    private static void convertOldFile() {\n        File file = new File(plugin.getDataFolder(), \"lang.yml\");\n        if (file.exists()) {\n            File dest = new File(plugin.getDataFolder(), \"lang/en-US.yml\");\n            dest.getParentFile().mkdirs();\n            file.renameTo(dest);\n        }\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Message::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        for (Message message : values()) {\n            long delay = plugin.getSettings().getMessageDelays().getOrDefault(message.name(), 0L);\n\n            if (delay > 0L)\n                message.delayedMessages = AutoRemovalCollection.newHashSet(delay, TimeUnit.MILLISECONDS);\n            else\n                message.delayedMessages = null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport org.bukkit.OfflinePlayer;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MessageContent {\n\n    public static final MessageContent EMPTY = new MessageContent(Collections.emptyList()) {\n        @Override\n        public Optional<String> getContent(@Nullable OfflinePlayer unused, Object... unused2) {\n            return Optional.empty();\n        }\n    };\n\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private static final Pattern DEFAULT_PLACEHOLDER_PATTERN = Pattern.compile(\"\\\\{(\\\\d+)}\");\n\n    private final List<IPart> contentParts = new LinkedList<>();\n\n    public static List<MessageContent> parse(List<String> contents) {\n        List<MessageContent> messageContentsList = new LinkedList<>();\n        for (String content : contents)\n            messageContentsList.add(parse(content));\n        return messageContentsList;\n    }\n\n    public static MessageContent parse(String content) {\n        Matcher matcher = DEFAULT_PLACEHOLDER_PATTERN.matcher(content);\n\n        List<IPart> parts = new LinkedList<>();\n        int lastPartIdx = 0;\n\n        while (matcher.find()) {\n            StringBuilder previousPart = new StringBuilder(content.substring(lastPartIdx, matcher.start()));\n\n            ArgumentPart argumentPart = null;\n\n            try {\n                int argumentIndex = Integer.parseInt(matcher.group(1));\n                argumentPart = ArgumentPart.fromIndex(argumentIndex);\n            } catch (NumberFormatException error) {\n                previousPart.append(matcher.group());\n            }\n\n            if (previousPart.length() > 0)\n                parts.add(new StaticPart(previousPart.toString()));\n            if (argumentPart != null)\n                parts.add(argumentPart);\n\n            lastPartIdx = matcher.end();\n        }\n\n        if (lastPartIdx < content.length())\n            parts.add(new StaticPart(content.substring(lastPartIdx)));\n\n        return new MessageContent(parts);\n    }\n\n    private MessageContent(List<IPart> contentParts) {\n        this.contentParts.addAll(contentParts);\n    }\n\n    public Optional<String> getContent(@Nullable OfflinePlayer offlinePlayer, Object... arguments) {\n        StringBuilder content = new StringBuilder();\n        for (IPart part : contentParts) {\n            if (part instanceof StaticPart) {\n                content.append(((StaticPart) part).content);\n            } else {\n                int argumentIndex = ((ArgumentPart) part).argumentIndex;\n                if (argumentIndex >= 0 && argumentIndex < arguments.length) {\n                    content.append(getArgumentString(arguments[argumentIndex]));\n                } else {\n                    content.append(\"{\").append(argumentIndex).append(\"}\");\n                }\n            }\n        }\n\n        if (content.length() == 0)\n            return Optional.empty();\n\n        return Optional.of(placeholdersService.get().parsePlaceholders(offlinePlayer, content.toString()));\n    }\n\n    public static String getArgumentString(Object argument) {\n        return argument instanceof BigDecimal ?\n                Formatters.NUMBER_FORMATTER.format((BigDecimal) argument) :\n                String.valueOf(argument);\n    }\n\n    private interface IPart {\n\n    }\n\n    private static class StaticPart implements IPart {\n\n        private final String content;\n\n        StaticPart(String content) {\n            this.content = content;\n        }\n\n    }\n\n    private static class ArgumentPart implements IPart {\n\n        private static final ArgumentPart[] CACHED_PARTS = new ArgumentPart[]{\n                new ArgumentPart(0),\n                new ArgumentPart(1),\n                new ArgumentPart(2),\n                new ArgumentPart(3)\n        };\n\n        private final int argumentIndex;\n\n        static ArgumentPart fromIndex(int index) {\n            return index >= 0 && index < CACHED_PARTS.length ? CACHED_PARTS[index] : new ArgumentPart(index);\n        }\n\n        ArgumentPart(int argumentIndex) {\n            this.argumentIndex = argumentIndex;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/EmptyMessageComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component;\n\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport org.bukkit.command.CommandSender;\n\npublic class EmptyMessageComponent implements IMessageComponent {\n\n    private static final EmptyMessageComponent INSTANCE = new EmptyMessageComponent();\n\n    public static EmptyMessageComponent getInstance() {\n        return INSTANCE;\n    }\n\n    private EmptyMessageComponent() {\n\n    }\n\n    @Override\n    public Type getType() {\n        return Type.EMPTY;\n    }\n\n    @Override\n    public String getMessage() {\n        return \"\";\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        // Do nothing.\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component;\n\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.ActionBarComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.BossBarComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.SoundComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.TitleComponent;\nimport com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl;\nimport net.md_5.bungee.api.chat.BaseComponent;\nimport net.md_5.bungee.api.chat.ClickEvent;\nimport net.md_5.bungee.api.chat.HoverEvent;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\n\npublic class MultipleComponents implements IMessageComponent {\n\n    private final List<IMessageComponent> messageComponents;\n\n    public static IMessageComponent parseSection(ConfigurationSection section, List<MessagesServiceImpl.CustomComponentParser> customComponentParsers) {\n        List<IMessageComponent> messageComponents = new LinkedList<>();\n\n        keysLoop:\n        for (String key : section.getKeys(false)) {\n            if (key.equals(\"action-bar\")) {\n                messageComponents.add(ActionBarComponent.of(Formatters.COLOR_FORMATTER.format(section.getString(key + \".text\"))));\n            } else if (key.equals(\"title\")) {\n                messageComponents.add(TitleComponent.of(\n                        Formatters.COLOR_FORMATTER.format(section.getString(key + \".title\")),\n                        Formatters.COLOR_FORMATTER.format(section.getString(key + \".sub-title\")),\n                        section.getInt(key + \".fade-in\"),\n                        section.getInt(key + \".duration\"),\n                        section.getInt(key + \".fade-out\")\n                ));\n            } else if (key.equals(\"sound\")) {\n                messageComponents.add(SoundComponent.of(MenuParserImpl.getInstance().getSound(section.getConfigurationSection(\"sound\"))));\n            } else if (key.equals(\"bossbar\")) {\n                BossBar.Color color;\n\n                try {\n                    color = BossBar.Color.valueOf(section.getString(key + \".color\").toUpperCase());\n                } catch (Exception error) {\n                    color = BossBar.Color.PINK;\n                }\n\n                messageComponents.add(BossBarComponent.of(\n                        Formatters.COLOR_FORMATTER.format(section.getString(key + \".message\")),\n                        color, section.getInt(key + \".ticks\")));\n            } else {\n                String text = section.getString(key + \".text\");\n\n                for (MessagesServiceImpl.CustomComponentParser parser : customComponentParsers) {\n                    Optional<IMessageComponent> res = parser.parse(text);\n                    if (res.isPresent()) {\n                        messageComponents.add(res.get());\n                        continue keysLoop;\n                    }\n                }\n\n                BaseComponent[] baseComponents = TextComponent.fromLegacyText(Formatters.COLOR_FORMATTER.format(text));\n\n                String toolTipMessage = section.getString(key + \".tooltip\");\n                if (toolTipMessage != null) {\n                    for (BaseComponent baseComponent : baseComponents)\n                        baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,\n                                new BaseComponent[]{new TextComponent(Formatters.COLOR_FORMATTER.format(toolTipMessage))}));\n                }\n\n                String commandMessage = section.getString(key + \".command\");\n                if (commandMessage != null) {\n                    for (BaseComponent baseComponent : baseComponents)\n                        baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, commandMessage));\n                }\n\n                String suggestMessage = section.getString(key + \".suggest\");\n                if (suggestMessage != null) {\n                    for (BaseComponent baseComponent : baseComponents)\n                        baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestMessage));\n                }\n\n                messageComponents.add(ComplexMessageComponent.of(baseComponents));\n            }\n        }\n\n        messageComponents.removeIf(component -> component.getType() == Type.EMPTY);\n\n        return of(messageComponents);\n    }\n\n    public static IMessageComponent of(List<IMessageComponent> messageComponents) {\n        return messageComponents.isEmpty() ? EmptyMessageComponent.getInstance() :\n                messageComponents.size() == 1 ? messageComponents.get(0) : new MultipleComponents(messageComponents);\n    }\n\n    private MultipleComponents(List<IMessageComponent> messageComponents) {\n        this.messageComponents = messageComponents;\n    }\n\n    @Override\n    public Type getType() {\n        return Type.MULTIPLE;\n    }\n\n    @Override\n    @Deprecated\n    public String getMessage() {\n        return messageComponents.isEmpty() ? \"\" : messageComponents.get(0).getMessage();\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return messageComponents.isEmpty() ? \"\" : messageComponents.get(0).getMessage(args);\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        this.messageComponents.forEach(messageComponent -> messageComponent.sendMessage(sender, args));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\npublic class ActionBarComponent implements IMessageComponent {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final MessageContent content;\n\n    public static IMessageComponent of(@Nullable String message) {\n        return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new ActionBarComponent(message);\n    }\n\n    private ActionBarComponent(String content) {\n        this.content = MessageContent.parse(content);\n    }\n\n    @Override\n    public Type getType() {\n        return Type.ACTION_BAR;\n    }\n\n    @Override\n    public String getMessage() {\n        return this.content.getContent(null).orElse(\"\");\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return this.content.getContent(null, args).orElse(\"\");\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        this.content.getContent((Player) sender, args).ifPresent(message ->\n                plugin.getNMSPlayers().sendActionBar((Player) sender, message));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java",
    "content": "\npackage com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBarsService;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport org.apache.logging.log4j.util.Strings;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\npublic class BossBarComponent implements IMessageComponent {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<BossBarsService> bossBarsService = new LazyReference<BossBarsService>() {\n        @Override\n        protected BossBarsService create() {\n            return plugin.getServices().getService(BossBarsService.class);\n        }\n    };\n\n    private final MessageContent content;\n    private final BossBar.Color color;\n    private final int ticksToRun;\n\n    public static IMessageComponent of(@Nullable String message, BossBar.Color color, int ticks) {\n        return ticks <= 0 || Strings.isBlank(message) ? EmptyMessageComponent.getInstance() : new BossBarComponent(message, color, ticks);\n    }\n\n    private BossBarComponent(String content, BossBar.Color color, int ticks) {\n        this.content = MessageContent.parse(content);\n        this.color = color;\n        this.ticksToRun = ticks;\n    }\n\n    @Override\n    public Type getType() {\n        return Type.BOSS_BAR;\n    }\n\n    @Override\n    public String getMessage() {\n        return this.content.getContent(null).orElse(\"\");\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return this.content.getContent(null, args).orElse(\"\");\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        if (sender instanceof Player) {\n            this.content.getContent((Player) sender, args).ifPresent(message ->\n                    bossBarsService.get().createBossBar((Player) sender, message, this.color, this.ticksToRun));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport net.md_5.bungee.api.chat.BaseComponent;\nimport net.md_5.bungee.api.chat.ClickEvent;\nimport net.md_5.bungee.api.chat.HoverEvent;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\n\npublic class ComplexMessageComponent implements IMessageComponent {\n\n    private final IWrappedComponent[] components;\n    private final MessageContent content;\n\n    public static IMessageComponent of(@Nullable BaseComponent[] baseComponents) {\n        if (baseComponents == null || baseComponents.length == 0)\n            return EmptyMessageComponent.getInstance();\n\n        boolean isTextEmpty = true;\n\n        for (BaseComponent baseComponent : baseComponents) {\n            if (baseComponent instanceof TextComponent && !Text.isBlank(((TextComponent) baseComponent).getText())) {\n                isTextEmpty = false;\n                break;\n            }\n        }\n\n        return isTextEmpty ? EmptyMessageComponent.getInstance() : new ComplexMessageComponent(baseComponents);\n    }\n\n    private ComplexMessageComponent(BaseComponent[] baseComponents) {\n        this.components = parseComponents(baseComponents);\n        this.content = findTextComponentContent(baseComponents);\n    }\n\n    private static IWrappedComponent[] parseComponents(BaseComponent[] baseComponents) {\n        IWrappedComponent[] components = new IWrappedComponent[baseComponents.length];\n        for (int i = 0; i < components.length; ++i) {\n            BaseComponent curr = baseComponents[i];\n            IWrappedComponent wrappedComponent;\n            if (curr instanceof TextComponent) {\n                wrappedComponent = new ContentComponent((TextComponent) curr);\n            } else if (curr.getHoverEvent() != null) {\n                wrappedComponent = new HoverEventComponent(curr);\n            } else {\n                wrappedComponent = new ComponentHolder(curr);\n            }\n            components[i] = wrappedComponent;\n        }\n        return components;\n    }\n\n    private static MessageContent findTextComponentContent(BaseComponent[] baseComponents) {\n        for (BaseComponent baseComponent : baseComponents) {\n            if (baseComponent instanceof TextComponent)\n                return MessageContent.parse(baseComponent.toLegacyText());\n        }\n\n        return MessageContent.EMPTY;\n    }\n\n    @Override\n    public Type getType() {\n        return Type.COMPLEX_MESSAGE;\n    }\n\n    @Override\n    public String getMessage() {\n        return this.content.getContent(null).orElse(\"\");\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return this.content.getContent(null, args).orElse(\"\");\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        if (!(sender instanceof Player)) {\n            this.content.getContent(null, args).ifPresent(sender::sendMessage);\n        } else if (components.length > 0) {\n            BaseComponent[] components = new BaseComponent[this.components.length];\n            for (int i = 0; i < this.components.length; ++i)\n                components[i] = this.components[i].parse((Player) sender, args);\n            ((Player) sender).spigot().sendMessage(components);\n        }\n    }\n\n    private interface IWrappedComponent {\n\n        BaseComponent parse(OfflinePlayer offlinePlayer, Object... args);\n\n    }\n\n    private static class ComponentHolder implements IWrappedComponent {\n\n        private final BaseComponent handle;\n\n        ComponentHolder(BaseComponent handle) {\n            this.handle = handle;\n        }\n\n        @Override\n        public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) {\n            return this.handle;\n        }\n\n    }\n\n    private static class ContentComponent implements IWrappedComponent {\n\n        private final MessageContent content;\n        @Nullable\n        private final HoverEventContents hoverEventContents;\n        @Nullable\n        private final ClickEvent.Action clickEventAction;\n        @Nullable\n        private final MessageContent clickEventContent;\n\n        ContentComponent(TextComponent textComponent) {\n            this.content = MessageContent.parse(textComponent.toLegacyText());\n            this.hoverEventContents = textComponent.getHoverEvent() == null ? null :\n                    new HoverEventContents(textComponent.getHoverEvent());\n            ClickEvent clickEvent = textComponent.getClickEvent();\n            if (clickEvent != null) {\n                this.clickEventAction = clickEvent.getAction();\n                this.clickEventContent = MessageContent.parse(clickEvent.getValue());\n            } else {\n                this.clickEventAction = null;\n                this.clickEventContent = null;\n            }\n        }\n\n        @Override\n        public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) {\n            TextComponent textComponent = (TextComponent) TextComponent.fromLegacyText(\n                    this.content.getContent(offlinePlayer, args).orElse(\"\"))[0];\n            if (this.hoverEventContents != null)\n                textComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args));\n            if (this.clickEventAction != null && this.clickEventContent != null) {\n                textComponent.setClickEvent(new ClickEvent(this.clickEventAction,\n                        this.clickEventContent.getContent(offlinePlayer, args).orElse(\"\")));\n            }\n\n            return textComponent;\n        }\n    }\n\n    private static class HoverEventComponent implements IWrappedComponent {\n\n        private final BaseComponent baseComponent;\n        private final HoverEventContents hoverEventContents;\n\n        HoverEventComponent(BaseComponent baseComponent) {\n            this.baseComponent = baseComponent;\n            this.hoverEventContents = new HoverEventContents(baseComponent.getHoverEvent());\n        }\n\n        @Override\n        public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) {\n            BaseComponent newComponent = this.baseComponent.duplicate();\n            newComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args));\n            return newComponent;\n        }\n\n    }\n\n    private static class HoverEventContents {\n\n        private final HoverEvent.Action action;\n        private final IWrappedComponent[] components;\n\n        HoverEventContents(HoverEvent hoverEvent) {\n            this.action = hoverEvent.getAction();\n            this.components = parseComponents(hoverEvent.getValue());\n        }\n\n        HoverEvent parse(OfflinePlayer offlinePlayer, Object... args) {\n            BaseComponent[] components = new BaseComponent[this.components.length];\n            for (int i = 0; i < components.length; ++i)\n                components[i] = this.components[i].parse(offlinePlayer, args);\n            return new HoverEvent(this.action, components);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\npublic class RawMessageComponent implements IMessageComponent {\n\n    private final MessageContent content;\n\n    public static IMessageComponent of(@Nullable String message) {\n        return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new RawMessageComponent(message);\n    }\n\n    private RawMessageComponent(String message) {\n        this.content = MessageContent.parse(message);\n    }\n\n    @Override\n    public Type getType() {\n        return Type.RAW_MESSAGE;\n    }\n\n    @Override\n    public String getMessage() {\n        return this.content.getContent(null).orElse(\"\");\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return this.content.getContent(null, args).orElse(\"\");\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        Player player = sender instanceof Player ? (Player) sender : null;\n        this.content.getContent(player, args).ifPresent(sender::sendMessage);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/SoundComponent.java",
    "content": "package com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\npublic class SoundComponent implements IMessageComponent {\n\n    private final GameSound gameSound;\n\n    public static IMessageComponent of(@Nullable GameSound gameSound) {\n        return GameSoundImpl.isEmpty(gameSound) ? EmptyMessageComponent.getInstance() : new SoundComponent(gameSound);\n    }\n\n    private SoundComponent(GameSound gameSound) {\n        this.gameSound = gameSound;\n    }\n\n\n    @Override\n    public Type getType() {\n        return Type.SOUND;\n    }\n\n    @Override\n    public String getMessage() {\n        return \"\";\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        if (sender instanceof Player)\n            GameSoundImpl.playSound((Player) sender, gameSound);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java",
    "content": "\npackage com.bgsoftware.superiorskyblock.core.messages.component.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.messages.MessageContent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\npublic class TitleComponent implements IMessageComponent {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final MessageContent titleMessage;\n    private final MessageContent subtitleMessage;\n    private final int fadeIn;\n    private final int duration;\n    private final int fadeOut;\n\n    public static IMessageComponent of(@Nullable String titleMessage, @Nullable String subtitleMessage,\n                                       int fadeIn, int duration, int fadeOut) {\n        return duration <= 0 || (Text.isBlank(titleMessage) && Text.isBlank(subtitleMessage)) ?\n                EmptyMessageComponent.getInstance() : new TitleComponent(titleMessage, subtitleMessage, fadeIn, duration, fadeOut);\n    }\n\n    private TitleComponent(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) {\n        this.titleMessage = Text.isBlank(titleMessage) ? MessageContent.EMPTY : MessageContent.parse(titleMessage);\n        this.subtitleMessage = Text.isBlank(subtitleMessage) ? MessageContent.EMPTY : MessageContent.parse(subtitleMessage);\n        this.fadeIn = fadeIn;\n        this.duration = duration;\n        this.fadeOut = fadeOut;\n    }\n\n    @Override\n    public Type getType() {\n        return Type.TITLE;\n    }\n\n    @Override\n    public String getMessage() {\n        return this.titleMessage.getContent(null).orElse(\"\");\n    }\n\n    @Override\n    public String getMessage(Object... args) {\n        return this.titleMessage.getContent(null, args).orElse(\"\");\n    }\n\n    @Override\n    public void sendMessage(CommandSender sender, Object... args) {\n        String titleMessage = this.titleMessage.getContent((Player) sender, args).orElse(null);\n        String subtitleMessage = this.subtitleMessage.getContent((Player) sender, args).orElse(null);\n        if (titleMessage != null && subtitleMessage != null)\n            plugin.getNMSPlayers().sendTitle((Player) sender, titleMessage, subtitleMessage,\n                    this.fadeIn, this.duration, this.fadeOut);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableBoolean.java",
    "content": "package com.bgsoftware.superiorskyblock.core.mutable;\n\npublic class MutableBoolean {\n\n    private boolean value;\n\n    public MutableBoolean(boolean value) {\n        this.value = value;\n    }\n\n    public boolean get() {\n        return this.value;\n    }\n\n    public void set(boolean value) {\n        this.value = value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableInt.java",
    "content": "package com.bgsoftware.superiorskyblock.core.mutable;\n\npublic class MutableInt {\n\n    private int value;\n\n    public MutableInt(int value) {\n        this.value = value;\n    }\n\n    public int get() {\n        return this.value;\n    }\n\n    public void set(int value) {\n        this.value = value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableLong.java",
    "content": "package com.bgsoftware.superiorskyblock.core.mutable;\n\npublic class MutableLong {\n\n    private long value;\n\n    public MutableLong(long value) {\n        this.value = value;\n    }\n\n    public long get() {\n        return this.value;\n    }\n\n    public void set(long value) {\n        this.value = value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableObject.java",
    "content": "package com.bgsoftware.superiorskyblock.core.mutable;\n\npublic class MutableObject<E> {\n\n    private E value;\n\n    public MutableObject(E value) {\n        this.value = value;\n    }\n\n    public E getValue() {\n        return value;\n    }\n\n    public void setValue(E value) {\n        this.value = value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/persistence/EmptyPersistentDataContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\n\nimport java.util.function.BiConsumer;\n\npublic class EmptyPersistentDataContainer implements PersistentDataContainer {\n\n    private static final EmptyPersistentDataContainer INSTANCE = new EmptyPersistentDataContainer();\n\n    public static EmptyPersistentDataContainer getInstance() {\n        return INSTANCE;\n    }\n\n    private EmptyPersistentDataContainer() {\n\n    }\n\n    @Override\n    public boolean has(String key) {\n        return false;\n    }\n\n    @Override\n    public <T> boolean hasKeyOfType(String key, PersistentDataType<T> type) {\n        return false;\n    }\n\n    @Nullable\n    @Override\n    public <T> T put(String key, PersistentDataType<T> type, T value) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public <T, R> R put(String key, PersistentDataType<T> type, T value, PersistentDataType<R> returnType) throws IllegalArgumentException, IllegalStateException {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public Object remove(String key) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public <T> T removeKeyOfType(String key, PersistentDataType<T> type) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public <T> T get(String key, PersistentDataType<T> type) throws IllegalArgumentException {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public Object get(String key) {\n        return null;\n    }\n\n    @Override\n    public <T> T getOrDefault(String key, PersistentDataType<T> type, T def) throws IllegalArgumentException {\n        return def;\n    }\n\n    @Override\n    public Object getOrDefault(String key, Object def) {\n        return def;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return true;\n    }\n\n    @Override\n    public int size() {\n        return 0;\n    }\n\n    @Override\n    public void forEach(BiConsumer<String, Object> action) {\n        // Do nothing.\n    }\n\n    @Override\n    public byte[] serialize() {\n        return new byte[0];\n    }\n\n    @Override\n    public void load(byte[] data) {\n        // Do nothing.\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext;\nimport com.bgsoftware.superiorskyblock.tag.BigDecimalTag;\nimport com.bgsoftware.superiorskyblock.tag.ByteArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.ByteTag;\nimport com.bgsoftware.superiorskyblock.tag.DoubleTag;\nimport com.bgsoftware.superiorskyblock.tag.FloatTag;\nimport com.bgsoftware.superiorskyblock.tag.IntArrayTag;\nimport com.bgsoftware.superiorskyblock.tag.IntTag;\nimport com.bgsoftware.superiorskyblock.tag.LongTag;\nimport com.bgsoftware.superiorskyblock.tag.PersistentDataTag;\nimport com.bgsoftware.superiorskyblock.tag.PersistentDataTagSerialized;\nimport com.bgsoftware.superiorskyblock.tag.ShortTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.tag.UUIDTag;\nimport com.google.common.base.Preconditions;\nimport com.google.common.collect.ImmutableMap;\n\nimport java.math.BigDecimal;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Function;\n\npublic class PersistenceDataTypeSerializer {\n\n    private static final Map<Class<?>, Function<Object, Tag<?>>> CLASS_TO_NBT = new ImmutableMap.Builder<Class<?>, Function<Object, Tag<?>>>()\n            .put(BigDecimal.class, value -> BigDecimalTag.of((BigDecimal) value))\n            .put(byte[].class, value -> ByteArrayTag.of((byte[]) value))\n            .put(Byte.class, value -> ByteTag.of((byte) value))\n            .put(Double.class, value -> DoubleTag.of((double) value))\n            .put(Float.class, value -> FloatTag.of((float) value))\n            .put(int[].class, value -> IntArrayTag.of((int[]) value))\n            .put(Integer.class, value -> IntTag.of((int) value))\n            .put(Long.class, value -> LongTag.of((long) value))\n            .put(Short.class, value -> ShortTag.of((short) value))\n            .put(String.class, value -> StringTag.of((String) value))\n            .put(UUID.class, value -> UUIDTag.of((UUID) value))\n            .build();\n\n    private PersistenceDataTypeSerializer() {\n\n    }\n\n    @Nullable\n    public static <T> T deserialize(Tag<?> tag, PersistentDataType<T> type) throws IllegalArgumentException {\n        if (tag instanceof PersistentDataTagSerialized) {\n            tag = ((PersistentDataTagSerialized) tag).getPersistentDataTag(type);\n        }\n\n        checkTagType(tag, type);\n        return type.getType().cast(tag.getValue());\n    }\n\n    public static <T> Tag<?> serialize(T value, PersistentDataType<T> type) {\n        PersistentDataTypeContext<T> serializer = type.getContext();\n        if (serializer != null)\n            return PersistentDataTag.of(value, serializer);\n\n        Tag<?> serializedTag = primitiveSerialize(value);\n\n        Preconditions.checkState(serializedTag != null, \"value \" + value.getClass() + \" doesnt have a valid serializer.\");\n\n        return serializedTag;\n    }\n\n    public static boolean isTagOfType(Tag<?> tag, PersistentDataType<?> type) {\n        return tag instanceof PersistentDataTagSerialized ? type.getContext() != null :\n                tag.getValue().getClass().isAssignableFrom(type.getType());\n    }\n\n    private static void checkTagType(Tag<?> tag, PersistentDataType<?> type) {\n        if (!isTagOfType(tag, type))\n            throw new IllegalArgumentException(\"Expected: \" + type.getType().getName() + \", actual: \" + tag.getValue().getClass());\n    }\n\n    private static Tag<?> primitiveSerialize(Object value) {\n        Function<Object, Tag<?>> tagFunction = CLASS_TO_NBT.get(value.getClass());\n        return tagFunction == null ? null : tagFunction.apply(value);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.persistence;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.PersistentDataTagSerialized;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.google.common.base.Preconditions;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\npublic class PersistentDataContainerImpl<E> implements PersistentDataContainer {\n\n    private final E holder;\n    private final Consumer<E> saveFunction;\n\n    private final CompoundTag innerTag = CompoundTag.of();\n\n    public PersistentDataContainerImpl(E holder, Consumer<E> saveFunction) {\n        this.holder = holder;\n        this.saveFunction = saveFunction;\n    }\n\n    @Override\n    public boolean has(String key) {\n        return innerTag.containsKey(key);\n    }\n\n    @Override\n    public <T> boolean hasKeyOfType(String key, PersistentDataType<T> type) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        Tag<?> tag = innerTag.getTag(key).orElse(null);\n        return tag != null && PersistenceDataTypeSerializer.isTagOfType(tag, type);\n    }\n\n    @Nullable\n    @Override\n    public <T> T put(String key, PersistentDataType<T> type, T value) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        Preconditions.checkNotNull(value, \"value parameter cannot be null\");\n        return put(key, type, value, type);\n    }\n\n    @Nullable\n    @Override\n    public <T, R> R put(String key, PersistentDataType<T> type, T value, PersistentDataType<R> returnType) throws IllegalArgumentException, IllegalStateException {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        Preconditions.checkNotNull(value, \"value parameter cannot be null\");\n        Preconditions.checkNotNull(returnType, \"returnType parameter cannot be null\");\n        Tag<?> oldValue = innerTag.setTag(key, PersistenceDataTypeSerializer.serialize(value, type));\n\n        this.saveFunction.accept(holder);\n\n        return oldValue == null ? null : PersistenceDataTypeSerializer.deserialize(oldValue, returnType);\n    }\n\n    @Nullable\n    @Override\n    public Object remove(String key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Tag<?> oldValue = innerTag.remove(key);\n\n        this.saveFunction.accept(holder);\n\n        return oldValue == null ? null : oldValue.getValue();\n    }\n\n    @Nullable\n    @Override\n    public <T> T removeKeyOfType(String key, PersistentDataType<T> type) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n\n        if (!hasKeyOfType(key, type))\n            return null;\n\n        Tag<?> oldValue = innerTag.remove(key);\n\n        this.saveFunction.accept(holder);\n\n        return PersistenceDataTypeSerializer.deserialize(oldValue, type);\n    }\n\n    @Nullable\n    @Override\n    public <T> T get(String key, PersistentDataType<T> type) throws IllegalArgumentException {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        return _getOfType(key, type, null);\n    }\n\n    @Nullable\n    @Override\n    public Object get(String key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        return _get(key, null);\n    }\n\n    @Override\n    public <T> T getOrDefault(String key, PersistentDataType<T> type, T def) throws IllegalArgumentException {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        Preconditions.checkNotNull(type, \"type parameter cannot be null\");\n        return _getOfType(key, type, def);\n    }\n\n    @Override\n    public Object getOrDefault(String key, Object def) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null\");\n        return _get(key, def);\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return innerTag.isEmpty();\n    }\n\n    @Override\n    public int size() {\n        return innerTag.size();\n    }\n\n    @Override\n    public void forEach(BiConsumer<String, Object> action) {\n        innerTag.getValue().forEach((key, value) -> {\n            action.accept(key, value.getValue());\n        });\n    }\n\n    @Override\n    public byte[] serialize() {\n        ByteArrayOutputStream byteArrayDataOutput = new ByteArrayOutputStream();\n\n        try {\n            innerTag.write(new DataOutputStream(byteArrayDataOutput));\n        } catch (IOException ignored) {\n        }\n\n        return byteArrayDataOutput.toByteArray();\n    }\n\n    @Override\n    public void load(byte[] data) {\n        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);\n        try {\n            this.innerTag.putAll((CompoundTag) Tag.fromStream(new DataInputStream(byteArrayInputStream), 0));\n        } catch (Exception error) {\n            throw new IllegalArgumentException(error);\n        }\n    }\n\n    @Nullable\n    private <T> T _getOfType(String key, PersistentDataType<T> type, @Nullable T def) {\n        Tag<?> tag = innerTag.getTag(key).orElse(null);\n\n        if (tag == null) {\n            return def;\n        }\n\n        if (tag instanceof PersistentDataTagSerialized) {\n            tag = ((PersistentDataTagSerialized) tag).getPersistentDataTag(type);\n            innerTag.setTag(key, tag);\n        }\n\n        return PersistenceDataTypeSerializer.deserialize(tag, type);\n    }\n\n    @Nullable\n    private Object _get(String key, @Nullable Object def) {\n        Tag<?> tag = innerTag.getTag(key).orElse(null);\n        return tag == null ? def : tag.getValue();\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/profiler/ProfileType.java",
    "content": "package com.bgsoftware.superiorskyblock.core.profiler;\n\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\n\npublic enum ProfileType {\n\n    CALCULATE_ISLAND,\n    CREATE_ISLAND,\n    DISBAND_ISLAND,\n    LOAD_CHUNK,\n    SCHEMATIC_BLOCKS_PLACE,\n    SCHEMATIC_PLACE;\n\n    private final LazyReference<String> prettyName = new LazyReference<String>() {\n        @Override\n        protected String create() {\n            return Formatters.CAPITALIZED_FORMATTER.format(ProfileType.this.name());\n        }\n    };\n\n    ProfileType() {\n\n    }\n\n    public String getPrettyName() {\n        return this.prettyName.get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/profiler/Profiler.java",
    "content": "package com.bgsoftware.superiorskyblock.core.profiler;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.stats.StatsProfilers;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class Profiler {\n\n    private Profiler() {\n\n    }\n\n    private static final long INVALID_PROFILE_ID = -1;\n\n    private static final Map<Long, ProfilerSession> profilerSessions = new ConcurrentHashMap<>();\n    private static final AtomicLong lastProfilerId = new AtomicLong(0);\n\n    public static long start(ProfileType profileType) {\n        return start(profileType, null);\n    }\n\n    public static long start(ProfileType profileType, @Nullable Object extra) {\n        return start(profileType, 1, extra);\n    }\n\n    public static long start(ProfileType profileType, int stopCount) {\n        return start(profileType, stopCount, null);\n    }\n\n    public static long start(ProfileType profileType, int stopCount, @Nullable Object extra) {\n        ProfilerSession profilerSession;\n\n        try {\n            profilerSession = new ProfilerSession(lastProfilerId.incrementAndGet(), stopCount, profileType, extra);\n            profilerSessions.put(profilerSession.getId(), profilerSession);\n            return profilerSession.getId();\n        } catch (Throwable error) {\n            error.printStackTrace();\n            return INVALID_PROFILE_ID;\n        }\n    }\n\n    public static void end(long id) {\n        if (id == INVALID_PROFILE_ID)\n            return;\n\n        ProfilerSession profilerSession = profilerSessions.get(id);\n\n        if (profilerSession == null)\n            return;\n\n        if (profilerSession.end()) {\n            profilerSessions.remove(id);\n            String[] profiledData = profilerSession.dump();\n            Log.profile(profiledData);\n            StatsProfilers.INSTANCE.submitProfiler(profilerSession);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/profiler/ProfilerSession.java",
    "content": "package com.bgsoftware.superiorskyblock.core.profiler;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class ProfilerSession {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final long id;\n    private final AtomicInteger stopCount;\n    private final ProfileType profileType;\n    @Nullable\n    private final Object extra;\n    private final Data startData;\n    private Data endData;\n\n    public ProfilerSession(long id, int stopCount, ProfileType profileType, @Nullable Object extra) {\n        this.id = id;\n        this.stopCount = new AtomicInteger(stopCount);\n        this.profileType = profileType;\n        this.extra = extra;\n        this.startData = new Data();\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    public ProfileType getProfileType() {\n        return profileType;\n    }\n\n    @Nullable\n    public Object getExtra() {\n        return extra;\n    }\n\n    public Data getStartData() {\n        return startData;\n    }\n\n    public Data getEndData() {\n        return Objects.requireNonNull(endData);\n    }\n\n    public boolean end() {\n        boolean ended = this.stopCount.decrementAndGet() <= 0;\n        if (ended)\n            this.endData = new Data();\n        return ended;\n    }\n\n    public String[] dump() {\n        List<String> dump = new ArrayList<>();\n\n        dump.add(\"Profiler #\" + this.id);\n        dump.add(\"  Type: \" + this.profileType.getPrettyName());\n        dump.add(\"  Time elapsed: \" + TimeUnit.NANOSECONDS.toMillis(this.endData.time - this.startData.time) + \"ms\");\n        dump.add(\"  TPS: \" + this.startData.tps + \" -> \" + this.endData.tps);\n\n        return dump.toArray(new String[0]);\n    }\n\n    public static class Data {\n\n\n        public final long time = System.nanoTime();\n        public final double tps = plugin.getNMSAlgorithms().getCurrentTps();\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.core.schematic;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.NumberTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.event.inventory.InventoryType;\n\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class SchematicBlock {\n\n    private static final ListTag EMPTY_LIST_TAG = ListTag.of(Collections.emptyList());\n    private static final Gson GSON = new Gson();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final Location location;\n    private final int blockId;\n    @Nullable\n    private final Extra extra;\n    @Nullable\n    private CompoundTag tileEntityData = null;\n\n    public SchematicBlock(Location location, int blockId, @Nullable Extra extra) {\n        this.location = location;\n        this.blockId = blockId;\n        this.extra = extra;\n    }\n\n    public int getX() {\n        return location.getBlockX();\n    }\n\n    public int getY() {\n        return location.getBlockY();\n    }\n\n    public int getZ() {\n        return location.getBlockZ();\n    }\n\n    public World getWorld() {\n        return location.getWorld();\n    }\n\n    public Location getLocation() {\n        return location;\n    }\n\n    public int getCombinedId() {\n        return this.blockId;\n    }\n\n    @Nullable\n    public CompoundTag getStatesTag() {\n        return this.extra == null ? null : this.extra.statesTag;\n    }\n\n    @Nullable\n    public CompoundTag getOriginalTileEntity() {\n        CompoundTag tileEntity = this.extra == null ? null : this.extra.tileEntity;\n        return tileEntity == null ? null : tileEntity.copy();\n    }\n\n    @Nullable\n    public CompoundTag getTileEntityData() {\n        return this.tileEntityData;\n    }\n\n    public void doPrePlace(Island island) {\n        CompoundTag originalTileEntity = getOriginalTileEntity();\n\n        if (originalTileEntity == null)\n            return;\n\n        this.tileEntityData = CompoundTag.fromNBT(originalTileEntity.toNBT());\n        String id = this.tileEntityData.getString(\"id\").orElse(null);\n\n        if (id == null) {\n            Log.warn(\"Weird tile-entity data detected: \" + this.tileEntityData.getValue());\n            throw new RuntimeException(\"Detected tile-entity data with no 'id' key.\");\n        }\n\n        if (isSignId(id)) {\n            if (this.tileEntityData.containsKey(\"front_text\")) {\n                backFrontSignLinesReplace(this.tileEntityData, island);\n            } else {\n                legacySignLinesReplace(this.tileEntityData, island);\n            }\n        } else if (plugin.getSettings().getDefaultContainers().isEnabled() && isChestId(id)) {\n            String inventoryType = this.tileEntityData.getString(\"inventoryType\").orElse(null);\n            if (inventoryType != null) {\n                try {\n                    InventoryType containerType = InventoryType.valueOf(inventoryType);\n                    ListTag items = plugin.getSettings().getDefaultContainers().getContents(containerType);\n                    if (items != null)\n                        this.tileEntityData.setTag(\"Items\", items.copy());\n                } catch (Exception ignored) {\n                }\n            }\n        }\n    }\n\n    public boolean shouldPostPlace() {\n        if (this.tileEntityData == null)\n            return false;\n\n        String id = this.tileEntityData.getString(\"id\").orElse(null);\n        return id != null && isSignId(id);\n    }\n\n    public void doPostPlace(Island island) {\n        try {\n            plugin.getNMSWorld().placeSign(island, location);\n        } finally {\n            this.tileEntityData = null;\n        }\n    }\n\n    private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island island) {\n        CompoundTag frontText = tileEntityData.getCompound(\"front_text\").orElse(null);\n        CompoundTag backText = tileEntityData.getCompound(\"back_text\").orElse(null);\n\n        if (frontText == null || backText == null) {\n            // This should never occur\n            Log.error(\"Invalid sign tile entity data: \", tileEntityData);\n        }\n\n        ListTag frontTextMessages = frontText.getList(\"messages\").orElse(EMPTY_LIST_TAG);\n        ListTag backTextMessages = backText.getList(\"messages\").orElse(EMPTY_LIST_TAG);\n        ListTag newFrontTextMessages = ListTag.of(StringTag.class);\n        ListTag newBackTextMessages = ListTag.of(StringTag.class);\n\n        for (int i = 0; i < 8; ++i) {\n            ListTag messages = i < 4 ? frontTextMessages : backTextMessages;\n            ListTag newMessages = i < 4 ? newFrontTextMessages : newBackTextMessages;\n\n            int realIndex = i % 4;\n\n            String line;\n            if (i < plugin.getSettings().getDefaultSign().size()) {\n                line = plugin.getSettings().getDefaultSign().get(i);\n            } else {\n                Tag<?> tag = messages.getValue().get(realIndex);\n                if (tag instanceof CompoundTag) {\n                    JsonObject jsonObject = new JsonObject();\n                    for (Map.Entry<String, Tag<?>> entry : ((CompoundTag) tag).entrySet()) {\n                        Tag<?> valueTag = entry.getValue();\n                        if (valueTag instanceof NumberTag) {\n                            // Booleans are parsed as NumberTag\n                            jsonObject.addProperty(entry.getKey(), ((NumberTag<?>) valueTag).getValue().intValue() == 1);\n                        } else {\n                            jsonObject.addProperty(entry.getKey(), String.valueOf(valueTag.getValue()));\n                        }\n                    }\n                    line = GSON.toJson(jsonObject);\n                } else {\n                    line = ((StringTag) tag).getValue();\n                }\n            }\n\n            line = parseSignPlaceholders(island, line);\n\n            newMessages.addTag(StringTag.of(line));\n        }\n\n        frontText.setTag(\"messages\", newFrontTextMessages);\n        backText.setTag(\"messages\", newBackTextMessages);\n    }\n\n    private static void legacySignLinesReplace(CompoundTag tileEntityData, Island island) {\n        boolean needSignFormat = false;\n\n        for (int i = 1; i <= 4; i++) {\n            boolean isDefaultSignLine = false;\n            String line;\n\n            if ((i - 1) >= plugin.getSettings().getDefaultSign().size()) {\n                line = tileEntityData.getString(\"Text\" + i).orElse(null);\n            } else {\n                line = plugin.getSettings().getDefaultSign().get(i - 1);\n                if (ServerVersion.isAtLeast(ServerVersion.v1_17)) {\n                    isDefaultSignLine = true;\n                    needSignFormat = true;\n                }\n            }\n\n            if (line != null) {\n                tileEntityData.setString((isDefaultSignLine ? \"SSB.Text\" : \"Text\") + i,\n                        parseSignPlaceholders(island, line));\n            }\n        }\n\n        if (needSignFormat)\n            tileEntityData.setByte(\"SSB.HasSignLines\", (byte) 1);\n    }\n\n    private static String parseSignPlaceholders(Island island, String val) {\n        return val.replace(\"{player}\", island.getOwner().getName())\n                .replace(\"{island}\", island.getName().isEmpty() ? island.getOwner().getName() : island.getName());\n    }\n\n    public SchematicBlock setLocation(Location newBlockLoc) {\n        return new SchematicBlock(newBlockLoc, this.blockId, this.extra);\n    }\n\n    private static boolean isSignId(String id) {\n        return id.equals(\"Sign\") || id.equals(\"minecraft:sign\") || id.equals(\"minecraft:hanging_sign\");\n    }\n\n    private static boolean isChestId(String id) {\n        return id.equals(\"Chest\") || id.equals(\"minecraft:chest\") || id.equals(\"minecraft:trapped_chest\");\n    }\n\n    public static class Extra {\n\n        @Nullable\n        private final CompoundTag statesTag;\n        @Nullable\n        private final CompoundTag tileEntity;\n\n        public Extra(@Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) {\n            this.statesTag = statesTag;\n            this.tileEntity = tileEntity;\n        }\n\n        public CompoundTag getTileEntity() {\n            return tileEntity;\n        }\n\n        public CompoundTag getStatesTag() {\n            return statesTag;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlockData.java",
    "content": "package com.bgsoftware.superiorskyblock.core.schematic;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\n\npublic class SchematicBlockData implements Comparable<SchematicBlockData> {\n\n    private final int combinedId;\n    private final BlockOffset blockOffset;\n    @Nullable\n    private final SchematicBlock.Extra extra;\n\n    public SchematicBlockData(int combinedId, BlockOffset blockOffset, @Nullable SchematicBlock.Extra extra) {\n        this.combinedId = combinedId;\n        this.blockOffset = blockOffset;\n        this.extra = extra;\n    }\n\n    public BlockOffset getBlockOffset() {\n        return blockOffset;\n    }\n\n    public int getCombinedId() {\n        return combinedId;\n    }\n\n    @Nullable\n    public SchematicBlock.Extra getExtra() {\n        return extra;\n    }\n\n    @Override\n    public int compareTo(@NotNull SchematicBlockData o) {\n        int levelCompare = Integer.compare(blockOffset.getOffsetY(), o.blockOffset.getOffsetY());\n        if (levelCompare != 0)\n            return levelCompare;\n        int xCoordCompare = Integer.compare(blockOffset.getOffsetX(), o.blockOffset.getOffsetX());\n        return xCoordCompare != 0 ? xCoordCompare : Integer.compare(blockOffset.getOffsetZ(), o.blockOffset.getOffsetZ());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicEntity.java",
    "content": "package com.bgsoftware.superiorskyblock.core.schematic;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Location;\nimport org.bukkit.entity.EntityType;\n\npublic class SchematicEntity {\n\n    private final static SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final EntityType entityType;\n    private final CompoundTag entityTag;\n    private final BlockOffset offset;\n\n    public SchematicEntity(EntityType entityType, CompoundTag entityTag, BlockOffset offset) {\n        this.entityType = entityType;\n        this.entityTag = SchematicEntityFilter.filterNBTTag(entityTag);\n        this.offset = offset;\n    }\n\n    public void spawnEntity(Location min) {\n        plugin.getNMSTags().spawnEntity(entityType, offset.applyToLocation(min), entityTag);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicEntityFilter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.schematic;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\n\npublic class SchematicEntityFilter {\n\n    private SchematicEntityFilter() {\n\n    }\n\n    public static CompoundTag filterNBTTag(@Nullable CompoundTag entityTag) {\n        if (entityTag != null) {\n            entityTag.remove(\"UUID\");\n            entityTag.remove(\"UUIDMost\");\n            entityTag.remove(\"UUIDLeast\");\n        }\n\n        return entityTag;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/ISerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\n\npublic interface ISerializer<S, D> {\n\n    @NotNull\n    D serialize(@Nullable S serializable);\n\n    @Nullable\n    S deserialize(@Nullable D deserializable);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization;\n\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.BlockPositionSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.InventorySerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStack2TagSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStackSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.LocationSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.OffsetSerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.impl.WorldPositionSerializer;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\n\npublic class Serializers {\n\n    public static final ISerializer<ItemStack[], byte[]> INVENTORY_SERIALIZER = InventorySerializer.getInstance();\n    public static final ISerializer<ItemStack, String> ITEM_STACK_SERIALIZER = ItemStackSerializer.getInstance();\n    public static final ISerializer<ItemStack, CompoundTag> ITEM_STACK_TO_TAG_SERIALIZER = ItemStack2TagSerializer.getInstance();\n    public static final ISerializer<Location, String> LOCATION_SPACED_CENTERED_SERIALIZER = new LocationSerializer(\", \", true);\n    public static final ISerializer<Location, String> LOCATION_SPACED_SERIALIZER = new LocationSerializer(\", \");\n    public static final ISerializer<Location, String> LOCATION_SERIALIZER = new LocationSerializer(\",\");\n    public static final ISerializer<BlockPosition, String> BLOCK_POSITION_SERIALIZER = BlockPositionSerializer.getInstance();\n    public static final ISerializer<WorldPosition, String> WORLD_POSITION_SERIALIZER = WorldPositionSerializer.getInstance();\n    public static final ISerializer<BlockOffset, String> OFFSET_SPACED_SERIALIZER = new OffsetSerializer(\", \");\n    public static final ISerializer<BlockOffset, String> OFFSET_SERIALIZER = new OffsetSerializer(\",\");\n\n    private Serializers() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\n\npublic class BlockPositionSerializer implements ISerializer<BlockPosition, String> {\n\n    private static final BlockPositionSerializer INSTANCE = new BlockPositionSerializer();\n\n    public static BlockPositionSerializer getInstance() {\n        return INSTANCE;\n    }\n\n    private BlockPositionSerializer() {\n    }\n\n    @NotNull\n    @Override\n    public String serialize(@Nullable BlockPosition serializable) {\n        return serializable == null ? \"\" :\n                serializable.getX() + \", \" + serializable.getY() + \", \" + serializable.getZ();\n    }\n\n    @Nullable\n    @Override\n    public BlockPosition deserialize(@Nullable String element) {\n        if (Text.isBlank(element))\n            return null;\n\n        try {\n            String[] sections = element.split(\", \");\n\n            int startIndex = 0;\n            if (sections.length >= 4) {\n                // In the past, BlockPositions were serialized with a world, yaw and pitch.\n                // Nowadays, we ignore all of them.\n                ++startIndex;\n            }\n\n            int x = (int) Double.parseDouble(sections[startIndex++]);\n            int y = (int) Double.parseDouble(sections[startIndex++]);\n            int z = (int) Double.parseDouble(sections[startIndex]);\n\n            return SBlockPosition.of(x, y, z);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", element);\n            Log.error(error, \"An unexpected error occurred while deserializing position '\" + element + \"':\");\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport org.bukkit.Material;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class InventorySerializer implements ISerializer<ItemStack[], byte[]> {\n\n    private static final ItemStack[] EMPTY_CONTENTS = new ItemStack[0];\n    private static final byte[] EMPTY_SERIALIZED_DATA = new byte[0];\n    private static final byte[] EMPTY_SLOTS = new byte[0];\n    private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList());\n\n    private static final InventorySerializer INSTANCE = new InventorySerializer();\n\n    public static InventorySerializer getInstance() {\n        return INSTANCE;\n    }\n\n    private InventorySerializer() {\n    }\n\n    @NotNull\n    @Override\n    public byte[] serialize(@Nullable ItemStack[] serializable) {\n        if (serializable == null || serializable.length == 0)\n            return EMPTY_SERIALIZED_DATA;\n\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        DataOutputStream dataOutput = new DataOutputStream(outputStream);\n\n        CompoundTag compoundTag = CompoundTag.of();\n\n        List<ItemStack> serializedItems = new ArrayList<>(serializable.length);\n        byte[] slots = new byte[serializable.length * 2];\n\n        for (int i = 0; i < serializable.length; ++i) {\n            ItemStack itemStack = serializable[i];\n            int itemIndex = i * 2;\n\n            if (itemStack == null || itemStack.getType() == Material.AIR) {\n                slots[itemIndex] = -1;\n                slots[itemIndex + 1] = 0;\n            } else {\n                ItemStack serializedItem = getSerializedItem(itemStack);\n                int similarItemIndex = serializedItems.indexOf(serializedItem);\n                if (similarItemIndex == -1) {\n                    slots[itemIndex] = (byte) serializedItems.size();\n                    serializedItems.add(serializedItem);\n                } else {\n                    slots[itemIndex] = (byte) similarItemIndex;\n                }\n\n                slots[itemIndex + 1] = (byte) itemStack.getAmount();\n            }\n        }\n\n        ListTag items = ListTag.of(CompoundTag.class);\n        for (ItemStack itemStack : serializedItems)\n            items.addTag(Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack));\n\n        compoundTag.setTag(\"Items\", items);\n        compoundTag.setByteArray(\"Slots\", slots);\n\n        try {\n            compoundTag.write(dataOutput);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", Arrays.asList(serializable));\n            Log.error(error, \"An unexpected error occurred while serializing inventory:\");\n            return EMPTY_SERIALIZED_DATA;\n        }\n\n        return outputStream.toByteArray();\n    }\n\n    @Override\n    public ItemStack[] deserialize(@Nullable byte[] deserializable) {\n        if (deserializable == null || deserializable.length == 0)\n            return EMPTY_CONTENTS;\n\n        return deserialize(deserializable, true);\n    }\n\n    private static ItemStack[] deserialize(byte[] deserializable, boolean tryAgain) {\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(deserializable);\n        CompoundTag compoundTag;\n\n        try {\n            compoundTag = (CompoundTag) Tag.fromStream(new DataInputStream(inputStream), 0);\n        } catch (Exception error) {\n            if (tryAgain)\n                return deserialize(new BigInteger(new String(deserializable), 32).toByteArray(), false);\n\n            Log.entering(\"ENTER\", new String(deserializable));\n            Log.error(error, \"An unexpected error occurred while deserializing inventory:\");\n            return EMPTY_CONTENTS;\n        }\n\n        ItemStack[] contents;\n\n        if (compoundTag.containsKey(\"Length\")) {\n            contents = new ItemStack[compoundTag.getInt(\"Length\").orElse(0)];\n\n            for (int i = 0; i < contents.length; i++) {\n                CompoundTag itemCompound = compoundTag.getCompound(i + \"\").orElse(null);\n                if (itemCompound != null)\n                    contents[i] = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemCompound);\n            }\n        } else {\n            byte[] slots = compoundTag.getByteArray(\"Slots\").orElse(EMPTY_SLOTS);\n            ListTag items = compoundTag.getList(\"Items\").orElse(EMPTY_ITEMS_LIST);\n            ItemStack[] serializedItems = new ItemStack[items.size()];\n\n            contents = new ItemStack[slots.length / 2];\n\n            for (int i = 0; i < slots.length; i += 2) {\n                int itemIndex = slots[i];\n\n                if (itemIndex == -1 || itemIndex >= serializedItems.length)\n                    continue;\n\n                int itemAmount = slots[i + 1];\n\n                if (serializedItems[itemIndex] == null) {\n                    Tag<?> itemTag = items.getValue().get(itemIndex);\n                    if (itemTag instanceof CompoundTag) {\n                        serializedItems[itemIndex] = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) itemTag);\n                    } else {\n                        serializedItems[itemIndex] = new ItemStack(Material.AIR);\n                    }\n                }\n\n                ItemStack contentItem = serializedItems[itemIndex].clone();\n                contentItem.setAmount(itemAmount);\n\n                contents[i / 2] = contentItem;\n            }\n\n        }\n\n        return contents;\n    }\n\n    private static ItemStack getSerializedItem(ItemStack itemStack) {\n        ItemStack serializedItem = itemStack.clone();\n        serializedItem.setAmount(1);\n        return serializedItem;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Material;\nimport org.bukkit.inventory.ItemStack;\n\npublic class ItemStack2TagSerializer implements ISerializer<ItemStack, CompoundTag> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final ItemStack2TagSerializer INSTANCE = new ItemStack2TagSerializer();\n\n    public static ItemStack2TagSerializer getInstance() {\n        return INSTANCE;\n    }\n\n    private ItemStack2TagSerializer() {\n    }\n\n    @Override\n    @NotNull\n    public CompoundTag serialize(@Nullable ItemStack serializable) {\n        if (serializable == null)\n            return CompoundTag.of();\n\n        return plugin.getNMSTags().serializeItem(serializable);\n    }\n\n    @Nullable\n    @Override\n    public ItemStack deserialize(@Nullable CompoundTag deserializable) {\n        if (deserializable == null)\n            return new ItemStack(Material.AIR);\n\n        return plugin.getNMSTags().deserializeItem(deserializable);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStackSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.math.BigInteger;\n\npublic class ItemStackSerializer implements ISerializer<ItemStack, String> {\n\n    private static final ItemStackSerializer INSTANCE = new ItemStackSerializer();\n\n    public static ItemStackSerializer getInstance() {\n        return INSTANCE;\n    }\n\n    private ItemStackSerializer() {\n    }\n\n    @NotNull\n    @Override\n    public String serialize(@Nullable ItemStack serializable) {\n        if (serializable == null)\n            return \"\";\n\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        DataOutputStream dataOutput = new DataOutputStream(outputStream);\n\n        try {\n            Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(serializable).write(dataOutput);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", serializable);\n            Log.error(error, \"An unexpected error occurred while serializing item:\");\n            return \"\";\n        }\n\n        return new BigInteger(1, outputStream.toByteArray()).toString(32);\n    }\n\n    @Nullable\n    @Override\n    public ItemStack deserialize(@Nullable String deserializable) {\n        if (Text.isBlank(deserializable))\n            return null;\n\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(deserializable, 32).toByteArray());\n\n        try {\n            CompoundTag compoundTag = (CompoundTag) Tag.fromStream(new DataInputStream(inputStream), 0);\n            return Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(compoundTag);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", deserializable);\n            Log.error(error, \"An unexpected error occurred while deserializing item:\");\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\nimport org.bukkit.Location;\n\npublic class LocationSerializer implements ISerializer<Location, String> {\n\n    private final String separator;\n    private final boolean center;\n\n    public LocationSerializer(String separator) {\n        this.separator = separator;\n        this.center = false;\n    }\n\n    public LocationSerializer(String separator, boolean center) {\n        this.separator = separator;\n        this.center = center;\n    }\n\n    @NotNull\n    @Override\n    public String serialize(@Nullable Location serializable) {\n        return serializable == null ? \"\" : LazyWorldLocation.getWorldName(serializable) + separator +\n                serializable.getX() + separator +\n                serializable.getY() + separator +\n                serializable.getZ() + separator +\n                serializable.getYaw() + separator +\n                serializable.getPitch();\n    }\n\n    @Nullable\n    @Override\n    public Location deserialize(@Nullable String element) {\n        if (Text.isBlank(element))\n            return null;\n\n        try {\n            String[] sections = element.split(separator);\n\n            double x = Double.parseDouble(sections[1]);\n            if (center && !sections[1].contains(\".\")) x += 0.5;\n\n            double y = Double.parseDouble(sections[2]);\n\n            double z = Double.parseDouble(sections[3]);\n            if (center && !sections[3].contains(\".\")) z += 0.5;\n\n            float yaw = sections.length > 5 ? Float.parseFloat(sections[4]) : 0;\n            float pitch = sections.length > 6 ? Float.parseFloat(sections[5]) : 0;\n\n            return new LazyWorldLocation(sections[0], x, y, z, yaw, pitch);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", element);\n            Log.error(error, \"An unexpected error occurred while deserializing location '\" + element + \"':\");\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/OffsetSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\n\npublic class OffsetSerializer implements ISerializer<BlockOffset, String> {\n\n    private final String separator;\n\n    public OffsetSerializer(String separator) {\n        this.separator = separator;\n    }\n\n    @NotNull\n    @Override\n    public String serialize(@Nullable BlockOffset serializable) {\n        return serializable == null ? \"\" : serializable.getOffsetX() + separator + serializable.getOffsetY() + separator + serializable.getOffsetZ();\n    }\n\n    @Nullable\n    @Override\n    public BlockOffset deserialize(@Nullable String element) {\n        if (Text.isBlank(element))\n            return null;\n\n        String[] stringSections = element.split(separator);\n\n        if (stringSections.length != 3)\n            return null;\n\n        try {\n            return SBlockOffset.fromOffsets(Integer.parseInt(stringSections[0]), Integer.parseInt(stringSections[1]), Integer.parseInt(stringSections[2]));\n        } catch (NumberFormatException error) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/PersistentDataSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\n\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class PersistentDataSerializer implements ISerializer<Object, String> {\n\n    private static final Pattern BYTE_VALUE = Pattern.compile(\"^([0-9]+)b$\");\n    private static final Pattern DOUBLE_VALUE = Pattern.compile(\"^([0-9.]+)d$\");\n    private static final Pattern FLOAT_VALUE = Pattern.compile(\"^([0-9]+)f$\");\n    private static final Pattern INT_VALUE = Pattern.compile(\"^([0-9]+)i$\");\n    private static final Pattern LONG_VALUE = Pattern.compile(\"^([0-9]+)l$\");\n    private static final Pattern SHORT_VALUE = Pattern.compile(\"^([0-9]+)s$\");\n\n    private final Locale locale;\n\n    public PersistentDataSerializer(Locale locale) {\n        this.locale = locale;\n    }\n\n    @Override\n    public @NotNull String serialize(@Nullable Object serializable) {\n        if (serializable == null)\n            return \"\";\n\n        String result;\n\n        if (serializable instanceof Byte) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"b\");\n        } else if (serializable instanceof Double) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"d\");\n        } else if (serializable instanceof Float) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"f\");\n        } else if (serializable instanceof Integer) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"i\");\n        } else if (serializable instanceof Long) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"l\");\n        } else if (serializable instanceof Short) {\n            result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"s\");\n        } else {\n            result = \"\\\"\" + Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, \"\") + \"\\\"\";\n        }\n\n        return result == null ? \"\" : result;\n    }\n\n    @Nullable\n    @Override\n    public Object deserialize(@Nullable String deserializable) {\n        if (deserializable == null)\n            return null;\n\n        Matcher matcher;\n\n        if ((matcher = BYTE_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Byte.parseByte(matcher.group(1)), PersistentDataType.BYTE);\n        } else if ((matcher = DOUBLE_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Double.parseDouble(matcher.group(1)), PersistentDataType.DOUBLE);\n        } else if ((matcher = FLOAT_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Float.parseFloat(matcher.group(1)), PersistentDataType.FLOAT);\n        } else if ((matcher = INT_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Integer.parseInt(matcher.group(1)), PersistentDataType.INTEGER);\n        } else if ((matcher = LONG_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Long.parseLong(matcher.group(1)), PersistentDataType.LONG);\n        } else if ((matcher = SHORT_VALUE.matcher(deserializable)).matches()) {\n            return new Pair<>(Short.parseShort(matcher.group(1)), PersistentDataType.SHORT);\n        }\n\n        return new Pair<>(deserializable, PersistentDataType.STRING);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.serialization.impl;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.ISerializer;\n\npublic class WorldPositionSerializer implements ISerializer<WorldPosition, String> {\n\n    private static final WorldPositionSerializer INSTANCE = new WorldPositionSerializer();\n\n    public static WorldPositionSerializer getInstance() {\n        return INSTANCE;\n    }\n\n    private WorldPositionSerializer() {\n    }\n\n    @NotNull\n    @Override\n    public String serialize(@Nullable WorldPosition serializable) {\n        return serializable == null ? \"\" :\n                serializable.getX() + \",\" + serializable.getY() + \",\" + serializable.getZ() +\n                        \",\" + serializable.getYaw() + \",\" + serializable.getPitch();\n    }\n\n    @Nullable\n    @Override\n    public WorldPosition deserialize(@Nullable String element) {\n        if (Text.isBlank(element))\n            return null;\n\n        try {\n            String[] sections = element.split(\",\");\n\n            int startIndex = 0;\n            if (sections.length >= 6) {\n                // In the past, WorldPositions were serialized with a world.\n                // Nowadays, we ignore all of them.\n                ++startIndex;\n            }\n\n            double x = Double.parseDouble(sections[startIndex++]);\n            double y = Double.parseDouble(sections[startIndex++]);\n            double z = Double.parseDouble(sections[startIndex++]);\n            float yaw = Float.parseFloat(sections[startIndex++]);\n            float pitch = Float.parseFloat(sections[startIndex]);\n\n            return SWorldPosition.of(x, y, z, yaw, pitch);\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", element);\n            Log.error(error, \"An unexpected error occurred while deserializing position '\" + element + \"':\");\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\npublic class StackedBlock {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<HologramsService> hologramsService = new LazyReference<HologramsService>() {\n        @Override\n        protected HologramsService create() {\n            return plugin.getServices().getService(HologramsService.class);\n        }\n    };\n\n    private final LazyWorldLocation location;\n\n    private int amount;\n    private Key blockKey;\n    private Hologram hologram;\n    private boolean removed;\n\n    public StackedBlock(Location location) {\n        this.location = LazyWorldLocation.of(location);\n    }\n\n    public LazyWorldLocation getLocation() {\n        return location;\n    }\n\n    public int getAmount() {\n        return amount;\n    }\n\n    public void setAmount(int amount) {\n        this.amount = amount;\n    }\n\n    public Key getBlockKey() {\n        return blockKey;\n    }\n\n    public void setBlockKey(Key blockKey) {\n        this.blockKey = blockKey;\n    }\n\n    public void markAsRemoved() {\n        removed = true;\n        removeHologram();\n    }\n\n    public void updateName() {\n        if (this.removed || this.amount <= 1) {\n            removeHologram();\n            return;\n        }\n\n        World world = this.location.getWorld();\n        if (world == null)\n            return;\n\n        Key currentBlockKey = Keys.of(location.getBlock());\n\n        if (blockKey == null || blockKey.equals(ConstantKeys.AIR)) {\n            blockKey = currentBlockKey;\n            if (blockKey.equals(ConstantKeys.AIR))\n                return;\n        }\n\n        // Must be checked in order to fix issue #632\n        if (!currentBlockKey.equals(blockKey)) {\n            removeHologram();\n            return;\n        }\n\n        if (hologram == null) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location location = copyLocation(wrapper.getHandle()).add(0.5, 1, 0.5);\n                hologram = hologramsService.get().createHologram(location);\n            }\n        }\n\n        hologram.setHologramName(plugin.getSettings().getStackedBlocks().getCustomName()\n                .replace(\"{0}\", String.valueOf(amount))\n                .replace(\"{1}\", Formatters.CAPITALIZED_FORMATTER.format(blockKey.getGlobalKey()))\n                .replace(\"{2}\", Formatters.NUMBER_FORMATTER.format(amount))\n        );\n    }\n\n    public void removeHologram() {\n        if (hologram != null) {\n            hologram.removeHologram();\n            hologram = null;\n        }\n    }\n\n    private Location copyLocation(Location location) {\n        location.setX(this.location.getX());\n        location.setY(this.location.getY());\n        location.setZ(this.location.getZ());\n        location.setYaw(this.location.getYaw());\n        location.setPitch(this.location.getPitch());\n        location.setWorld(this.location.getWorld());\n        return location;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.StackedBlocksDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.container.StackedBlocksContainer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\n\npublic class StackedBlocksManagerImpl extends Manager implements StackedBlocksManager {\n\n    private final StackedBlocksContainer stackedBlocksContainer;\n    private DatabaseBridge databaseBridge;\n\n    public StackedBlocksManagerImpl(SuperiorSkyblockPlugin plugin, StackedBlocksContainer stackedBlocksContainer) {\n        super(plugin);\n        this.stackedBlocksContainer = stackedBlocksContainer;\n    }\n\n    @Override\n    public void loadData() {\n        initializeDatabaseBridge();\n\n        Log.info(\"Starting to load stacked blocks...\");\n\n        AtomicBoolean updateBlockKeys = new AtomicBoolean(false);\n\n        databaseBridge.loadAllObjects(\"stacked_blocks\", _resultSet -> {\n            DatabaseResult resultSet = new DatabaseResult(_resultSet);\n            loadStackedBlock(resultSet);\n            Optional<String> item = resultSet.getString(\"block_type\");\n            if (!item.isPresent() || item.get().isEmpty())\n                updateBlockKeys.set(true);\n        });\n\n        if (updateBlockKeys.get()) {\n            BukkitExecutor.sync(this::updateStackedBlockKeys);\n        }\n\n        Log.info(\"Finished stacked blocks!\");\n    }\n\n    @Override\n    public int getStackedBlockAmount(Block block) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return getStackedBlockAmount(block.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    @Override\n    public int getStackedBlockAmount(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n        StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location);\n        return stackedBlock == null ? 1 : stackedBlock.getAmount();\n    }\n\n    @Override\n    public Key getStackedBlockKey(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n        StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location);\n        return stackedBlock == null ? null : stackedBlock.getBlockKey();\n    }\n\n    @Override\n    public boolean setStackedBlock(Block block, int amount) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return setStackedBlock(block.getLocation(wrapper.getHandle()), Keys.of(block), amount);\n        }\n    }\n\n    @Override\n    public boolean setStackedBlock(Location location, Key blockKey, int amount) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n        Preconditions.checkNotNull(blockKey, \"blockKey parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BLOCK_AMOUNT, location, blockKey, amount);\n\n        StackedBlock stackedBlock = this.stackedBlocksContainer.createStackedBlock(location);\n\n        boolean succeed = true;\n\n        if (stackedBlock.getBlockKey() != null && !blockKey.equals(stackedBlock.getBlockKey())) {\n            Log.warn(\"Found a glitched stacked-block at \", Formatters.LOCATION_FORMATTER.format(location), \" - fixing it...\");\n            amount = 0;\n            succeed = false;\n        }\n\n        if (amount > 1) {\n            stackedBlock.setBlockKey(blockKey);\n            stackedBlock.setAmount(amount);\n            // Must be called with delay in order to fix issue #632\n            BukkitExecutor.sync(stackedBlock::updateName, 2L);\n            StackedBlocksDatabaseBridge.saveStackedBlock(this, stackedBlock);\n        } else {\n            this.stackedBlocksContainer.removeStackedBlock(location);\n            StackedBlocksDatabaseBridge.deleteStackedBlock(this, stackedBlock);\n        }\n\n        return succeed;\n    }\n\n    @Override\n    public int removeStackedBlock(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n\n        StackedBlock oldStackedBlock = this.stackedBlocksContainer.removeStackedBlock(location);\n\n        if (oldStackedBlock != null) {\n            StackedBlocksDatabaseBridge.deleteStackedBlock(this, oldStackedBlock);\n        }\n\n        return oldStackedBlock == null ? 1 : oldStackedBlock.getAmount();\n    }\n\n    @Override\n    public Map<Location, Integer> removeStackedBlocks(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk parameter cannot be null.\");\n        return removeStackedBlocks(chunk.getWorld(), chunk.getX(), chunk.getZ());\n    }\n\n    @Override\n    public Map<Location, Integer> removeStackedBlocks(World world, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) {\n            return removeStackedBlocks(chunkPosition);\n        }\n    }\n\n    public Map<Location, Integer> removeStackedBlocks(ChunkPosition chunkPosition) {\n        Preconditions.checkNotNull(chunkPosition, \"chunkPosition parameter cannot be null.\");\n\n        Map<Location, Integer> removedStackedBlocks = new LinkedHashMap<>();\n\n        try {\n            databaseBridge.batchOperations(true);\n            this.stackedBlocksContainer.removeStackedBlocks(chunkPosition, stackedBlock -> {\n                removedStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount());\n                stackedBlock.removeHologram();\n                StackedBlocksDatabaseBridge.deleteStackedBlock(this, stackedBlock);\n            });\n        } finally {\n            databaseBridge.batchOperations(false);\n        }\n\n        return removedStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(removedStackedBlocks);\n    }\n\n    @Override\n    public Map<Location, Integer> getStackedBlocks(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk parameter cannot be null.\");\n        return getStackedBlocks(chunk.getWorld(), chunk.getX(), chunk.getZ());\n    }\n\n    @Override\n    public Map<Location, Integer> getStackedBlocks(World world, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        Map<Location, Integer> chunkStackedBlocks = new LinkedHashMap<>();\n\n        try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) {\n            this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> {\n                chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount());\n            });\n        }\n\n        return chunkStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(chunkStackedBlocks);\n    }\n\n    @Override\n    public Map<Location, Integer> getStackedBlocks() {\n        Map<Location, Integer> allStackedBlocks = new LinkedHashMap<>();\n        this.stackedBlocksContainer.forEach(stackedBlock -> {\n            allStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount());\n        });\n        return allStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(allStackedBlocks);\n    }\n\n    public boolean hasStackedBlocks() {\n        return this.stackedBlocksContainer.size() > 0;\n    }\n\n    @Override\n    public void updateStackedBlockHologram(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n\n        StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location);\n        if (stackedBlock != null) {\n            stackedBlock.updateName();\n            if (stackedBlock.getAmount() <= 1)\n                removeStackedBlock(location);\n        }\n    }\n\n    @Override\n    public void updateStackedBlockHolograms(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk parameter cannot be null.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n            this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> {\n                stackedBlock.updateName();\n                if (stackedBlock.getAmount() <= 1)\n                    removeStackedBlock(stackedBlock.getLocation());\n            });\n        }\n    }\n\n    @Override\n    public void removeStackedBlockHologram(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n\n        StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location);\n        if (stackedBlock != null) {\n            stackedBlock.removeHologram();\n        }\n    }\n\n    @Override\n    public void removeStackedBlockHolograms(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk parameter cannot be null.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n            this.stackedBlocksContainer.forEach(chunkPosition, StackedBlock::removeHologram);\n        }\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return databaseBridge;\n    }\n\n    public void forEach(ChunkPosition chunkPosition, Consumer<StackedBlock> consumer) {\n        this.stackedBlocksContainer.forEach(chunkPosition, consumer);\n    }\n\n    private void loadStackedBlock(DatabaseResult resultSet) {\n        Optional<Location> location = resultSet.getString(\"location\").map(Serializers.LOCATION_SPACED_SERIALIZER::deserialize);\n        if (!location.isPresent()) {\n            Log.warn(\"Cannot load stacked block from null location, skipping...\");\n            return;\n        }\n\n        if (!(plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider)) {\n            if (location.get().getWorld() == null) {\n                Log.warn(\"Cannot load stacked block with invalid world \",\n                        LazyWorldLocation.getWorldName(location.get()), \", skipping...\");\n                return;\n            }\n        }\n\n        Optional<Integer> amount = resultSet.getInt(\"amount\");\n        if (!amount.isPresent()) {\n            Log.warn(\"Cannot load stacked block from null amount, skipping...\");\n            return;\n        }\n\n        Optional<String> item = resultSet.getString(\"block_type\");\n\n        Key blockKey;\n        if (!item.isPresent() || item.get().isEmpty()) {\n            blockKey = null;\n        } else {\n            String itemValue = item.get();\n            Location blockLocation = location.get();\n            blockKey = Keys.of(Key.class, new LazyReference<Key>() {\n\n                private final Key baseKey = Keys.ofMaterialAndData(itemValue);\n                private final Location keyLocation = blockLocation;\n\n                @Override\n                protected Key create() {\n                    return Keys.of(this.baseKey, this.keyLocation);\n                }\n            });\n        }\n\n        try {\n            StackedBlock stackedBlock = this.stackedBlocksContainer.createStackedBlock(location.get());\n            stackedBlock.setAmount(amount.get());\n            stackedBlock.setBlockKey(blockKey);\n        } catch (IllegalArgumentException error) {\n            Log.error(error);\n        }\n    }\n\n    private void updateStackedBlockKeys() {\n        this.stackedBlocksContainer.forEach(stackedBlock ->\n                stackedBlock.setBlockKey(Keys.of(stackedBlock.getLocation().getBlock())));\n    }\n\n    private void initializeDatabaseBridge() {\n        databaseBridge = plugin.getFactory().createDatabaseBridge(this);\n        databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stackedblocks.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock;\nimport org.bukkit.Location;\n\nimport java.util.function.Consumer;\n\npublic class DefaultStackedBlocksContainer implements StackedBlocksContainer {\n\n    private final Location2ObjectMap<StackedBlock> stackedBlocks = new Location2ObjectMap<>();\n\n    @Nullable\n    @Override\n    public StackedBlock getStackedBlock(Location location) {\n        return this.stackedBlocks.get(location);\n    }\n\n    @Override\n    public StackedBlock createStackedBlock(Location location) {\n        StackedBlock stackedBlock = new StackedBlock(location);\n        StackedBlock oldStackedBlock = this.stackedBlocks.put(location, stackedBlock);\n        if (oldStackedBlock != null)\n            oldStackedBlock.markAsRemoved();\n        return stackedBlock;\n    }\n\n    @Override\n    public StackedBlock removeStackedBlock(Location location) {\n        StackedBlock removedStackedBlock = this.stackedBlocks.remove(location);\n        if (removedStackedBlock != null)\n            removedStackedBlock.markAsRemoved();\n        return removedStackedBlock;\n    }\n\n    @Override\n    public void forEach(ChunkPosition chunkPosition, Consumer<StackedBlock> consumer) {\n        this.stackedBlocks.forEach(chunkPosition, consumer);\n    }\n\n    @Override\n    public void forEach(Consumer<StackedBlock> consumer) {\n        this.stackedBlocks.values().forEach(consumer);\n    }\n\n    @Override\n    public void removeStackedBlocks(ChunkPosition chunkPosition, Consumer<StackedBlock> consumer) {\n        this.stackedBlocks.removeAll(chunkPosition, stackedBlock -> {\n            stackedBlock.markAsRemoved();\n            consumer.accept(stackedBlock);\n        });\n    }\n\n    @Override\n    public int size() {\n        return this.stackedBlocks.size();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/StackedBlocksContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stackedblocks.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock;\nimport org.bukkit.Location;\n\nimport java.util.function.Consumer;\n\npublic interface StackedBlocksContainer {\n\n    @Nullable\n    StackedBlock getStackedBlock(Location location);\n\n    StackedBlock createStackedBlock(Location location);\n\n    StackedBlock removeStackedBlock(Location location);\n\n    void forEach(ChunkPosition chunkPosition, Consumer<StackedBlock> consumer);\n\n    void forEach(Consumer<StackedBlock> consumer);\n\n    void removeStackedBlocks(ChunkPosition chunkPosition, Consumer<StackedBlock> consumer);\n\n    int size();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/IStatsCollector.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.google.gson.JsonObject;\n\npublic interface IStatsCollector {\n\n    void collect(JsonObject statsObject);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsClient.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.util.concurrent.ThreadFactoryBuilder;\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport org.bukkit.Bukkit;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.URL;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\npublic class StatsClient {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Gson GSON = new Gson();\n\n    private static final int VERSION = 1;\n    private static final long TASK_DELAY = 1;\n    private static final byte MINIMUM_ONLINE_PLAYERS = 10;\n    private static final List<IStatsCollector> STATS_COLLECTORS = new LinkedList<>();\n\n    private static final String API_ENDPOINT = \"https://api.bg-software.com/v1/stats/\";\n\n    private static StatsClient INSTANCE;\n\n    static {\n        STATS_COLLECTORS.add(StatsIslandsCounter.INSTANCE);\n        STATS_COLLECTORS.add(StatsPlayersCounter.INSTANCE);\n        STATS_COLLECTORS.add(StatsProfilers.INSTANCE);\n        STATS_COLLECTORS.add(StatsSchematicsSizes.INSTANCE);\n    }\n\n    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder()\n            .setNameFormat(\"SuperiorSkyblock Stats\").build());\n\n    private ScheduledFuture<?> scheduledTask;\n\n    private StatsClient() {\n\n    }\n\n    public void start() {\n        this.scheduledTask = scheduler.scheduleAtFixedRate(this::collectStatsTask, 1, TASK_DELAY, TimeUnit.MINUTES);\n    }\n\n    public void shutdown() {\n        if (this.scheduledTask != null) {\n            this.scheduledTask.cancel(true);\n            this.scheduledTask = null;\n        }\n\n        if (!this.scheduler.isShutdown())\n            this.scheduler.shutdownNow();\n    }\n\n    private void collectStatsTask() {\n        UUID serverUUID = plugin.getGrid().getServerUUID();\n        if (serverUUID == null) {\n            shutdown();\n            return;\n        }\n\n        if (Bukkit.getOnlinePlayers().size() < MINIMUM_ONLINE_PLAYERS)\n            return;\n\n        try {\n            JsonObject statsObject = new JsonObject();\n            STATS_COLLECTORS.forEach(collector -> collector.collect(statsObject));\n            submitStats(statsObject, serverUUID);\n        } catch (Exception error) {\n            Log.error(error, \"An error occurred while uploading stats:\");\n        }\n    }\n\n    private void submitStats(JsonObject statsObject, UUID serverUUID) throws IOException {\n        if (statsObject.entrySet().isEmpty())\n            return;\n\n        statsObject.addProperty(\"version\", VERSION);\n        statsObject.addProperty(\"server\", serverUUID.toString());\n\n        HttpsURLConnection conn = (HttpsURLConnection) new URL(API_ENDPOINT).openConnection();\n        conn.setRequestMethod(\"POST\");\n        conn.setRequestProperty(\"Content-Type\", \"application/json\");\n        conn.setDoOutput(true);\n\n        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()))) {\n            writer.write(GSON.toJson(statsObject));\n        }\n\n        int statusCode = conn.getResponseCode();\n        if (statusCode != 200)\n            throw new RuntimeException(\"Received error code when submitting stats: \" + statusCode);\n\n        JsonObject response;\n\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {\n            response = GSON.fromJson(reader.readLine(), JsonObject.class);\n        }\n\n        if (response.has(\"error\"))\n            throw new RuntimeException(\"Received error when submitting stats: \" + response.get(\"error\").getAsString());\n\n        if (!response.has(\"status\"))\n            throw new RuntimeException(\"Received invalid response when submitting stats: \" + response);\n\n        String status = response.get(\"status\").getAsString();\n        if (!status.equalsIgnoreCase(\"success\"))\n            throw new RuntimeException(\"Received invalid status when submitting stats: \" + status);\n    }\n\n    public static StatsClient getInstance() {\n        if (INSTANCE == null)\n            INSTANCE = new StatsClient();\n\n        return INSTANCE;\n    }\n\n    public static Optional<StatsClient> getIfExists() {\n        return Optional.ofNullable(INSTANCE);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsIslandsCounter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.google.gson.JsonObject;\n\npublic class StatsIslandsCounter implements IStatsCollector {\n\n    public static final StatsIslandsCounter INSTANCE = new StatsIslandsCounter();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private int lastIslandsCount = 0;\n\n    private StatsIslandsCounter() {\n\n    }\n\n    @Override\n    public void collect(JsonObject statsObject) {\n        int currentIslandsCount = plugin.getGrid().getIslands().size();\n        if (currentIslandsCount != this.lastIslandsCount) {\n            statsObject.addProperty(\"islands_count\", currentIslandsCount);\n            this.lastIslandsCount = currentIslandsCount;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsPlayersCounter.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.google.gson.JsonObject;\nimport org.bukkit.Bukkit;\n\npublic class StatsPlayersCounter implements IStatsCollector {\n\n    public static final StatsPlayersCounter INSTANCE = new StatsPlayersCounter();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private int lastAllPlayers;\n\n    private StatsPlayersCounter() {\n\n    }\n\n    @Override\n    public void collect(JsonObject statsObject) {\n        statsObject.addProperty(\"online_players\", Bukkit.getOnlinePlayers().size());\n\n        int currentAllPlayers = plugin.getPlayers().getAllPlayers().size();\n        if (currentAllPlayers != this.lastAllPlayers) {\n            statsObject.addProperty(\"all_players\", currentAllPlayers);\n            this.lastAllPlayers = currentAllPlayers;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsProfilers.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfilerSession;\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\npublic class StatsProfilers implements IStatsCollector {\n\n    public static final StatsProfilers INSTANCE = new StatsProfilers();\n\n    private final List<ProfilerSession> collectedProfilers = new LinkedList<>();\n\n    private StatsProfilers() {\n\n    }\n\n    public void submitProfiler(ProfilerSession session) {\n        synchronized (this) {\n            collectedProfilers.add(session);\n        }\n    }\n\n    @Override\n    public void collect(JsonObject statsObject) {\n        List<ProfilerSession> collectedProfilers;\n\n        synchronized (this) {\n            if (this.collectedProfilers.isEmpty())\n                return;\n\n            collectedProfilers = new LinkedList<>(this.collectedProfilers);\n            this.collectedProfilers.clear();\n        }\n\n        JsonArray profilers = new JsonArray();\n\n        collectedProfilers.forEach(session -> {\n            JsonObject profiler = new JsonObject();\n            profiler.addProperty(\"type\", session.getProfileType().name());\n            profiler.addProperty(\"time_elapsed\",\n                    TimeUnit.NANOSECONDS.toMillis(session.getEndData().time - session.getStartData().time));\n            profiler.addProperty(\"start_tps\", session.getStartData().tps);\n            profiler.addProperty(\"end_tps\", session.getEndData().tps);\n            Object extra = session.getExtra();\n            if (extra != null)\n                profiler.addProperty(\"extra\", String.valueOf(extra));\n            profilers.add(profiler);\n        });\n\n        statsObject.add(\"profilers\", profilers);\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsSchematicsSizes.java",
    "content": "package com.bgsoftware.superiorskyblock.core.stats;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableLong;\nimport com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic;\nimport com.google.gson.JsonObject;\n\nimport java.util.List;\n\npublic class StatsSchematicsSizes implements IStatsCollector {\n\n    public static final StatsSchematicsSizes INSTANCE = new StatsSchematicsSizes();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private boolean collected = false;\n\n    private StatsSchematicsSizes() {\n\n    }\n\n    @Override\n    public void collect(JsonObject statsObject) {\n        if (collected)\n            return;\n\n        collected = true;\n\n        List<String> schematicNames = plugin.getSchematics().getSchematics();\n        if (schematicNames.isEmpty())\n            return;\n\n        JsonObject schematics = new JsonObject();\n\n        schematicNames.forEach(schematicName -> {\n            Schematic schematic = plugin.getSchematics().getSchematic(schematicName);\n            if (schematic instanceof SuperiorSchematic) {\n                MutableLong blocksCount = new MutableLong(0);\n                schematic.getBlockCounts().values().forEach(count -> blocksCount.set(blocksCount.get() + count));\n                if (blocksCount.get() > 0)\n                    schematics.addProperty(schematicName, blocksCount.get());\n            }\n        });\n\n        statsObject.add(\"schematics\", schematics);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/task/CalcTask.java",
    "content": "package com.bgsoftware.superiorskyblock.core.task;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport org.bukkit.scheduler.BukkitRunnable;\nimport org.bukkit.scheduler.BukkitTask;\n\npublic class CalcTask extends BukkitRunnable {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static BukkitTask calcTask;\n\n    private CalcTask() {\n        calcTask = runTaskTimerAsynchronously(plugin, plugin.getSettings().getCalcInterval(), plugin.getSettings().getCalcInterval());\n    }\n\n    public static void startTask() {\n        cancelTask();\n        if (plugin.getSettings().getCalcInterval() > 0)\n            new CalcTask();\n    }\n\n    public static void cancelTask() {\n        if (calcTask != null) {\n            calcTask.cancel();\n            calcTask = null;\n        }\n    }\n\n    @Override\n    public void run() {\n        if (Bukkit.getOnlinePlayers().size() > 0) {\n            announceToPlayers(false);\n            announceToOps(\"&7&o[SuperiorSkyblock] Calculating islands...\");\n            plugin.getGrid().calcAllIslands(() -> {\n                announceToPlayers(true);\n                announceToOps(\"&7&o[SuperiorSkyblock] Calculating islands done!\");\n            });\n        }\n    }\n\n    private void announceToOps(String message) {\n        for (Player player : Bukkit.getOnlinePlayers()) {\n            if (player.isOp())\n                Message.CUSTOM.send(player, message, true);\n        }\n        Message.CUSTOM.send(Bukkit.getConsoleSender(), message, true);\n    }\n\n    private void announceToPlayers(boolean done) {\n        for (Player player : Bukkit.getOnlinePlayers()) {\n            if (done) {\n                Message.RECALC_ALL_ISLANDS_DONE.send(player);\n            } else {\n                Message.RECALC_ALL_ISLANDS.send(player);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/task/ShutdownTask.java",
    "content": "package com.bgsoftware.superiorskyblock.core.task;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\npublic class ShutdownTask extends Thread {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public ShutdownTask(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void run() {\n        if (!plugin.getGrid().wasPluginDisabled()) {\n            Log.error(\"Detected crash. SuperiorSkyblock will attempt to save data...\");\n            plugin.onDisable();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java",
    "content": "package com.bgsoftware.superiorskyblock.core.threads;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Bukkit;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class BukkitExecutor {\n\n    private static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 20;\n    private static final int SHUTDOWN_INTERVAL_WAIT_TIME = 100;\n\n    private static SuperiorSkyblockPlugin plugin;\n    private static State state = State.RUNNING;\n\n    private static final AtomicLong ACTIVE_TASKS_COUNT = new AtomicLong(0);\n\n    private BukkitExecutor() {\n\n    }\n\n    public static void init(SuperiorSkyblockPlugin plugin) {\n        BukkitExecutor.plugin = plugin;\n    }\n\n    @Nullable\n    public static BukkitTask ensureMain(Runnable runnable) {\n        if (ensureNotShudown())\n            return null;\n\n        if (state != State.PREPARE_SHUTDOWN && !Bukkit.isPrimaryThread()) {\n            return sync(runnable);\n        } else {\n            runnable.run();\n            return null;\n        }\n    }\n\n    @Nullable\n    public static BukkitTask ensureAsync(Runnable runnable) {\n        if (ensureNotShudown())\n            return null;\n\n        if (state != State.PREPARE_SHUTDOWN && Bukkit.isPrimaryThread()) {\n            return async(runnable);\n        } else {\n            runnable.run();\n            return null;\n        }\n    }\n\n    public static BukkitTask sync(Runnable runnable) {\n        return sync(runnable, 0);\n    }\n\n    public static BukkitTask sync(Runnable runnable, long delay) {\n        if (ensureNotShudown())\n            return null;\n\n        if (state == State.PREPARE_SHUTDOWN) {\n            runnable.run();\n            return null;\n        } else {\n            return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay);\n        }\n    }\n\n    public static BukkitTask async(Runnable runnable) {\n        if (ensureNotShudown())\n            return null;\n\n        if (state == State.PREPARE_SHUTDOWN) {\n            runnable.run();\n            return null;\n        } else {\n            return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable);\n        }\n    }\n\n    public static BukkitTask async(Runnable runnable, long delay) {\n        if (ensureNotShudown())\n            return null;\n\n        if (state == State.PREPARE_SHUTDOWN) {\n            runnable.run();\n            return null;\n        } else {\n            return Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay);\n        }\n    }\n\n    public static void asyncTimer(Runnable runnable, long delay) {\n        if (ensureNotShudown())\n            return;\n\n        Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, delay);\n    }\n\n    public static void timer(Runnable runnable, long delay) {\n        if (ensureNotShudown())\n            return;\n\n        Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, delay);\n    }\n\n    public static NestedTask<Void> createTask() {\n        return new NestedTask<Void>().complete();\n    }\n\n    public static void prepareShutdown() {\n        state = State.PREPARE_SHUTDOWN;\n    }\n\n    public static void close(SuperiorSkyblockPlugin plugin) {\n        // Waiting for all active tasks to finish\n\n        Log.info(\"This can take up to \" + (DEFAULT_SHUTDOWN_TIMEOUT / 1000) + \" seconds to complete\");\n\n        long timeoutLeft = DEFAULT_SHUTDOWN_TIMEOUT;\n\n        while (ACTIVE_TASKS_COUNT.get() != 0 && timeoutLeft > 0) {\n            try {\n                Thread.sleep(SHUTDOWN_INTERVAL_WAIT_TIME);\n                timeoutLeft -= SHUTDOWN_INTERVAL_WAIT_TIME;\n            } catch (Throwable ignored) {\n            }\n        }\n\n        if (ACTIVE_TASKS_COUNT.get() != 0) {\n            new RuntimeException(\"Not all active tasks finished\").printStackTrace();\n        }\n\n        state = State.SHUTDOWN;\n        Bukkit.getScheduler().cancelTasks(plugin);\n    }\n\n    private static boolean ensureNotShudown() {\n        if (state == State.SHUTDOWN) {\n            new RuntimeException(\"Tried to call BukkitExecutor after it was shut down\").printStackTrace();\n            return true;\n        }\n\n        return false;\n    }\n\n    public static class NestedTask<T> {\n\n        private final CompletableFuture<T> value = new CompletableFuture<>();\n\n        NestedTask() {\n        }\n\n        public <R> NestedTask<R> runSync(Function<T, R> function) {\n            ensureNotShudown();\n\n            NestedTask<R> nestedTask = new NestedTask<>();\n            if (state == State.PREPARE_SHUTDOWN) {\n                nestedTask.value.complete(function.apply(value.join()));\n            } else {\n                onCreate();\n                value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> {\n                    try {\n                        nestedTask.value.complete(function.apply(value));\n                    } finally {\n                        onComplete();\n                    }\n                }));\n            }\n            return nestedTask;\n        }\n\n        public NestedTask<Void> runSync(Consumer<T> consumer) {\n            ensureNotShudown();\n\n            NestedTask<Void> nestedTask = new NestedTask<>();\n            if (state == State.PREPARE_SHUTDOWN) {\n                consumer.accept(value.join());\n                nestedTask.value.complete(null);\n            } else {\n                onCreate();\n                value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> {\n                    try {\n                        consumer.accept(value);\n                        nestedTask.value.complete(null);\n                    } finally {\n                        onComplete();\n                    }\n                }));\n            }\n            return nestedTask;\n        }\n\n        public <R> NestedTask<R> runAsync(Function<T, R> function) {\n            ensureNotShudown();\n\n            NestedTask<R> nestedTask = new NestedTask<>();\n            if (state == State.PREPARE_SHUTDOWN) {\n                nestedTask.value.complete(function.apply(value.join()));\n            } else {\n                onCreate();\n                value.whenComplete((value, ex) -> BukkitExecutor.async(() -> {\n                    try {\n                        nestedTask.value.complete(function.apply(value));\n                    } finally {\n                        onComplete();\n                    }\n                }));\n            }\n            return nestedTask;\n        }\n\n        public NestedTask<Void> runAsync(Consumer<T> consumer) {\n            ensureNotShudown();\n\n            NestedTask<Void> nestedTask = new NestedTask<>();\n            if (state == State.PREPARE_SHUTDOWN) {\n                consumer.accept(value.join());\n                nestedTask.value.complete(null);\n            } else {\n                onCreate();\n                value.whenComplete((value, ex) -> BukkitExecutor.async(() -> {\n                    try {\n                        consumer.accept(value);\n                        nestedTask.value.complete(null);\n                    } finally {\n                        onComplete();\n                    }\n                }));\n            }\n            return nestedTask;\n        }\n\n        private NestedTask<T> complete() {\n            value.complete(null);\n            return this;\n        }\n\n        private static void onCreate() {\n            long curr = ACTIVE_TASKS_COUNT.incrementAndGet();\n            Log.debug(Debug.TRACK_TASK, curr);\n        }\n\n        private static void onComplete() {\n            long curr = ACTIVE_TASKS_COUNT.decrementAndGet();\n            Log.debug(Debug.TRACK_TASK, curr);\n            if (curr < 0) {\n                new RuntimeException(\"Active tasks count is less than 0\").printStackTrace();\n                ACTIVE_TASKS_COUNT.set(0);\n            }\n        }\n\n    }\n\n    private enum State {\n\n        RUNNING,\n        PREPARE_SHUTDOWN,\n        SHUTDOWN\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/threads/Synchronized.java",
    "content": "package com.bgsoftware.superiorskyblock.core.threads;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class Synchronized<T> {\n\n    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();\n    private T value;\n\n    Synchronized(T value) {\n        this.value = value;\n    }\n\n    public static <T> Synchronized<T> of(T value) {\n        return new Synchronized<>(value);\n    }\n\n    public T get() {\n        if (value instanceof Map)\n            throw new UnsupportedOperationException(\"Cannot get raw maps from synced objects.\");\n\n        if (value instanceof Collection)\n            throw new UnsupportedOperationException(\"Cannot get raw collections from synced objects.\");\n\n        try {\n            lock.readLock().lock();\n            return value;\n        } finally {\n            lock.readLock().unlock();\n        }\n    }\n\n    public T set(T value) {\n        try {\n            lock.writeLock().lock();\n            T oldValue = this.value;\n            this.value = value;\n            return oldValue;\n        } finally {\n            lock.writeLock().unlock();\n        }\n    }\n\n    public void set(Function<T, T> function) {\n        try {\n            lock.writeLock().lock();\n            this.value = function.apply(value);\n        } finally {\n            lock.writeLock().unlock();\n        }\n    }\n\n    public void read(Consumer<T> consumer) {\n        try {\n            lock.readLock().lock();\n            consumer.accept(value);\n        } finally {\n            lock.readLock().unlock();\n        }\n    }\n\n    public <R> R readAndGet(Function<T, R> function) {\n        try {\n            lock.readLock().lock();\n            return function.apply(value);\n        } finally {\n            lock.readLock().unlock();\n        }\n    }\n\n    public void write(Consumer<T> consumer) {\n        try {\n            lock.writeLock().lock();\n            consumer.accept(value);\n        } finally {\n            lock.writeLock().unlock();\n        }\n    }\n\n    public <R> R writeAndGet(Function<T, R> function) {\n        try {\n            lock.writeLock().lock();\n            return function.apply(value);\n        } finally {\n            lock.writeLock().unlock();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java",
    "content": "package com.bgsoftware.superiorskyblock.core.threads;\n\nimport javax.annotation.Nullable;\nimport java.util.concurrent.CountDownLatch;\n\npublic class SynchronizedTasks {\n\n    @Nullable\n    private final CountDownLatch countDownLatch;\n    @Nullable\n    private final Runnable onFinishCallback;\n\n    public SynchronizedTasks(int count, @Nullable Runnable onFinishCallback) {\n        this.countDownLatch = count <= 0 ? null : new CountDownLatch(count);\n        this.onFinishCallback = onFinishCallback;\n    }\n\n    public void notifyTaskComplete() {\n        if (this.countDownLatch != null)\n            this.countDownLatch.countDown();\n    }\n\n    public void waitAllAsync() {\n        BukkitExecutor.ensureAsync(this::waitAllAsyncInternal);\n    }\n\n    private void waitAllAsyncInternal() {\n        if (this.countDownLatch != null) {\n            try {\n                this.countDownLatch.await();\n            } catch (InterruptedException error) {\n                throw new RuntimeException(error);\n            }\n        }\n\n        if (this.onFinishCallback != null)\n            this.onFinishCallback.run();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValue.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.function.DoubleSupplier;\n\npublic interface DoubleValue {\n\n    static DoubleValue fixed(double value) {\n        return DoubleValueFixed.of(value);\n    }\n\n    static DoubleValue syncedFixed(double value) {\n        return DoubleValueFixedSynced.of(value);\n    }\n\n    static DoubleValue syncedSupplied(DoubleSupplier supplier) {\n        return DoubleValueSuppliedSynced.of(supplier);\n    }\n\n    static double getNonSynced(@Nullable DoubleValue value, double syncedValue) {\n        return value == null ? syncedValue : value.getNonSynced(syncedValue);\n    }\n\n    double get();\n\n    boolean isSynced();\n\n    default double getNonSynced(double syncedValue) {\n        return isSynced() ? syncedValue : get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueFixed.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class DoubleValueFixed implements DoubleValue {\n\n    private static final ValuesCache<DoubleValueFixed> CACHE = new ValuesCache<>(DoubleValueFixed::new);\n\n    private final double value;\n\n    public static DoubleValueFixed of(double value) {\n        return value == (int) value ? CACHE.fetch((int) value) : new DoubleValueFixed(value);\n    }\n\n    private DoubleValueFixed(double value) {\n        this.value = value;\n    }\n\n    @Override\n    public double get() {\n        return this.value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueFixedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class DoubleValueFixedSynced implements DoubleValue {\n\n    private static final ValuesCache<DoubleValueFixedSynced> CACHE = new ValuesCache<>(DoubleValueFixedSynced::new);\n\n    private final double value;\n\n    public static DoubleValueFixedSynced of(double value) {\n        return value == (int) value ? CACHE.fetch((int) value) : new DoubleValueFixedSynced(value);\n    }\n\n    private DoubleValueFixedSynced(double value) {\n        this.value = value;\n    }\n\n    @Override\n    public double get() {\n        return value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueSuppliedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport java.util.function.DoubleSupplier;\n\npublic class DoubleValueSuppliedSynced implements DoubleValue {\n\n    private final DoubleSupplier supplier;\n\n    public static DoubleValueSuppliedSynced of(DoubleSupplier supplier) {\n        return new DoubleValueSuppliedSynced(supplier);\n    }\n\n    private DoubleValueSuppliedSynced(DoubleSupplier supplier) {\n        this.supplier = supplier;\n    }\n\n    @Override\n    public double get() {\n        return supplier.getAsDouble();\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValue.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.Map;\nimport java.util.function.IntSupplier;\nimport java.util.stream.Collectors;\n\npublic interface IntValue {\n\n    static IntValue fixed(int value) {\n        return IntValueFixed.of(value);\n    }\n\n    static IntValue syncedFixed(int value) {\n        return IntValueFixedSynced.of(value);\n    }\n\n    static IntValue syncedSupplied(IntSupplier supplier) {\n        return IntValueSuppliedSynced.of(supplier);\n    }\n\n    static <K> Map<K, Integer> unboxMap(Map<K, IntValue> input) {\n        return input.entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> entry.getValue().get()\n        ));\n    }\n\n    static int getNonSynced(@Nullable IntValue value, int syncedValue) {\n        return value == null ? syncedValue : value.getNonSynced(syncedValue);\n    }\n\n    int get();\n\n    boolean isSynced();\n\n    default int getNonSynced(int syncedValue) {\n        return isSynced() ? syncedValue : get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueFixed.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class IntValueFixed implements IntValue {\n\n    private static final ValuesCache<IntValueFixed> CACHE = new ValuesCache<>(IntValueFixed::new);\n\n    private final int value;\n\n    public static IntValueFixed of(int value) {\n        return CACHE.fetch(value);\n    }\n\n    private IntValueFixed(int value) {\n        this.value = value;\n    }\n\n    public int get() {\n        return this.value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueFixedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class IntValueFixedSynced implements IntValue {\n\n    private static final ValuesCache<IntValueFixedSynced> CACHE = new ValuesCache<>(IntValueFixedSynced::new);\n\n    private final int value;\n\n    public static IntValueFixedSynced of(int value) {\n        return CACHE.fetch(value);\n    }\n\n    private IntValueFixedSynced(int value) {\n        this.value = value;\n    }\n\n    @Override\n    public int get() {\n        return value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueSuppliedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport java.util.function.IntSupplier;\n\npublic class IntValueSuppliedSynced implements IntValue {\n\n    private final IntSupplier supplier;\n\n    public static IntValueSuppliedSynced of(IntSupplier supplier) {\n        return new IntValueSuppliedSynced(supplier);\n    }\n\n    private IntValueSuppliedSynced(IntSupplier supplier) {\n        this.supplier = supplier;\n    }\n\n    @Override\n    public int get() {\n        return supplier.getAsInt();\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport com.bgsoftware.common.annotations.Nullable;\n\nimport java.util.function.Supplier;\n\npublic interface Value<V> {\n\n    static <V> Value<V> fixed(V value) {\n        return new ValueFixed<>(value);\n    }\n\n    static <V> Value<V> syncedSupplied(Supplier<V> supplier) {\n        return new ValueSuppliedSynced<>(supplier);\n    }\n\n    static <V> Value<V> syncedFixed(V value) {\n        return new ValueFixedSynced<>(value);\n    }\n\n    static <V> V getNonSynced(@Nullable Value<V> value, V syncedValue) {\n        return value == null ? syncedValue : value.getNonSynced(syncedValue);\n    }\n\n    V get();\n\n    boolean isSynced();\n\n    default V getNonSynced(V syncedValue) {\n        return isSynced() ? syncedValue : get();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class ValueFixed<V> implements Value<V> {\n\n    private final V value;\n\n    ValueFixed(V value) {\n        this.value = value;\n    }\n\n    @Override\n    public V get() {\n        return value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\npublic class ValueFixedSynced<V> implements Value<V> {\n\n    private final V value;\n\n    ValueFixedSynced(V value) {\n        this.value = value;\n    }\n\n    @Override\n    public V get() {\n        return value;\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport java.util.function.Supplier;\n\npublic class ValueSuppliedSynced<V> implements Value<V> {\n\n    private final Supplier<V> supplier;\n\n    ValueSuppliedSynced(Supplier<V> supplier) {\n        this.supplier = supplier;\n    }\n\n    @Override\n    public V get() {\n        return supplier.get();\n    }\n\n    @Override\n    public boolean isSynced() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/value/ValuesCache.java",
    "content": "package com.bgsoftware.superiorskyblock.core.value;\n\nimport java.util.Objects;\nimport java.util.function.IntFunction;\n\npublic class ValuesCache<T> {\n\n    private static final int CACHE_SIZE = 32;\n\n    private final int[] indexes = new int[CACHE_SIZE];\n    private final Object[] cache = new Object[CACHE_SIZE];\n    private int capacity = 0;\n\n    private final IntFunction<T> creator;\n\n\n    public ValuesCache(IntFunction<T> creator) {\n        this.creator = creator;\n    }\n\n    public T fetch(int value) {\n        for (int i = 0; i < this.capacity; ++i) {\n            if (this.indexes[i] == value) {\n                return Objects.requireNonNull((T) this.cache[i]);\n            }\n        }\n\n        T cachedValue = this.creator.apply(value);\n        if (cachedValue != null && this.capacity < CACHE_SIZE) {\n            this.indexes[this.capacity] = value;\n            this.cache[this.capacity] = cachedValue;\n\n            ++this.capacity;\n        }\n\n        return cachedValue;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValue.java",
    "content": "package com.bgsoftware.superiorskyblock.core.values;\n\nimport javax.annotation.Nullable;\nimport java.math.BigDecimal;\n\npublic class BlockValue {\n\n    public static final BlockValue ZERO = new BlockValue(null, null);\n\n    @Nullable\n    private final BigDecimal worth;\n    @Nullable\n    private final BigDecimal level;\n\n    private static boolean isZero(@Nullable BigDecimal value) {\n        return value == null || value.compareTo(BigDecimal.ZERO) == 0;\n    }\n\n    public static BlockValue ofWorth(@Nullable BigDecimal worth) {\n        return ofWorthAndLevel(worth, null);\n    }\n\n    public static BlockValue ofLevel(@Nullable BigDecimal level) {\n        return ofWorthAndLevel(null, level);\n    }\n\n    public static BlockValue ofWorthAndLevel(@Nullable BigDecimal worth, @Nullable BigDecimal level) {\n        return isZero(worth) && isZero(level) ? ZERO : new BlockValue(worth, level);\n    }\n\n    private BlockValue(@Nullable BigDecimal worth, @Nullable BigDecimal level) {\n        this.worth = worth;\n        this.level = level;\n    }\n\n    public BigDecimal getWorth() {\n        return this.worth == null ? BigDecimal.ZERO : this.worth;\n    }\n\n    public boolean hasWorth() {\n        return this.worth != null;\n    }\n\n    public BlockValue setWorth(@Nullable BigDecimal worth) {\n        return ofWorthAndLevel(worth, this.level);\n    }\n\n    public BigDecimal getLevel() {\n        return this.level == null ? BigDecimal.ZERO : this.level;\n    }\n\n    public boolean hasLevel() {\n        return this.level != null;\n    }\n\n    public BlockValue setLevel(@Nullable BigDecimal level) {\n        return ofWorthAndLevel(this.worth, level);\n    }\n\n    @Override\n    public String toString() {\n        return \"BlockValue{\" +\n                \"worth=\" + worth +\n                \", level=\" + level +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.core.values;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager;\nimport com.bgsoftware.superiorskyblock.api.key.CustomKeyParser;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer;\nimport com.google.common.base.Preconditions;\nimport com.google.common.collect.ImmutableMap;\nimport org.bukkit.Location;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.inventory.ItemStack;\n\nimport javax.script.Bindings;\nimport javax.script.ScriptException;\nimport javax.script.SimpleBindings;\nimport java.io.File;\nimport java.math.BigDecimal;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\npublic class BlockValuesManagerImpl extends Manager implements BlockValuesManager {\n\n    private static final Map<String, BigDecimal> CACHED_BIG_DECIMALS;\n\n    static {\n        ImmutableMap.Builder<String, BigDecimal> mapBuilder = new ImmutableMap.Builder<>();\n        mapBuilder.put(\"\", BigDecimal.ZERO);\n\n        for (int i = 0; i < 10; ++i) {\n            mapBuilder.put(i + \"\", BigDecimal.valueOf(i));\n        }\n\n        for (int i = 10; i < 100; i *= 10) {\n            mapBuilder.put(i + \"\", BigDecimal.valueOf(i));\n        }\n\n        for (int i = 100; i <= 1000; i *= 100) {\n            mapBuilder.put(i + \"\", BigDecimal.valueOf(i));\n        }\n\n        CACHED_BIG_DECIMALS = mapBuilder.build();\n    }\n\n    private static final Bindings bindings = createBindings();\n\n    private static final KeyMap<CustomKeyParser> customKeyParsers = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n    private static final KeySet valuesMenuBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL);\n    private static final KeySet customBlockKeys = KeySets.createHashSet(KeyIndicator.MATERIAL);\n\n    private final BlockValuesContainer blockValuesContainer;\n    private final BlockValuesContainer customValuesContainer;\n\n    public BlockValuesManagerImpl(SuperiorSkyblockPlugin plugin,\n                                  BlockValuesContainer blockValuesContainer,\n                                  BlockValuesContainer customValuesContainer) {\n        super(plugin);\n        this.blockValuesContainer = blockValuesContainer;\n        this.customValuesContainer = customValuesContainer;\n    }\n\n    private static Bindings createBindings() {\n        SimpleBindings bindings = new SimpleBindings();\n        bindings.put(\"Math\", Math.class);\n        return bindings;\n    }\n\n    @Override\n    public void loadData() {\n        this.blockValuesContainer.clear();\n        this.customValuesContainer.clear();\n\n        loadDefaultValues();\n        plugin.getProviders().addPricesLoadCallback(this::convertWorthValuesToLevels);\n    }\n\n    @Override\n    public BigDecimal getBlockWorth(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return getBlockValue(key, true).getWorth();\n    }\n\n    @Override\n    public BigDecimal getBlockLevel(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return getBlockValue(key, false).getLevel();\n    }\n\n    public BlockValue getBlockValue(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return getBlockValue(key, true);\n    }\n\n    private BlockValue getBlockValue(Key key, boolean checkPrices) {\n        Log.debug(Debug.GET_VALUE, key);\n\n        BlockValue customBlockValue = customValuesContainer.getBlockValue(key);\n        if (customBlockValue != null) {\n            Log.debugResult(Debug.GET_VALUE, \"Return Custom Block Value\", customBlockValue);\n            return customBlockValue;\n        }\n\n        if (checkPrices) {\n            if (blockValuesContainer.containsKeyRaw(key)) {\n                BlockValue value = blockValuesContainer.getBlockValue(key);\n\n                if (value != null) {\n                    Log.debugResult(Debug.GET_VALUE, \"Return File\", value);\n                    return value;\n                }\n            }\n\n            if (plugin.getSettings().getSyncWorth() != SyncWorthStatus.NONE) {\n                BigDecimal price = plugin.getProviders().getPricesProvider().getPrice(key);\n                if (price.compareTo(BigDecimal.ZERO) >= 0) {\n                    BlockValue blockValue = BlockValue.ofWorth(price);\n                    Log.debugResult(Debug.GET_VALUE, \"Return Price\", blockValue);\n                    return blockValue;\n                }\n            }\n        }\n\n        BlockValue value = blockValuesContainer.getBlockValue(key);\n\n        if (value != null) {\n            Log.debugResult(Debug.GET_VALUE, \"Return File\", value);\n            return value;\n        }\n\n        Log.debugResult(Debug.GET_VALUE, \"Return File\", 0);\n\n        return BlockValue.ZERO;\n    }\n\n    @Override\n    public Key getBlockKey(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        if (isValuesMenu(key)) {\n            return markAsAPIIfNeeded(key, getValuesKey(key));\n        }\n\n        if (blockValuesContainer.containsKeyRaw(key)) {\n            return key;\n        }\n\n        if (plugin.getSettings().getSyncWorth() != SyncWorthStatus.NONE) {\n            Key newKey = plugin.getProviders().getPricesProvider().getBlockKey(key);\n            if (newKey != null) {\n                return markAsAPIIfNeeded(key, newKey);\n            }\n        }\n\n        Key blockValuesKey = blockValuesContainer.getBlockValueKey(key);\n        if (blockValuesKey != key)\n            return markAsAPIIfNeeded(key, blockValuesKey);\n\n        return markAsAPIIfNeeded(key, customBlockKeys.getKey(key, key));\n    }\n\n    private Key markAsAPIIfNeeded(Key original, Key newKey) {\n        if (original != newKey && ((BaseKey<?>) original).isAPIKey())\n            newKey = ((BaseKey<?>) newKey).markAPIKey();\n\n        return newKey;\n    }\n\n    @Override\n    public void registerCustomKey(Key key, @Nullable BigDecimal worthValue, @Nullable BigDecimal levelValue) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        if (!customValuesContainer.containsKey(key)) {\n            customValuesContainer.setBlockValue(key, BlockValue.ofWorthAndLevel(worthValue, levelValue));\n        }\n    }\n\n    @Override\n    public void registerKeyParser(CustomKeyParser customKeyParser, Key... blockTypes) {\n        Preconditions.checkNotNull(customKeyParser, \"customKeyParser parameter cannot be null.\");\n        Preconditions.checkNotNull(blockTypes, \"blockTypes parameter cannot be null.\");\n\n        for (Key blockType : blockTypes)\n            customKeyParsers.put(blockType, customKeyParser);\n    }\n\n    public void registerMenuValueBlocks(KeySet blocks) {\n        valuesMenuBlocks.addAll(blocks);\n    }\n\n    public boolean isValuesMenu(Key key) {\n        return valuesMenuBlocks.contains(key);\n    }\n\n    public Key getValuesKey(Key key) {\n        return valuesMenuBlocks.getKey(key, key);\n    }\n\n    public void addCustomBlockKey(Key key) {\n        customBlockKeys.add(key);\n    }\n\n    public void addCustomBlockKeys(Collection<Key> blocks) {\n        customBlockKeys.addAll(blocks);\n    }\n\n    public Key convertKey(Key original, Location location) {\n        CustomKeyParser customKeyParser = customKeyParsers.get(original);\n\n        if (customKeyParser == null)\n            return original;\n\n        Key key = customKeyParser.getCustomKey(location);\n\n        return key == null ? original : key;\n    }\n\n    public Key convertKey(Key original, ItemStack itemStack) {\n        CustomKeyParser customKeyParser = customKeyParsers.get(original);\n\n        if (customKeyParser == null)\n            return original;\n\n        return customKeyParser.getCustomKey(itemStack, original);\n    }\n\n    public Key convertKey(Key original, Entity entity) {\n        CustomKeyParser customKeyParser = customKeyParsers.get(original);\n\n        if (customKeyParser == null)\n            return original;\n\n        Key key = customKeyParser.getCustomKey(entity);\n\n        return key == null ? original : key;\n    }\n\n    @Nullable\n    public Pair<Key, ItemStack> convertCustomKeyItem(Key original) {\n        for (Map.Entry<Key, CustomKeyParser> entry : customKeyParsers.entrySet()) {\n            if (entry.getValue().isCustomKey(original)) {\n                return new Pair<>(entry.getKey(), entry.getValue().getCustomKeyItem(original));\n            }\n        }\n\n        return new Pair<>(original, null);\n    }\n\n    private BigDecimal convertWorthToLevel(BigDecimal value) {\n        // If the formula contains no mathematical operations or the placeholder for the worth value,\n        // we can directly create the BigDecimal instance from it.\n        try {\n            return fastBigDecimalFromString(plugin.getSettings().getIslandLevelFormula());\n        } catch (NumberFormatException ignored) {\n        }\n\n        try {\n            Object evaluated = plugin.getScriptEngine().eval(plugin.getSettings().getIslandLevelFormula()\n                    .replace(\"{}\", value.toString()), bindings);\n\n            // Checking for division by 0\n            if (evaluated.equals(Double.POSITIVE_INFINITY) || evaluated.equals(Double.NEGATIVE_INFINITY))\n                return BigDecimal.ZERO;\n\n            return fastBigDecimalFromString(evaluated.toString());\n        } catch (ScriptException error) {\n            Log.entering(\"ENTER\", value);\n            Log.error(error, \"An unexpected error occurred while converting level from worth:\");\n            return value;\n        }\n    }\n\n    private void convertWorthValuesToLevels() {\n        blockValuesContainer.forEach((blockKey, blockCount) -> {\n            BlockValue realBlockValue = blockValuesContainer.getBlockValue(blockKey);\n            if (realBlockValue != null && !realBlockValue.hasLevel()) {\n                BlockValue newBlockValue = realBlockValue.setLevel(convertWorthToLevel(realBlockValue.getWorth()));\n                blockValuesContainer.setBlockValue(blockKey, newBlockValue);\n            }\n        });\n    }\n\n    private void loadDefaultValues() {\n        // First, convert old file\n        File blockValuesFile = new File(plugin.getDataFolder(), \"blockvalues.yml\");\n        if (blockValuesFile.exists()) {\n            File worthFile = new File(\"block-values/worth.yml\");\n            if (!worthFile.getParentFile().mkdirs() || !blockValuesFile.renameTo(worthFile))\n                Log.error(\"Failed to convert old block values to the new format.\");\n        }\n\n        // Load level and worth values\n        loadValuesFromFile(\"block-values/worth.yml\", (key, worth) -> {\n            blockValuesContainer.setBlockValue(key, BlockValue.ofWorth(worth));\n        });\n\n        loadValuesFromFile(\"block-values/levels.yml\", (key, level) -> {\n            BlockValue currValue = blockValuesContainer.getBlockValue(key);\n            BlockValue newValue = currValue == null ? BlockValue.ofLevel(level) : currValue.setLevel(level);\n            blockValuesContainer.setBlockValue(key, newValue);\n        });\n    }\n\n    private void loadValuesFromFile(String fileName, BiConsumer<Key, BigDecimal> consumer) {\n        File file = new File(plugin.getDataFolder(), fileName);\n\n        if (!file.exists())\n            plugin.saveResource(fileName, true);\n\n        YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file);\n\n        ConfigurationSection valuesSection = cfg.isConfigurationSection(\"block-values\") ?\n                cfg.getConfigurationSection(\"block-values\") :\n                cfg.getConfigurationSection(\"\");\n\n        for (String key : valuesSection.getKeys(false)) {\n            String value = valuesSection.getString(key);\n            try {\n                consumer.accept(Keys.ofMaterialAndData(key), new BigDecimal(value));\n            } catch (Exception ex) {\n                Log.warnFromFile(\"levels.yml\", \"Cannot parse value for \", key, \" in file \", fileName, \", skipping...\");\n            }\n        }\n\n    }\n\n    private static BigDecimal fastBigDecimalFromString(String value) {\n        return CACHED_BIG_DECIMALS.getOrDefault(value, new BigDecimal(value));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.core.values.container;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\n\nimport javax.annotation.Nullable;\nimport java.util.function.BiConsumer;\n\npublic class BlockValuesContainer {\n\n    private final KeyMap<BlockValue> valuesMap = KeyMaps.createHashMap(KeyIndicator.MATERIAL);\n\n    public void setBlockValue(Key key, BlockValue value) {\n        valuesMap.put(key, value);\n    }\n\n    @Nullable\n    public BlockValue getBlockValue(Key key) {\n        return valuesMap.get(key);\n    }\n\n    public boolean containsKeyRaw(Key key) {\n        return valuesMap.getKey(key) == key;\n    }\n\n    public boolean containsKey(Key key) {\n        return valuesMap.containsKey(key);\n    }\n\n    public Key getBlockValueKey(Key key) {\n        return valuesMap.getKey(key, key);\n    }\n\n    public void forEach(BiConsumer<Key, BlockValue> consumer) {\n        valuesMap.forEach(consumer);\n    }\n\n    public void clear() {\n        valuesMap.clear();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.external;\n\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.common.shopsbridge.ShopsProvider;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.AFKProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.MenusProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.PricesProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersSnapshotProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksSnapshotProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.ISkinsListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldsListener;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.JavaVersion;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.external.async.AsyncProvider;\nimport com.bgsoftware.superiorskyblock.external.async.AsyncProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider;\nimport com.bgsoftware.superiorskyblock.external.chunks.ChunksProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.economy.EconomyProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.menus.MenusProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.permissions.PermissionsProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider;\nimport com.bgsoftware.superiorskyblock.external.prices.PricesProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.prices.PricesProvider_ShopsBridgeWrapper;\nimport com.bgsoftware.superiorskyblock.external.spawners.SpawnersProvider_AutoDetect;\nimport com.bgsoftware.superiorskyblock.external.spawners.SpawnersProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_AutoDetect;\nimport com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.vanish.VanishProvider_Default;\nimport com.bgsoftware.superiorskyblock.external.worlds.DefaultWorldLoadListener;\nimport com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default;\nimport com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.plugin.Plugin;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class ProvidersManagerImpl extends Manager implements ProvidersManager {\n\n    private static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE);\n\n    private final List<AFKProvider> AFKProvidersList = new LinkedList<>();\n    private List<Runnable> pricesLoadCallbacks = new LinkedList<>();\n    private SpawnersProvider spawnersProvider = new SpawnersProvider_Default();\n    private StackedBlocksProvider stackedBlocksProvider = new StackedBlocksProvider_Default();\n    private EconomyProvider economyProvider = new EconomyProvider_Default();\n    private EconomyProvider bankEconomyProvider = new EconomyProvider_Default();\n    private PermissionsProvider permissionsProvider = new PermissionsProvider_Default();\n    private PricesProvider pricesProvider = new PricesProvider_Default();\n    private VanishProvider vanishProvider = new VanishProvider_Default();\n    private AsyncProvider asyncProvider = new AsyncProvider_Default();\n    private WorldsProvider worldsProvider;\n    private boolean isCustomWorldsProvider;\n    private ChunksProvider chunksProvider = new ChunksProvider_Default();\n    private MenusProvider menusProvider;\n    private boolean listenToSpawnerChanges = true;\n\n    private final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private final List<ISkinsListener> skinsListeners = new LinkedList<>();\n    private final List<IStackedBlocksListener> stackedBlocksListeners = new LinkedList<>();\n    private final List<IWorldsListener> worldsListeners = new LinkedList<>();\n    private final List<ICustomBlocksProvider> customBlocksProviders = new LinkedList<>();\n    private final List<EntitiesProvider> entitiesProviders = new LinkedList<>();\n\n    private final IWorldLoadListener DEFAULT_WORLD_LOAD_LISTENER = new DefaultWorldLoadListener(plugin);\n\n    public ProvidersManagerImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        setWorldsProviderInternal(new WorldsProvider_Default(plugin));\n        this.menusProvider = new MenusProvider_Default(plugin);\n    }\n\n    @Override\n    public void loadData() {\n        BukkitExecutor.sync(() -> {\n            registerGeneralHooks();\n            registerSpawnersProvider();\n            registerStackedBlocksProvider();\n            registerEntitiesProvider();\n            registerPermissionsProvider();\n            registerPricesProvider();\n            registerVanishProvider();\n            registerAFKProvider();\n            registerAsyncProvider();\n            registerEconomyProviders();\n            registerPlaceholdersProvider();\n            registerChunksProvider();\n        });\n\n        registerMessageProviders();\n\n        // We try to forcefully load prices after a second the server has enabled.\n        BukkitExecutor.sync(this::forcePricesLoad, 60L);\n    }\n\n    @Override\n    public SpawnersProvider getSpawnersProvider() {\n        return this.spawnersProvider;\n    }\n\n    @Override\n    public void setSpawnersProvider(SpawnersProvider spawnersProvider) {\n        Preconditions.checkNotNull(spawnersProvider, \"spawnersProvider parameter cannot be null.\");\n        this.spawnersProvider = spawnersProvider;\n    }\n\n    @Override\n    public StackedBlocksProvider getStackedBlocksProvider() {\n        return this.stackedBlocksProvider;\n    }\n\n    @Override\n    public void setStackedBlocksProvider(StackedBlocksProvider stackedBlocksProvider) {\n        Preconditions.checkNotNull(stackedBlocksProvider, \"stackedBlocksProvider parameter cannot be null.\");\n        this.stackedBlocksProvider = stackedBlocksProvider;\n    }\n\n    @Override\n    public List<EntitiesProvider> getEntitiesProviders() {\n        return Collections.unmodifiableList(this.entitiesProviders);\n    }\n\n    @Override\n    public void addEntitiesProvider(EntitiesProvider entitiesProvider) {\n        Preconditions.checkNotNull(entitiesProvider, \"entitiesProvider parameter cannot be null.\");\n        this.entitiesProviders.add(entitiesProvider);\n    }\n\n    @Override\n    public EconomyProvider getEconomyProvider() {\n        return this.economyProvider;\n    }\n\n    @Override\n    public void setEconomyProvider(EconomyProvider economyProvider) {\n        Preconditions.checkNotNull(economyProvider, \"economyProvider parameter cannot be null.\");\n        this.economyProvider = economyProvider;\n    }\n\n    @Override\n    public WorldsProvider getWorldsProvider() {\n        return this.worldsProvider;\n    }\n\n    @Override\n    public void setWorldsProvider(WorldsProvider worldsProvider) {\n        Preconditions.checkNotNull(worldsProvider, \"worldsProvider parameter cannot be null.\");\n        setWorldsProviderInternal(worldsProvider);\n        PluginEventsFactory.callWorldsProviderUpdateEvent();\n    }\n\n    private void setWorldsProviderInternal(WorldsProvider worldsProvider) {\n        this.worldsProvider = worldsProvider;\n        this.isCustomWorldsProvider = !(worldsProvider instanceof WorldsProvider_Default);\n        try {\n            this.worldsProvider.addWorldLoadListener(DEFAULT_WORLD_LOAD_LISTENER);\n        } catch (UnsupportedOperationException ignored) {\n            // Ignore UnsupportedOperationException\n        }\n    }\n\n    @Override\n    public ChunksProvider getChunksProvider() {\n        return chunksProvider;\n    }\n\n    @Override\n    public void setChunksProvider(ChunksProvider chunksProvider) {\n        Preconditions.checkNotNull(chunksProvider, \"chunksProvider parameter cannot be null.\");\n        this.chunksProvider = chunksProvider;\n    }\n\n    @Override\n    public EconomyProvider getBankEconomyProvider() {\n        return this.bankEconomyProvider;\n    }\n\n    @Override\n    public void setBankEconomyProvider(EconomyProvider bankEconomyProvider) {\n        Preconditions.checkNotNull(bankEconomyProvider, \"bankEconomyProvider parameter cannot be null.\");\n        this.bankEconomyProvider = bankEconomyProvider;\n    }\n\n    @Override\n    public List<AFKProvider> getAFKProviders() {\n        return Collections.unmodifiableList(this.AFKProvidersList);\n    }\n\n    @Override\n    public void addAFKProvider(AFKProvider afkProvider) {\n        Preconditions.checkNotNull(afkProvider, \"afkProvider parameter cannot be null.\");\n        AFKProvidersList.add(afkProvider);\n    }\n\n    @Override\n    public MenusProvider getMenusProvider() {\n        return this.menusProvider;\n    }\n\n    @Override\n    public void setMenusProvider(MenusProvider menusProvider) {\n        Preconditions.checkNotNull(menusProvider, \"menusProvider parameter cannot be null.\");\n        this.menusProvider = menusProvider;\n    }\n\n    @Override\n    public PermissionsProvider getPermissionsProvider() {\n        return permissionsProvider;\n    }\n\n    @Override\n    public void setPermissionsProvider(PermissionsProvider permissionsProvider) {\n        this.permissionsProvider = permissionsProvider;\n    }\n\n    @Override\n    public PricesProvider getPricesProvider() {\n        return pricesProvider;\n    }\n\n    @Override\n    public void setPricesProvider(PricesProvider pricesProvider) {\n        this.pricesProvider = pricesProvider;\n        this.pricesProvider.getWhenPricesAreReady().whenComplete((result, error) -> this.forcePricesLoad());\n    }\n\n    public void forcePricesLoad() {\n        if (this.pricesLoadCallbacks != null) {\n            this.pricesLoadCallbacks.forEach(Runnable::run);\n            this.pricesLoadCallbacks = null;\n            // After we loaded all the price callbacks, we want to sort the top islands.\n            SortingType.values().forEach(plugin.getGrid()::forceSortIslands);\n        }\n    }\n\n    @Override\n    public VanishProvider getVanishProvider() {\n        return vanishProvider;\n    }\n\n    @Override\n    public void setVanishProvider(VanishProvider vanishProvider) {\n        this.vanishProvider = vanishProvider;\n    }\n\n    @Override\n    public void registerSkinsListener(ISkinsListener skinsListener) {\n        this.skinsListeners.add(skinsListener);\n    }\n\n    @Override\n    public void unregisterSkinsListener(ISkinsListener skinsListener) {\n        this.skinsListeners.remove(skinsListener);\n    }\n\n    public boolean notifySkinsListeners(SuperiorPlayer superiorPlayer) {\n        this.skinsListeners.forEach(skinsListener -> skinsListener.setSkinTexture(superiorPlayer));\n        return !this.skinsListeners.isEmpty();\n    }\n\n    @Override\n    public void registerStackedBlocksListener(IStackedBlocksListener stackedBlocksListener) {\n        this.stackedBlocksListeners.add(stackedBlocksListener);\n    }\n\n    @Override\n    public void unregisterStackedBlocksListener(IStackedBlocksListener stackedBlocksListener) {\n        this.stackedBlocksListeners.remove(stackedBlocksListener);\n    }\n\n    public void registerCustomBlocksProvider(ICustomBlocksProvider customBlocksProvider) {\n        this.customBlocksProviders.add(customBlocksProvider);\n    }\n\n    public List<ICustomBlocksProvider> getCustomBlocksProviders() {\n        return customBlocksProviders;\n    }\n\n    public void addPricesLoadCallback(Runnable callback) {\n        if (this.pricesLoadCallbacks == null) {\n            callback.run();\n        } else {\n            this.pricesLoadCallbacks.add(callback);\n        }\n    }\n\n    public void notifyStackedBlocksListeners(OfflinePlayer offlinePlayer, Block block,\n                                             IStackedBlocksListener.Action action) {\n        this.stackedBlocksListeners.forEach(stackedBlocksListener ->\n                stackedBlocksListener.recordBlockAction(offlinePlayer, block, action));\n    }\n\n    @Override\n    public void registerWorldsListener(IWorldsListener worldsListener) {\n        this.worldsListeners.add(worldsListener);\n    }\n\n    @Override\n    public void unregisterWorldsListener(IWorldsListener worldsListener) {\n        this.worldsListeners.remove(worldsListener);\n    }\n\n    public void runWorldsListeners(String worldName) {\n        this.worldsListeners.forEach(worldsListener -> worldsListener.loadWorld(worldName));\n    }\n\n    public Key getSpawnerKey(ItemStack itemStack) {\n        String type = spawnersProvider.getSpawnerType(itemStack);\n        return type == null ? SpawnerKey.GLOBAL_KEY : Keys.ofSpawner(type);\n    }\n\n    public boolean hasSnapshotsSupport() {\n        return spawnersProvider instanceof SpawnersSnapshotProvider ||\n                stackedBlocksProvider instanceof StackedBlocksSnapshotProvider;\n    }\n\n    public void takeSnapshots(Chunk chunk) {\n        if (spawnersProvider instanceof SpawnersSnapshotProvider) {\n            ((SpawnersSnapshotProvider) spawnersProvider).takeSnapshot(chunk);\n        }\n        if (stackedBlocksProvider instanceof StackedBlocksSnapshotProvider) {\n            ((StackedBlocksSnapshotProvider) stackedBlocksProvider).takeSnapshot(chunk);\n        }\n    }\n\n    public void releaseSnapshots(ChunkPosition chunkPosition) {\n        if (spawnersProvider instanceof SpawnersSnapshotProvider) {\n            ((SpawnersSnapshotProvider) spawnersProvider).releaseSnapshot(\n                    chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ());\n        }\n        if (stackedBlocksProvider instanceof StackedBlocksSnapshotProvider) {\n            ((StackedBlocksSnapshotProvider) stackedBlocksProvider).releaseSnapshot(\n                    chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ());\n        }\n    }\n\n    public AsyncProvider getAsyncProvider() {\n        return asyncProvider;\n    }\n\n    public EconomyProvider.EconomyResult depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        while (amount.compareTo(MAX_DOUBLE) > 0) {\n            EconomyProvider.EconomyResult result = economyProvider.depositMoney(superiorPlayer, Double.MAX_VALUE);\n            if (result.hasFailed())\n                return result;\n\n            amount = amount.subtract(MAX_DOUBLE);\n        }\n\n        return economyProvider.depositMoney(superiorPlayer, amount.doubleValue());\n    }\n\n    public EconomyProvider.EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        while (amount.compareTo(MAX_DOUBLE) > 0) {\n            EconomyProvider.EconomyResult result = economyProvider.withdrawMoney(superiorPlayer, Double.MAX_VALUE);\n            if (result.hasFailed())\n                return result;\n\n            amount = amount.subtract(MAX_DOUBLE);\n        }\n\n        return economyProvider.withdrawMoney(superiorPlayer, amount.doubleValue());\n    }\n\n    public EconomyProvider.EconomyResult depositMoneyForBanks(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        while (amount.compareTo(MAX_DOUBLE) > 0) {\n            EconomyProvider.EconomyResult result = bankEconomyProvider.depositMoney(superiorPlayer, Double.MAX_VALUE);\n            if (result.hasFailed())\n                return result;\n\n            amount = amount.subtract(MAX_DOUBLE);\n        }\n\n        return bankEconomyProvider.depositMoney(superiorPlayer, amount.doubleValue());\n    }\n\n    public EconomyProvider.EconomyResult withdrawMoneyForBanks(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        while (amount.compareTo(MAX_DOUBLE) > 0) {\n            EconomyProvider.EconomyResult result = bankEconomyProvider.withdrawMoney(superiorPlayer, Double.MAX_VALUE);\n            if (result.hasFailed())\n                return result;\n\n            amount = amount.subtract(MAX_DOUBLE);\n        }\n\n        return bankEconomyProvider.withdrawMoney(superiorPlayer, amount.doubleValue());\n    }\n\n    public boolean hasCustomWorldsSupport() {\n        return this.isCustomWorldsProvider;\n    }\n\n    public boolean isAFK(Player player) {\n        return AFKProvidersList.stream().anyMatch(afkProvider -> afkProvider.isAFK(player));\n    }\n\n    public boolean shouldListenToSpawnerChanges() {\n        return listenToSpawnerChanges;\n    }\n\n    private void registerGeneralHooks() {\n        if (canRegisterHook(\"JetsMinions\"))\n            registerHook(\"JetsMinionsHook\");\n\n        if (canRegisterHook(\"SkinsRestorer\")) {\n            String version = Bukkit.getPluginManager().getPlugin(\"SkinsRestorer\").getDescription().getVersion();\n            if (version.startsWith(\"14\")) {\n                registerHook(\"SkinsRestorer14Hook\");\n            } else if (version.startsWith(\"15\")) {\n                registerHook(\"SkinsRestorer15Hook\");\n            } else {\n                registerHook(\"SkinsRestorerHook\");\n            }\n        }\n\n        if (canRegisterHook(\"ChangeSkin\"))\n            registerHook(\"ChangeSkinHook\");\n\n        if (canRegisterHook(\"Slimefun\"))\n            registerHook(\"SlimefunHook\");\n\n        if (canRegisterHook(\"CoreProtect\"))\n            registerHook(\"CoreProtectHook\");\n\n        if (isHookEnabled(\"SlimeWorldManager\") && JavaVersion.isAtLeast(17)) {\n            if (isOldSlimeWorldManager()) {\n                registerHook(\"SlimeWorldManagerHook\");\n            } else {\n                registerHook(\"AdvancedSlimePaperHook\");\n            }\n        }\n\n        if (canRegisterHook(\"ProtocolLib\"))\n            registerHook(\"ProtocolLibHook\");\n\n        if (Bukkit.getPluginManager().isPluginEnabled(\"Oraxen\"))\n            registerHook(\"OraxenHook\");\n\n        if (Bukkit.getPluginManager().isPluginEnabled(\"Nexo\"))\n            registerHook(\"NexoHook\");\n\n        if (Bukkit.getPluginManager().isPluginEnabled(\"ItemsAdder\"))\n            registerHook(\"ItemsAdderHook\");\n\n        if (canRegisterHook(\"Plan\"))\n            registerHook(\"PlanHook\");\n\n        if (Bukkit.getPluginManager().isPluginEnabled(\"CraftEngine\"))\n            // We load the hook with an extra delay to let CraftEngine load its data first\n            BukkitExecutor.sync(() -> registerHook(\"CraftEngineHook\"), 5L);\n\n        if (canRegisterHook(\"SmoothTimber\"))\n            registerHook(\"SmoothTimberHook\");\n\n        if (canRegisterHook(\"SilkSpawners\")) {\n            List<String> pluginAuthors = Bukkit.getPluginManager().getPlugin(\"SilkSpawners\").getDescription().getAuthors();\n            if (pluginAuthors.contains(\"mushroomhostage\")) {\n                registerHook(\"TimbruSilkSpawnersHook\");\n            }\n        }\n\n    }\n\n    private void registerMessageProviders() {\n        if (isHookEnabled(\"MiniMessage\") && hasMiniMessageSupport()) {\n            registerHook(\"MiniMessageHook\");\n        }\n    }\n\n    private void registerSpawnersProvider() {\n        if (!(spawnersProvider instanceof SpawnersProvider_AutoDetect))\n            return;\n\n        String configSpawnersProvider = plugin.getSettings().getSpawnersProvider();\n        boolean auto = configSpawnersProvider.equalsIgnoreCase(\"Auto\");\n\n        Optional<SpawnersProvider> spawnersProvider = Optional.empty();\n\n        if (canRegisterHook(\"MergedSpawner\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"MergedSpawner\"))) {\n            spawnersProvider = createInstance(\"spawners.SpawnersProvider_MergedSpawner\");\n            listenToSpawnerChanges = false;\n        } else if (canRegisterHook(\"AdvancedSpawners\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"AdvancedSpawners\"))) {\n            spawnersProvider = createInstance(\"spawners.SpawnersProvider_AdvancedSpawners\");\n        } else if (canRegisterHook(\"WildStacker\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"WildStacker\"))) {\n            spawnersProvider = createInstance(\"spawners.SpawnersProvider_WildStacker\");\n        } else if (canRegisterHook(\"SilkSpawners\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"SilkSpawners\"))) {\n            Plugin silkSpawnersPlugin = Bukkit.getPluginManager().getPlugin(\"SilkSpawners\");\n            if (silkSpawnersPlugin.getDescription().getAuthors().contains(\"CandC_9_12\")) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_CandcSilkSpawners\");\n            } else if (silkSpawnersPlugin.getDescription().getAuthors().contains(\"mushroomhostage\")) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_TimbruSilkSpawners\");\n            }\n        } else if (canRegisterHook(\"PvpingSpawners\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"PvpingSpawners\"))) {\n            spawnersProvider = createInstance(\"spawners.SpawnersProvider_PvpingSpawners\");\n        } else if (canRegisterHook(\"EpicSpawners\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"EpicSpawners\"))) {\n            String version = Bukkit.getPluginManager().getPlugin(\"EpicSpawners\").getDescription().getVersion();\n            if (version.startsWith(\"9\")) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_EpicSpawners9\");\n            } else if (version.startsWith(\"8\")) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_EpicSpawners8\");\n            } else if (version.startsWith(\"7\")) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_EpicSpawners7\");\n            } else {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_EpicSpawners6\");\n            }\n        } else if (canRegisterHook(\"UltimateStacker\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"UltimateStacker\"))) {\n            String version = Bukkit.getPluginManager().getPlugin(\"UltimateStacker\").getDescription().getVersion();\n            int majorVersion = Integer.parseInt(String.valueOf(version.charAt(0)));\n            if (majorVersion >= 4) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_UltimateStacker4\");\n            } else if (majorVersion == 3) {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_UltimateStacker3\");\n            } else {\n                spawnersProvider = createInstance(\"spawners.SpawnersProvider_UltimateStacker\");\n            }\n            listenToSpawnerChanges = false;\n        } else if (canRegisterHook(\"RoseStacker\") &&\n                (auto || configSpawnersProvider.equalsIgnoreCase(\"RoseStacker\"))) {\n            spawnersProvider = createInstance(\"spawners.SpawnersProvider_RoseStacker\");\n            listenToSpawnerChanges = false;\n        }\n\n        spawnersProvider.ifPresent(this::setSpawnersProvider);\n    }\n\n    private void registerStackedBlocksProvider() {\n        if (!(stackedBlocksProvider instanceof StackedBlocksProvider_AutoDetect))\n            return;\n\n        String configStackedBlocksProvider = plugin.getSettings().getStackedBlocksProvider();\n        boolean auto = configStackedBlocksProvider.equalsIgnoreCase(\"Auto\");\n\n        Optional<StackedBlocksProvider> stackedBlocksProvider = Optional.empty();\n\n        if (canRegisterHook(\"WildStacker\") &&\n                (auto || configStackedBlocksProvider.equalsIgnoreCase(\"WildStacker\"))) {\n            stackedBlocksProvider = createInstance(\"stackedblocks.StackedBlocksProvider_WildStacker\");\n        } else if (canRegisterHook(\"RoseStacker\") &&\n                (auto || configStackedBlocksProvider.equalsIgnoreCase(\"RoseStacker\"))) {\n            stackedBlocksProvider = createInstance(\"stackedblocks.StackedBlocksProvider_RoseStacker\");\n        }\n\n        stackedBlocksProvider.ifPresent(this::setStackedBlocksProvider);\n    }\n\n    private void registerEntitiesProvider() {\n        if (canRegisterHook(\"WildStacker\")) {\n            Optional<EntitiesProvider> entitiesProvider = createInstance(\"entities.EntitiesProvider_WildStacker\");\n            entitiesProvider.ifPresent(this::addEntitiesProvider);\n        }\n        if (canRegisterHook(\"RoseStacker\")) {\n            Optional<EntitiesProvider> entitiesProvider = createInstance(\"entities.EntitiesProvider_RoseStacker\");\n            entitiesProvider.ifPresent(this::addEntitiesProvider);\n        }\n    }\n\n    private void registerPermissionsProvider() {\n        Optional<PermissionsProvider> permissionsProvider = Optional.empty();\n\n        if (canRegisterHook(\"LuckPerms\")) {\n            permissionsProvider = createInstance(\"permissions.PermissionsProvider_LuckPerms\");\n        }\n\n        permissionsProvider.ifPresent(this::setPermissionsProvider);\n    }\n\n    private void registerPricesProvider() {\n        ShopsProvider.SHOPGUIPLUS.createInstance(plugin)\n                .map(shopsBridge -> new PricesProvider_ShopsBridgeWrapper(plugin, ShopsProvider.SHOPGUIPLUS, shopsBridge))\n                .ifPresent(this::setPricesProvider);\n    }\n\n    private void registerVanishProvider() {\n        Optional<VanishProvider> vanishProvider = Optional.empty();\n\n        if (canRegisterHook(\"VanishNoPacket\")) {\n            vanishProvider = createInstance(\"vanish.VanishProvider_VanishNoPacket\");\n        } else if (canRegisterHook(\"SuperVanish\") ||\n                canRegisterHook(\"PremiumVanish\")) {\n            vanishProvider = createInstance(\"vanish.VanishProvider_SuperVanish\");\n        } else if (canRegisterHook(\"Essentials\")) {\n            vanishProvider = createInstance(\"vanish.VanishProvider_Essentials\");\n        } else if (canRegisterHook(\"CMI\")) {\n            vanishProvider = createInstance(\"vanish.VanishProvider_CMI\");\n        }\n\n        vanishProvider.ifPresent(this::setVanishProvider);\n    }\n\n    private void registerAFKProvider() {\n        if (canRegisterHook(\"CMI\")) {\n            Optional<AFKProvider> afkProvider = createInstance(\"afk.AFKProvider_CMI\");\n            afkProvider.ifPresent(this::addAFKProvider);\n        }\n        if (canRegisterHook(\"Essentials\")) {\n            Optional<AFKProvider> afkProvider = createInstance(\"afk.AFKProvider_Essentials\");\n            afkProvider.ifPresent(this::addAFKProvider);\n        }\n    }\n\n    private void registerAsyncProvider() {\n        if (hasPaperAsyncSupport()) {\n            Optional<AsyncProvider> asyncProviderOptional = createInstance(\"async.AsyncProvider_Paper\");\n            asyncProviderOptional.ifPresent(asyncProvider -> {\n                this.asyncProvider = asyncProvider;\n            });\n        }\n    }\n\n    private void registerEconomyProviders() {\n        if (canRegisterHook(\"Vault\")) {\n            if (this.economyProvider instanceof EconomyProvider_Default ||\n                    this.bankEconomyProvider instanceof EconomyProvider_Default) {\n                Optional<EconomyProvider> economyProviderOptional = createInstance(\"economy.EconomyProvider_Vault\");\n                economyProviderOptional.ifPresent(economyProvider -> {\n                    if (this.economyProvider instanceof EconomyProvider_Default)\n                        setEconomyProvider(economyProvider);\n                    if (this.bankEconomyProvider instanceof EconomyProvider_Default)\n                        setBankEconomyProvider(economyProvider);\n                });\n            }\n        }\n    }\n\n    private void registerPlaceholdersProvider() {\n        List<PlaceholdersProvider> placeholdersProviders = new ArrayList<>();\n\n        if (canRegisterHook(\"MVdWPlaceholderAPI\")) {\n            Optional<PlaceholdersProvider> placeholdersProvider = createInstance(\"placeholders.PlaceholdersProvider_MVdWPlaceholderAPI\");\n            placeholdersProvider.ifPresent(placeholdersProviders::add);\n        }\n        if (canRegisterHook(\"PlaceholderAPI\")) {\n            Optional<PlaceholdersProvider> placeholdersProvider = createInstance(\"placeholders.PlaceholdersProvider_PlaceholderAPI\");\n            placeholdersProvider.ifPresent(placeholdersProviders::add);\n        }\n\n        ((PlaceholdersServiceImpl) this.placeholdersService.get()).register(placeholdersProviders);\n    }\n\n    private void registerChunksProvider() {\n        if (hasPaperAsyncSupport()) {\n            Optional<ChunksProvider> chunksProviderOptional = createInstance(\"chunks.ChunksProvider_Paper\");\n            chunksProviderOptional.ifPresent(chunksProvider -> {\n                try {\n                    setChunksProvider(chunksProvider);\n                    Log.info(\"Detected PaperSpigot - Using async chunk-loading support with PaperMC.\");\n                } catch (Exception error) {\n                    Log.error(error, \"Detected PaperSpigot but failed to load async chunk-loading support due to an unexpected error:\");\n                }\n            });\n        }\n    }\n\n    private void registerHook(String className) {\n        try {\n            Class<?> clazz = Class.forName(\"com.bgsoftware.superiorskyblock.external.\" + className);\n\n            if (!isHookCompatible(clazz))\n                return;\n\n            Method registerMethod = clazz.getMethod(\"register\", SuperiorSkyblockPlugin.class);\n            registerMethod.invoke(null, plugin);\n        } catch (Throwable error) {\n            if (error.getClass() != UnsupportedClassVersionError.class)\n                Log.error(error, \"An unexpected error occurred while registering hook \", className, \":\");\n        }\n    }\n\n    private static boolean hasPaperAsyncSupport() {\n        return new ReflectMethod<>(World.class, \"getChunkAtAsync\", int.class, int.class).isValid();\n    }\n\n    private static boolean isOldSlimeWorldManager() {\n        try {\n            Class.forName(\"com.grinderwolf.swm.api.SlimePlugin\");\n            return true;\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }\n\n    private static boolean hasMiniMessageSupport() {\n        try {\n            Class.forName(\"net.kyori.adventure.text.minimessage.MiniMessage\");\n            return ServerVersion.isAtLeast(ServerVersion.v1_18);\n        } catch (ClassNotFoundException error) {\n            return false;\n        }\n    }\n\n    private <T> Optional<T> createInstance(String className) {\n        try {\n            Class<?> clazz = Class.forName(\"com.bgsoftware.superiorskyblock.external.\" + className);\n\n            if (!isHookCompatible(clazz))\n                return Optional.empty();\n\n            try {\n                Constructor<?> constructor = clazz.getConstructor(SuperiorSkyblockPlugin.class);\n                // noinspection unchecked\n                return Optional.of((T) constructor.newInstance(plugin));\n            } catch (NoSuchMethodException error) {\n                // noinspection unchecked\n                return Optional.of((T) clazz.newInstance());\n            }\n        } catch (ClassNotFoundException ignored) {\n            return Optional.empty();\n        } catch (Exception error) {\n            Log.entering(\"ENTER\", className);\n            Log.error(error, \"An unexpected error occurred while creating hook instance:\");\n            return Optional.empty();\n        }\n    }\n\n    private boolean canRegisterHook(String pluginName) {\n        return Bukkit.getPluginManager().isPluginEnabled(pluginName) && isHookEnabled(pluginName);\n    }\n\n    private boolean isHookEnabled(String pluginName) {\n        return !plugin.getSettings().getDisabledHooks().contains(pluginName.toLowerCase(Locale.ENGLISH));\n    }\n\n    private boolean isHookCompatible(Class<?> clazz) {\n        ReflectMethod<Boolean> compatibleMethod = new ReflectMethod<>(clazz, \"isCompatible\");\n        return !compatibleMethod.isValid() || compatibleMethod.invoke(null);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.external.async;\n\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\nimport java.util.function.Consumer;\n\npublic interface AsyncProvider {\n\n    default void teleport(Entity entity, Location location) {\n        teleport(entity, location, r -> {\n        });\n    }\n\n    void teleport(Entity entity, Location location, Consumer<Boolean> teleportResult);\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.async;\n\nimport com.bgsoftware.superiorskyblock.external.async.AsyncProvider;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\nimport java.util.function.Consumer;\n\npublic class AsyncProvider_Default implements AsyncProvider {\n\n    @Override\n    public void teleport(Entity entity, Location location, Consumer<Boolean> teleportResult) {\n        boolean result = entity.teleport(location);\n        if (teleportResult != null)\n            teleportResult.accept(result);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.external.blocks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\n\npublic interface ICustomBlocksProvider {\n\n    @Nullable\n    KeyMap<Integer> getBlockCountsForChunk(ChunkPosition chunkPosition);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/chunks/ChunksProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.chunks;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider;\nimport org.bukkit.Chunk;\nimport org.bukkit.World;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class ChunksProvider_Default implements ChunksProvider {\n\n    @Override\n    public CompletableFuture<Chunk> loadChunk(World world, int chunkX, int chunkZ) {\n        return CompletableFuture.completedFuture(world.getChunkAt(chunkX, chunkZ));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.economy;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\npublic class EconomyProvider_Default implements EconomyProvider {\n\n    private static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE);\n\n    @Override\n    public BigDecimal getBalance(SuperiorPlayer superiorPlayer) {\n        return MAX_DOUBLE;\n    }\n\n    @Override\n    public EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount) {\n        return new EconomyResult(\"Vault is not installed\");\n    }\n\n    @Override\n    public EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount) {\n        return new EconomyResult(\"Vault is not installed\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.menus;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.MenusProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuConfig;\nimport com.bgsoftware.superiorskyblock.core.menu.Menus;\nimport com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryIconEdit;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpIconEdit;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs;\nimport com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.google.common.base.Preconditions;\n\nimport java.io.File;\nimport java.util.IdentityHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class MenusProvider_Default implements MenusProvider {\n\n    private final Map<Schematic, MenuIslandCreationConfig> ISLAND_CREATION_CONFIG_CACHE = new IdentityHashMap<>();\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public MenusProvider_Default(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    private static void handleExceptions(Runnable runnable) {\n        try {\n            runnable.run();\n        } catch (Exception ex) {\n            ManagerLoadException handlerError = new ManagerLoadException(ex, ManagerLoadException.ErrorLevel.CONTINUE);\n            Log.error(handlerError, \"An unexpected error occurred while loading menu:\");\n        }\n    }\n\n    @Override\n    public void initializeMenus() {\n        File guiFolder = new File(plugin.getDataFolder(), \"guis\");\n        if (guiFolder.exists()) {\n            File oldGuisFolder = new File(plugin.getDataFolder(), \"old-guis\");\n            //noinspection ResultOfMethodCallIgnored\n            guiFolder.renameTo(oldGuisFolder);\n        }\n\n        // We first want to unregister all menus\n        plugin.getMenus().unregisterMenus();\n\n        Menus.registerMenus();\n\n        File customMenusFolder = new File(plugin.getDataFolder(), \"menus/custom\");\n\n        if (!customMenusFolder.exists()) {\n            //noinspection ResultOfMethodCallIgnored\n            customMenusFolder.mkdirs();\n            return;\n        }\n\n        for (File menuFile : Files.listFolderFiles(customMenusFolder, false)) {\n            handleExceptions(() -> plugin.getMenus().registerMenu(MenuCustom.createInstance(menuFile)));\n        }\n    }\n\n    @Override\n    public void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_BANK_LOGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshBankLogs(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_BANK_LOGS.refreshViews(island);\n    }\n\n    @Override\n    public void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_BIOMES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Menus.MENU_BORDER_COLOR.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu);\n    }\n\n    @Override\n    public void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(bannedPlayer, \"bannedPlayer parameter cannot be null.\");\n        Menus.MENU_CONFIRM_BAN.createView(targetPlayer, new MenuConfirmBan.Args(targetIsland, bannedPlayer), previousMenu);\n    }\n\n    @Override\n    public void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_CONFIRM_DISBAND.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(kickedPlayer, \"kickedPlayer parameter cannot be null.\");\n        Menus.MENU_CONFIRM_KICK.createView(targetPlayer, new MenuConfirmKick.Args(targetIsland, kickedPlayer), previousMenu);\n    }\n\n    @Override\n    public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Menus.MENU_CONFIRM_LEAVE.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu);\n    }\n\n    @Override\n    public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(newOwner, \"newOwner parameter cannot be null.\");\n        Menus.MENU_CONFIRM_TRANSFER.createView(targetPlayer, new MenuConfirmTransfer.Args(targetIsland, newOwner), previousMenu);\n    }\n\n    @Override\n    public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_CONTROL_PANEL.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_COOPS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshCoops(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_COOPS.refreshViews(island);\n    }\n\n    @Override\n    public void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_COUNTS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshCounts(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_COUNTS.refreshViews(island);\n    }\n\n    @Override\n    public void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Menus.MENU_GLOBAL_WARPS.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu);\n    }\n\n    @Override\n    public void refreshGlobalWarps() {\n        Menus.MENU_GLOBAL_WARPS.refreshViews();\n    }\n\n    @Override\n    public void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_BANK.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshIslandBank(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_BANK.refreshViews(island);\n    }\n\n    @Override\n    public void openIslandBannedPlayers(SuperiorPlayer targetPlayer, ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_BANNED_PLAYERS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshIslandBannedPlayers(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_BANNED_PLAYERS.refreshViews(island);\n    }\n\n    @Override\n    public void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        if (Menus.MENU_ISLAND_CHEST.isSkipOneItem()) {\n            IslandChest[] islandChest = targetIsland.getChest();\n            if (islandChest.length == 1) {\n                islandChest[0].openChest(targetPlayer);\n                return;\n            }\n        }\n\n        Menus.MENU_ISLAND_CHEST.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshIslandChest(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_CHEST.refreshViews(island);\n    }\n\n    @Override\n    public MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic) {\n        return ISLAND_CREATION_CONFIG_CACHE.computeIfAbsent(schematic, unused -> {\n            for (MenuTemplateButton<MenuIslandCreation.View> button : Menus.MENU_ISLAND_CREATION.getLayout().getButtons()) {\n                if (IslandCreationButton.class.equals(button.getViewButtonType()) &&\n                        ((IslandCreationButton.Template) button).getSchematic().equals(schematic)) {\n                    return ((IslandCreationButton.Template) button).getCreationConfig();\n                }\n            }\n\n            return new MenuConfig.IslandCreation(schematic, null);\n        });\n    }\n\n    @Override\n    public void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        if (Menus.MENU_ISLAND_CREATION.isSkipOneItem()) {\n            List<Schematic> schematicButtons = Menus.MENU_ISLAND_CREATION.getLayout().getButtons().stream()\n                    .filter(button -> IslandCreationButton.class.equals(button.getViewButtonType()))\n                    .map(button -> ((IslandCreationButton.Template) button).getSchematic())\n                    .collect(Collectors.toList());\n\n            if (schematicButtons.size() == 1) {\n                MenuIslandCreationConfig creationConfig = getIslandCreationConfig(schematicButtons.get(0));\n                MenuActions.simulateIslandCreationClick(targetPlayer, islandName, creationConfig, false, targetPlayer.getOpenedView());\n                return;\n            }\n        }\n\n        Menus.MENU_ISLAND_CREATION.createView(targetPlayer, new MenuIslandCreation.Args(islandName), previousMenu);\n    }\n\n    @Override\n    public void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_RATE.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_RATINGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshIslandRatings(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_RATINGS.refreshViews(island);\n    }\n\n    @Override\n    public void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandMember, \"islandMember parameter cannot be null.\");\n        Menus.MENU_MEMBER_MANAGE.createView(targetPlayer, new PlayerViewArgs(islandMember), previousMenu);\n    }\n\n    @Override\n    public void destroyMemberManage(SuperiorPlayer islandMember) {\n        Preconditions.checkNotNull(islandMember, \"islandMember parameter cannot be null.\");\n        Menus.MENU_MEMBER_MANAGE.closeViews(islandMember);\n    }\n\n    @Override\n    public void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandMember, \"islandMember parameter cannot be null.\");\n        Menus.MENU_MEMBER_ROLE.createView(targetPlayer, new PlayerViewArgs(islandMember), previousMenu);\n    }\n\n    @Override\n    public void destroyMemberRole(SuperiorPlayer islandMember) {\n        Preconditions.checkNotNull(islandMember, \"islandMember parameter cannot be null.\");\n        Menus.MENU_MEMBER_ROLE.closeViews(islandMember);\n    }\n\n    @Override\n    public void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_MEMBERS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshMembers(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_MEMBERS.refreshViews(island);\n    }\n\n    @Override\n    public void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        if (Menus.MENU_MISSIONS.isSkipOneItem()) {\n            List<MissionCategory> missionCategories = plugin.getMissions().getMissionCategories();\n            if (missionCategories.size() == 1) {\n                openMissionsCategory(targetPlayer, previousMenu, missionCategories.get(0));\n                return;\n            }\n        }\n        Menus.MENU_MISSIONS.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu);\n    }\n\n    @Override\n    public void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(missionCategory, \"missionCategory parameter cannot be null.\");\n        Menus.MENU_MISSIONS_CATEGORY.createView(targetPlayer, new MenuMissionsCategory.Args(missionCategory), previousMenu);\n    }\n\n    @Override\n    public void refreshMissionsCategory(MissionCategory missionCategory) {\n        Preconditions.checkNotNull(missionCategory, \"missionCategory parameter cannot be null.\");\n        Menus.MENU_MISSIONS_CATEGORY.refreshViews(missionCategory);\n    }\n\n    @Override\n    public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(permissiblePlayer, \"permissiblePlayer parameter cannot be null.\");\n        Menus.MENU_ISLAND_PRIVILEGES.createView(targetPlayer, new MenuIslandPrivileges.Args(targetIsland, permissiblePlayer), previousMenu);\n    }\n\n    @Override\n    public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(permissibleRole, \"permissibleRole parameter cannot be null.\");\n        Menus.MENU_ISLAND_PRIVILEGES.createView(targetPlayer, new MenuIslandPrivileges.Args(targetIsland, permissibleRole), previousMenu);\n    }\n\n    @Override\n    public void refreshPermissions(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island);\n    }\n\n    @Override\n    public void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(permissiblePlayer, \"permissiblePlayer parameter cannot be null.\");\n        Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island, permissiblePlayer);\n    }\n\n    @Override\n    public void refreshPermissions(Island island, PlayerRole permissibleRole) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(permissibleRole, \"permissibleRole parameter cannot be null.\");\n        Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island, permissibleRole);\n    }\n\n    @Override\n    public void updatePermission(IslandPrivilege islandPrivilege) {\n        // The default implementation does not care if the island privilege is valid for showing the island\n        // privileges in the menu. If the island privilege is not valid at the time of opening the menu, it\n        // will show it as it was disabled. This is the responsibility of the server owners to properly\n        // configure the menu.\n    }\n\n    @Override\n    public void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Menus.MENU_PLAYER_LANGUAGE.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu);\n    }\n\n    @Override\n    public void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_FLAGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshSettings(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_FLAGS.refreshViews(island);\n    }\n\n    @Override\n    public void updateSettings(IslandFlag islandFlag) {\n        // The default implementation does not care if the island flag is valid for showing the island flags\n        // in the menu. If the island flag is not valid at the time of opening the menu, it will show it as\n        // it was disabled. This is the responsibility of the server owners to properly configure the menu.\n    }\n\n    @Override\n    public void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        Menus.MENU_TOP_ISLANDS.createView(targetPlayer, new MenuTopIslands.Args(sortingType), previousMenu);\n    }\n\n    @Override\n    public void refreshTopIslands(SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        Menus.MENU_TOP_ISLANDS.refreshViews(sortingType);\n    }\n\n    @Override\n    public void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_UNIQUE_VISITORS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshUniqueVisitors(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_UNIQUE_VISITORS.refreshViews(island);\n    }\n\n    @Override\n    public void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_UPGRADES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshUpgrades(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_UPGRADES.refreshViews(island);\n    }\n\n    @Override\n    public void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_VALUES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshValues(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_VALUES.refreshViews(island);\n    }\n\n    @Override\n    public void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n        Menus.MENU_ISLAND_VISITORS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n    }\n\n    @Override\n    public void refreshVisitors(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_ISLAND_VISITORS.refreshViews(island);\n    }\n\n    @Override\n    public void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetIsland, \"targetIsland parameter cannot be null.\");\n\n        // The warp categories menu should be opened only if:\n        //      A) its enabled\n        //      B) there are more than 1 category\n        if (plugin.getSettings().isWarpCategories() && targetIsland.getWarpCategories().size() > 1) {\n            Menus.MENU_WARP_CATEGORIES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu);\n        } else {\n            WarpCategory warpCategory = targetIsland.getWarpCategories().values().stream().findFirst()\n                    .orElseGet(() -> targetIsland.createWarpCategory(\"Default Category\"));\n            openWarps(targetPlayer, previousMenu, warpCategory);\n        }\n    }\n\n    @Override\n    public void refreshWarpCategories(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_WARP_CATEGORIES.refreshViews(island);\n    }\n\n    @Override\n    public void destroyWarpCategories(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Menus.MENU_WARP_CATEGORIES.closeViews(island);\n    }\n\n    @Override\n    public void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetCategory, \"targetCategory parameter cannot be null.\");\n        Menus.MENU_WARP_CATEGORY_ICON_EDIT.createView(targetPlayer, new MenuWarpCategoryIconEdit.Args(targetCategory), previousMenu);\n    }\n\n    @Override\n    public void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetCategory, \"targetCategory parameter cannot be null.\");\n        Menus.MENU_WARP_CATEGORY_MANAGE.createView(targetPlayer, new MenuWarpCategoryManage.Args(targetCategory), previousMenu);\n    }\n\n    @Override\n    public void refreshWarpCategoryManage(WarpCategory warpCategory) {\n        Preconditions.checkNotNull(warpCategory, \"warpCategory parameter cannot be null.\");\n        Menus.MENU_WARP_CATEGORY_MANAGE.refreshViews(warpCategory);\n    }\n\n    @Override\n    public void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetWarp, \"targetWarp parameter cannot be null.\");\n        Menus.MENU_WARP_ICON_EDIT.createView(targetPlayer, new MenuWarpIconEdit.Args(targetWarp), previousMenu);\n    }\n\n    @Override\n    public void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetWarp, \"targetWarp parameter cannot be null.\");\n        Menus.MENU_WARP_MANAGE.createView(targetPlayer, new MenuWarpManage.Args(targetWarp), previousMenu);\n    }\n\n    @Override\n    public void refreshWarpManage(IslandWarp islandWarp) {\n        Preconditions.checkNotNull(islandWarp, \"islandWarp parameter cannot be null.\");\n        Menus.MENU_WARP_MANAGE.refreshViews(islandWarp);\n    }\n\n    @Override\n    public void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) {\n        Preconditions.checkNotNull(targetPlayer, \"targetPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(targetCategory, \"targetCategory parameter cannot be null.\");\n\n        // We want skip one item to only work if the player can't edit warps, otherwise he\n        // won't be able to edit them as the menu will get skipped if only one warp exists.\n        if (Menus.MENU_WARPS.isSkipOneItem() && !targetCategory.getIsland().hasPermission(targetPlayer, IslandPrivileges.SET_WARP)) {\n            List<IslandWarp> availableWarps = targetCategory.getIsland().isMember(targetPlayer) ? targetCategory.getWarps() :\n                    targetCategory.getWarps().stream()\n                            .filter(islandWarp -> !islandWarp.hasPrivateFlag())\n                            .collect(Collectors.toList());\n\n            if (availableWarps.size() == 1) {\n                MenuActions.simulateWarpsClick(targetPlayer, targetCategory.getIsland(), availableWarps.get(0));\n                return;\n            }\n        }\n\n        Menus.MENU_WARPS.createView(targetPlayer, new MenuWarps.Args(targetCategory), previousMenu);\n    }\n\n    @Override\n    public void refreshWarps(WarpCategory warpCategory) {\n        Preconditions.checkNotNull(warpCategory, \"warpCategory parameter cannot be null.\");\n        Menus.MENU_WARPS.refreshViews(warpCategory);\n    }\n\n    @Override\n    public void destroyWarps(WarpCategory warpCategory) {\n        Preconditions.checkNotNull(warpCategory, \"warpCategory parameter cannot be null.\");\n        Menus.MENU_WARPS.closeViews(warpCategory);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.permissions;\n\nimport com.bgsoftware.common.reflection.ClassInfo;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider;\nimport org.bukkit.entity.Player;\nimport org.bukkit.permissions.PermissibleBase;\nimport org.bukkit.permissions.PermissionAttachmentInfo;\n\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class PermissionsProvider_Default implements PermissionsProvider {\n\n    private static final ReflectField<PermissibleBase> HUMAN_ENTITY_PERMS = new ReflectField<>(\n            new ClassInfo(\"entity.CraftHumanEntity\", ClassInfo.PackageType.CRAFTBUKKIT),\n            PermissibleBase.class, \"perm\");\n    private static final ReflectField<Map<String, PermissionAttachmentInfo>> PERMISSIBLE_BASE_PERMISSIONS =\n            new ReflectField<>(PermissibleBase.class, Map.class, \"permissions\");\n\n    @Override\n    public boolean hasPermission(Player player, String permission) {\n        PermissibleBase permissibleBase = HUMAN_ENTITY_PERMS.get(player);\n        PermissionAttachmentInfo permissionAttachmentInfo = PERMISSIBLE_BASE_PERMISSIONS.get(permissibleBase)\n                .get(permission.toLowerCase(Locale.ENGLISH));\n        return permissionAttachmentInfo != null && permissionAttachmentInfo.getValue();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.external.placeholders;\n\nimport org.bukkit.OfflinePlayer;\n\npublic interface PlaceholdersProvider {\n\n    String parsePlaceholders(OfflinePlayer offlinePlayer, String value);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/prices/PricesProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.prices;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.PricesProvider;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigDecimal;\n\npublic class PricesProvider_Default implements PricesProvider {\n\n    private final BigDecimal INVALID_WORTH = BigDecimal.valueOf(-1);\n\n    @Override\n    public BigDecimal getPrice(Key key) {\n        return INVALID_WORTH;\n    }\n\n    @Override\n    public Key getBlockKey(Key blockKey) {\n        return blockKey;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/prices/PricesProvider_ShopsBridgeWrapper.java",
    "content": "package com.bgsoftware.superiorskyblock.external.prices;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.shopsbridge.IShopsBridge;\nimport com.bgsoftware.common.shopsbridge.ShopsProvider;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.PricesProvider;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.math.BigDecimal;\nimport java.util.Locale;\nimport java.util.concurrent.CompletableFuture;\n\npublic class PricesProvider_ShopsBridgeWrapper implements PricesProvider {\n\n    private final KeyMap<BigDecimal> cachedPrices = KeyMap.createConcurrentKeyMap();\n    private final SuperiorSkyblockPlugin plugin;\n    private final IShopsBridge shopsBridge;\n\n    public PricesProvider_ShopsBridgeWrapper(SuperiorSkyblockPlugin plugin, ShopsProvider shopsProvider, IShopsBridge shopsBridge) {\n        Log.info(\"Using \" + shopsProvider.getPluginName() + \" as a prices provider.\");\n        this.plugin = plugin;\n        this.shopsBridge = shopsBridge;\n    }\n\n    @Override\n    public BigDecimal getPrice(Key key) {\n        try {\n            return this.cachedPrices.computeIfAbsent(key, this::getPriceFromShopsBridge);\n        } catch (Throwable error) {\n            Log.error(error, \"Failed to load prices for item \" + key);\n            return BigDecimal.ZERO;\n        }\n    }\n\n    @Nullable\n    @Override\n    public Key getBlockKey(Key blockKey) {\n        return this.cachedPrices.getKey(blockKey, null);\n    }\n\n    @Override\n    public CompletableFuture<Void> getWhenPricesAreReady() {\n        return this.shopsBridge.getWhenShopsLoaded();\n    }\n\n    private BigDecimal getPriceFromShopsBridge(Key key) {\n        ItemStack itemStack;\n\n        try {\n            Material material = Material.valueOf(key.getGlobalKey().toUpperCase(Locale.ENGLISH));\n            if (material == Materials.SPAWNER.toBukkitType()) {\n                EntityType entityType = EntityType.valueOf(key.getSubKey().toUpperCase(Locale.ENGLISH));\n                itemStack = new ItemBuilder(material).withEntityType(entityType).build();\n            } else {\n                short durability = Short.parseShort(key.getSubKey());\n                itemStack = new ItemStack(material, 1, durability);\n            }\n        } catch (Throwable error) {\n            return BigDecimal.ZERO;\n        }\n\n        switch (plugin.getSettings().getSyncWorth()) {\n            case BUY:\n                return this.shopsBridge.getBuyPrice(itemStack);\n            case SELL:\n                return this.shopsBridge.getSellPrice(itemStack);\n            default:\n                return BigDecimal.ZERO;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProviderItemMetaSpawnerType.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.google.common.base.Preconditions;\nimport org.bukkit.block.CreatureSpawner;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.BlockStateMeta;\n\nimport java.util.Optional;\n\npublic interface SpawnersProviderItemMetaSpawnerType extends SpawnersProvider_AutoDetect {\n\n    default String getSpawnerType(ItemStack itemStack) {\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null.\");\n\n        if (itemStack.getItemMeta() instanceof BlockStateMeta) {\n            CreatureSpawner creatureSpawner = (CreatureSpawner) ((BlockStateMeta) itemStack.getItemMeta()).getBlockState();\n            return Optional.ofNullable(creatureSpawner.getSpawnedType()).map(EntityType::name).orElse(null);\n        }\n\n        return \"PIG\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AutoDetect.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider;\n\npublic interface SpawnersProvider_AutoDetect extends SpawnersProvider {\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.spawners;\n\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport org.bukkit.Location;\nimport org.bukkit.inventory.ItemStack;\n\npublic class SpawnersProvider_Default implements SpawnersProvider_AutoDetect {\n\n    @Override\n    public Pair<Integer, String> getSpawner(Location location) {\n        return new Pair<>(1, null);\n    }\n\n    @Override\n    public String getSpawnerType(ItemStack itemStack) {\n        return \"PIG\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_AutoDetect.java",
    "content": "package com.bgsoftware.superiorskyblock.external.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider;\n\npublic interface StackedBlocksProvider_AutoDetect extends StackedBlocksProvider {\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport org.bukkit.World;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\npublic class StackedBlocksProvider_Default implements StackedBlocksProvider_AutoDetect {\n\n    @Override\n    public Collection<Pair<Key, Integer>> getBlocks(World world, int chunkX, int chunkZ) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java",
    "content": "package com.bgsoftware.superiorskyblock.external.text;\n\npublic interface ITextFormatter {\n\n    String format(String value);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.vanish;\n\nimport com.bgsoftware.superiorskyblock.api.hooks.VanishProvider;\nimport org.bukkit.entity.Player;\nimport org.bukkit.metadata.MetadataValue;\n\npublic class VanishProvider_Default implements VanishProvider {\n\n    @Override\n    public boolean isVanished(Player player) {\n        return player.getMetadata(\"vanished\").stream()\n                .anyMatch(MetadataValue::asBoolean);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java",
    "content": "package com.bgsoftware.superiorskyblock.external.worlds;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport org.bukkit.World;\n\npublic class DefaultWorldLoadListener implements IWorldLoadListener {\n\n    private final LazyReference<DragonBattleService> dragonBattleService = new LazyReference<DragonBattleService>() {\n        @Override\n        protected DragonBattleService create() {\n            return plugin.getServices().getService(DragonBattleService.class);\n        }\n    };\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public DefaultWorldLoadListener(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags) {\n        if ((flags & WorldLoadFlags.END_DRAGON_FIGHT) != 0) {\n            SettingsManager.Worlds.DimensionConfig dimensionConfig =\n                    plugin.getSettings().getWorlds().getDimensionConfig(worldDimension);\n\n            if (worldDimension.getEnvironment() == World.Environment.THE_END &&\n                    dimensionConfig instanceof SettingsManager.Worlds.End &&\n                    ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) {\n                dragonBattleService.get().prepareEndWorld(world);\n            }\n        }\n        if ((flags & WorldLoadFlags.REMOVE_ANTI_XRAY) != 0)\n            plugin.getNMSWorld().removeAntiXray(world);\n        if ((flags & WorldLoadFlags.UPDATE_OCEAN_LEVEL) != 0)\n            plugin.getNMSWorld().setOceanLevel(world);\n        if ((flags & WorldLoadFlags.LISTEN_BLOCK_CHANGES) != 0)\n            plugin.getNMSWorld().listenBlockStateChanges(world);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java",
    "content": "package com.bgsoftware.superiorskyblock.external.worlds;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener;\nimport com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.world.WorldGenerator;\nimport com.google.common.base.Preconditions;\nimport com.google.common.collect.Sets;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Difficulty;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.WorldCreator;\nimport org.bukkit.WorldType;\nimport org.bukkit.block.BlockFace;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class WorldsProvider_Default implements WorldsProvider {\n\n    @WorldLoadFlags\n    private static final int SUPPORTED_LOAD_FLAGS = WorldLoadFlags.END_DRAGON_FIGHT | WorldLoadFlags.REMOVE_ANTI_XRAY |\n            WorldLoadFlags.UPDATE_OCEAN_LEVEL | WorldLoadFlags.LISTEN_BLOCK_CHANGES;\n\n    private final Set<BlockPosition> servedPositions = Sets.newHashSet();\n    private final EnumerateMap<Dimension, World> islandWorlds = new EnumerateMap<>(Dimension.values());\n    private final Map<UUID, Dimension> islandWorldsToDimensions = new HashMap<>();\n    private final List<IWorldLoadListener> worldLoadListenerList = new LinkedList<>();\n    private final SuperiorSkyblockPlugin plugin;\n\n    private World islandsWorld;\n\n    public WorldsProvider_Default(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public void prepareWorlds() {\n        Difficulty difficulty = Difficulty.valueOf(plugin.getSettings().getWorlds().getDifficulty());\n        for (Dimension dimension : Dimension.values()) {\n            SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n            if (dimensionConfig != null && dimensionConfig.isEnabled()) {\n                String worldName = dimensionConfig.getName();\n                World world = loadWorld(worldName, difficulty, dimension);\n                if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension())\n                    this.islandsWorld = world;\n            }\n        }\n    }\n\n    @Override\n    public World getIslandsWorld(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        return islandWorlds.get(dimension);\n    }\n\n    @Override\n    public Dimension getIslandsWorldDimension(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        return islandWorldsToDimensions.get(world.getUID());\n    }\n\n    @Override\n    public boolean isIslandsWorld(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        return islandWorldsToDimensions.containsKey(world.getUID());\n    }\n\n    @Override\n    public Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) {\n        Preconditions.checkNotNull(previousPosition, \"previousPosition parameter cannot be null.\");\n\n        BlockFace islandFace = getIslandFace(previousPosition);\n\n        BlockPosition nextPosition;\n\n        int islandRange = maxIslandSize * 3;\n\n        if (islandFace == BlockFace.NORTH) {\n            nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0);\n        } else if (islandFace == BlockFace.EAST) {\n            if (previousPosition.getX() == -previousPosition.getZ())\n                nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0);\n            else if (previousPosition.getX() == previousPosition.getZ())\n                nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0);\n            else\n                nextPosition = nextPosition(previousPosition, islandsHeight, 0, islandRange);\n        } else if (islandFace == BlockFace.SOUTH) {\n            if (previousPosition.getX() == -previousPosition.getZ())\n                nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange);\n            else\n                nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0);\n        } else if (islandFace == BlockFace.WEST) {\n            if (previousPosition.getX() == previousPosition.getZ())\n                nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0);\n            else\n                nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange);\n        } else {\n            throw new IllegalStateException();\n        }\n\n        Location nextLocation = nextPosition.toLocation(this.islandsWorld);\n\n        if (servedPositions.contains(nextPosition) || plugin.getGrid().getIslandAt(nextLocation) != null) {\n            return getNextLocation(nextPosition, islandsHeight, maxIslandSize, islandOwner, islandUUID);\n        }\n\n        servedPositions.add(nextPosition);\n\n        return nextLocation;\n    }\n\n    @Override\n    public void finishIslandCreation(Location islandLocation, UUID islandOwner, UUID islandUUID) {\n        Preconditions.checkNotNull(islandLocation, \"islandLocation parameter cannot be null.\");\n        servedPositions.remove(SBlockPosition.of(islandLocation));\n    }\n\n    @Override\n    public void prepareTeleport(Island island, Location location, Runnable finishCallback) {\n        finishCallback.run();\n    }\n\n    @Override\n    public boolean isDimensionEnabled(Dimension dimension) {\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        // If the config is null, it probably means another plugin registered it.\n        // Therefore, we register it as enabled.\n        return dimensionConfig == null || dimensionConfig.isEnabled();\n    }\n\n    @Override\n    public boolean isDimensionUnlocked(Dimension dimension) {\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        // If the config is null, it probably means another plugin registered it.\n        // Therefore, we register it as not unlocked by default.\n        return dimensionConfig != null && dimensionConfig.isEnabled() && dimensionConfig.isUnlocked();\n    }\n\n    @Override\n    public void addWorldLoadListener(IWorldLoadListener worldLoadListener) {\n        Preconditions.checkNotNull(worldLoadListener, \"worldLoadListener parameter cannot be null\");\n        this.worldLoadListenerList.add(worldLoadListener);\n    }\n\n    private void notifyWorldLoadListeners(World world, Dimension worldDimension) {\n        for (IWorldLoadListener worldLoadListener : this.worldLoadListenerList)\n            worldLoadListener.onWorldLoad(world, worldDimension, SUPPORTED_LOAD_FLAGS);\n    }\n\n    private BlockFace getIslandFace(BlockPosition blockPosition) {\n        //Possibilities: North / East\n        if (blockPosition.getX() >= blockPosition.getZ()) {\n            return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.NORTH : BlockFace.EAST;\n        }\n        //Possibilities: South / West\n        else {\n            return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.WEST : BlockFace.SOUTH;\n        }\n    }\n\n    private World loadWorld(String worldName, Difficulty difficulty, Dimension dimension) {\n        if (Bukkit.getWorld(worldName) != null) {\n            throw new RuntimeException(\"The world \" + worldName + \" is already loaded. This can occur by one of the following reasons:\\n\" +\n                    \"- Another plugin loaded it manually before SuperiorSkyblock.\\n\" +\n                    \"- Your level-name property in server.properties is set to \" + worldName + \".\");\n        }\n\n        World world = WorldCreator.name(worldName)\n                .type(WorldType.FLAT)\n                .environment(dimension.getEnvironment())\n                .generator(WorldGenerator.getWorldGenerator(dimension))\n                .createWorld();\n\n        world.setDifficulty(difficulty);\n        islandWorlds.put(dimension, world);\n        islandWorldsToDimensions.put(world.getUID(), dimension);\n\n        notifyWorldLoadListeners(world, dimension);\n\n        if (Bukkit.getPluginManager().isPluginEnabled(\"Multiverse-Core\")) {\n            Bukkit.dispatchCommand(Bukkit.getConsoleSender(), \"mv import \" + worldName + \" normal -g \" + plugin.getName());\n            Bukkit.dispatchCommand(Bukkit.getConsoleSender(), \"mv modify set generator \" + plugin.getName() + \" \" + worldName);\n        }\n\n        return world;\n    }\n\n    private static BlockPosition nextPosition(BlockPosition previousPosition, int islandsHeight, int offsetX, int offsetZ) {\n        return SBlockPosition.of(previousPosition.getX() + offsetX, islandsHeight, previousPosition.getZ() + offsetZ);\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, WorldsProvider_Default::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        WorldsProvider worldsProvider = SuperiorSkyblockPlugin.getPlugin().getProviders().getWorldsProvider();\n\n        if (!(worldsProvider instanceof WorldsProvider_Default))\n            return;\n\n        WorldsProvider_Default worldsProviderDefault = (WorldsProvider_Default) worldsProvider;\n        worldsProviderDefault.islandWorlds.values().forEach(SuperiorSkyblockPlugin.getPlugin().getNMSWorld()::setOceanLevel);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.handlers.GridManager;\nimport com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCreationAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.bgsoftware.superiorskyblock.island.preview.IslandPreviews;\nimport com.bgsoftware.superiorskyblock.island.preview.SIslandPreview;\nimport com.bgsoftware.superiorskyblock.island.purge.IslandsPurger;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport com.bgsoftware.superiorskyblock.world.WorldBlocks;\nimport com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic;\nimport com.google.common.base.Preconditions;\nimport com.google.common.collect.Sets;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Function;\n\npublic class GridManagerImpl extends Manager implements GridManager {\n\n    private static final Function<Island, UUID> ISLAND_OWNERS_MAPPER = island -> island.getOwner().getUniqueId();\n\n    private final Set<UUID> pendingCreationTasks = Sets.newHashSet();\n    private final Set<UUID> customWorlds = Sets.newHashSet();\n\n    private final LazyReference<DragonBattleService> dragonBattleService = new LazyReference<DragonBattleService>() {\n        @Override\n        protected DragonBattleService create() {\n            return plugin.getServices().getService(DragonBattleService.class);\n        }\n    };\n\n    private final IslandsPurger islandsPurger;\n    private final IslandPreviews islandPreviews;\n    private IslandsContainer islandsContainer;\n    private DatabaseBridge databaseBridge;\n    private IslandCreationAlgorithm islandCreationAlgorithm;\n\n    private Island spawnIsland;\n    private BlockPosition lastIsland;\n    @Nullable\n    private UUID serverUUID;\n\n    private BigDecimal totalWorth = BigDecimal.ZERO;\n    private long lastTimeWorthUpdate = 0;\n    private BigDecimal totalLevel = BigDecimal.ZERO;\n    private long lastTimeLevelUpdate = 0;\n\n    private boolean pluginDisable = false;\n\n    private boolean forceSort = false;\n\n    private final List<SortingType> pendingSortingTypes = new LinkedList<>();\n    private final AtomicInteger activeCalcTasks = new AtomicInteger(0);\n    private final LazyReference<Synchronized<EnumerateSet<SortingType>>> activeSortingTasks = new LazyReference<Synchronized<EnumerateSet<SortingType>>>() {\n        @Override\n        protected Synchronized<EnumerateSet<SortingType>> create() {\n            return Synchronized.of(new EnumerateSet<>(SortingType.values()));\n        }\n    };\n\n    public GridManagerImpl(SuperiorSkyblockPlugin plugin, IslandsPurger islandsPurger, IslandPreviews islandPreviews) {\n        super(plugin);\n        this.islandsPurger = islandsPurger;\n        this.islandPreviews = islandPreviews;\n    }\n\n    @Override\n    public void loadData() {\n        if (this.islandsContainer == null)\n            throw new RuntimeException(\"GridManager was not initialized correctly. Contact Ome_R regarding this!\");\n\n        initializeDatabaseBridge();\n        if (this.islandCreationAlgorithm == null)\n            this.islandCreationAlgorithm = DefaultIslandCreationAlgorithm.getInstance();\n\n        loadServerUuid();\n\n        this.lastIsland = SBlockPosition.of(0, 100, 0);\n        BukkitExecutor.sync(this::updateSpawn);\n    }\n\n    public void updateSpawn() {\n        try {\n            this.spawnIsland = new SpawnIsland();\n            PluginEventsFactory.callSpawnUpdateEvent();\n        } catch (ManagerLoadException error) {\n            ManagerLoadException.handle(error);\n        }\n    }\n\n    public void syncUpgrades() {\n        getIslands().forEach(Island::updateUpgrades);\n    }\n\n    public UUID getServerUUID() {\n        return serverUUID;\n    }\n\n    @Override\n    public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        Preconditions.checkNotNull(bonus, \"bonus parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        createIsland(superiorPlayer, schematicName, bonus, biome, islandName, false);\n    }\n\n    @Override\n    public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName, boolean offset) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        Preconditions.checkNotNull(bonus, \"bonus parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        createIsland(superiorPlayer, schematicName, bonus, BigDecimal.ZERO, biome, islandName, false);\n    }\n\n    @Override\n    public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth,\n                             BigDecimal bonusLevel, Biome biome, String islandName, boolean offset) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        Preconditions.checkNotNull(bonusWorth, \"bonusWorth parameter cannot be null.\");\n        Preconditions.checkNotNull(bonusLevel, \"bonusLevel parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        createIsland(superiorPlayer, schematicName, bonusWorth, bonusLevel, biome, islandName, offset, null);\n    }\n\n    @Override\n    public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth,\n                             BigDecimal bonusLevel, Biome biome, String islandName, boolean offset,\n                             @Nullable BlockOffset spawnOffset) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        Preconditions.checkNotNull(bonusWorth, \"bonusWorth parameter cannot be null.\");\n        Preconditions.checkNotNull(bonusLevel, \"bonusLevel parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        Island.Builder builder = Island.newBuilder()\n                .setOwner(superiorPlayer)\n                .setSchematicName(schematicName)\n                .setName(islandName);\n\n        if (!offset) {\n            builder.setBonusWorth(bonusWorth)\n                    .setBonusLevel(bonusLevel);\n        }\n\n        createIsland(builder, biome, offset, spawnOffset);\n    }\n\n    @Override\n    public void createIsland(Island.Builder builderParam, Biome biome, boolean offset) {\n        Preconditions.checkNotNull(builderParam, \"builder parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkArgument(builderParam instanceof IslandBuilderImpl, \"Cannot create islands out of a custom builder.\");\n        createIsland(builderParam, biome, offset, null);\n    }\n\n    @Override\n    public void createIsland(Island.Builder builderParam, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset) {\n        Preconditions.checkNotNull(builderParam, \"builder parameter cannot be null.\");\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n        Preconditions.checkArgument(builderParam instanceof IslandBuilderImpl, \"Cannot create islands out of a custom builder.\");\n\n        IslandBuilderImpl builder = (IslandBuilderImpl) builderParam;\n\n        Preconditions.checkArgument(builder.owner != null, \"Cannot create an island with an invalid owner.\");\n\n        Schematic schematic = builder.islandType == null ? null : plugin.getSchematics().getSchematic(builder.islandType);\n\n        Preconditions.checkArgument(schematic != null, \"Cannot create an island with an invalid schematic.\");\n\n        try {\n            if (!Bukkit.isPrimaryThread()) {\n                BukkitExecutor.sync(() -> createIslandInternalAsync(builder, biome, offset, schematic, spawnOffset));\n            } else {\n                createIslandInternalAsync(builder, biome, offset, schematic, spawnOffset);\n            }\n        } catch (Throwable error) {\n            Log.entering(\"ENTER\", builder.owner.getName(), builder.islandType, biome, offset);\n            Log.error(error, \"An unexpected error occurred while creating an island:\");\n            builder.owner.setIsland(null);\n            Message.CREATE_ISLAND_FAILURE.send(builder.owner);\n        }\n    }\n\n    private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, boolean offset,\n                                           Schematic schematic, @Nullable BlockOffset spawnOffset) {\n        assert builder.owner != null;\n\n        Log.debug(Debug.CREATE_ISLAND, builder.owner.getName(), builder.bonusWorth, builder.bonusLevel,\n                builder.islandName, offset, biome, schematic.getName());\n\n        // Removing any active previews for the player.\n        boolean updateGameMode = this.islandPreviews.endIslandPreview(builder.owner) != null;\n\n        if (!PluginEventsFactory.callPreIslandCreateEvent(builder.owner, builder.islandName))\n            return;\n\n        builder.setUniqueId(generateIslandUUID());\n\n        long startTime = System.currentTimeMillis();\n\n        pendingCreationTasks.add(builder.owner.getUniqueId());\n\n        this.islandCreationAlgorithm.createIsland(builder, this.lastIsland).whenComplete((islandCreationResult, error) -> {\n\n            pendingCreationTasks.remove(builder.owner.getUniqueId());\n\n            if (error == null && islandCreationResult != null) {\n                Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Successfully created island\");\n\n                try {\n                    createIslandInternalOnSuccessCallback(builder, biome, offset, spawnOffset,\n                            schematic, updateGameMode, startTime, islandCreationResult);\n                    return;\n                } catch (Throwable runtimeError) {\n                    error = runtimeError;\n                }\n            }\n\n            Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Failed to create island\");\n\n            Log.entering(builder.owner.getName(), builder.bonusWorth, builder.bonusLevel, builder.islandName,\n                    offset, biome, schematic.getName());\n\n            if (error != null)\n                Log.error(error, \"An unexpected error occurred while creating an island:\");\n\n            builder.owner.setIsland(null);\n\n            Message.CREATE_ISLAND_FAILURE.send(builder.owner);\n        });\n    }\n\n    private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Biome biome, boolean offset,\n                                                       @Nullable BlockOffset spawnOffset, Schematic schematic,\n                                                       boolean updateGameMode, long startTime,\n                                                       IslandCreationAlgorithm.IslandCreationResult islandCreationResult) {\n        switch (islandCreationResult.getStatus()) {\n            case NAME_OCCUPIED:\n                builder.owner.setIsland(null);\n                Message.ISLAND_ALREADY_EXIST.send(builder.owner);\n                Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Island already exists\");\n                return;\n            case EVENT_CANCELLED:\n                builder.owner.setIsland(null);\n                Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Island creation event was cancelled\");\n                return;\n            case SUCCESS:\n                break;\n            default:\n                throw new RuntimeException(\"Cannot handle creation status: \" + islandCreationResult.getStatus());\n        }\n\n        Island island = islandCreationResult.getIsland();\n        Location islandLocation = islandCreationResult.getIslandLocation();\n        boolean teleportPlayer = islandCreationResult.shouldTeleportPlayer();\n\n        List<ChunkPosition> affectedChunks = schematic instanceof BaseSchematic ?\n                ((BaseSchematic) schematic).getAffectedChunks() : null;\n        Runnable onTeleportCallback = schematic instanceof BaseSchematic ?\n                ((BaseSchematic) schematic).onTeleportCallback() : null;\n\n        Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Registering new island\");\n\n        this.islandsContainer.addIsland(island);\n        setLastIslandPosition(SBlockPosition.of(islandLocation));\n\n        Dimension defaultDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n\n        try {\n            island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE);\n\n            island.setBiome(biome, false);\n            island.setSchematicGenerate(defaultDimension);\n            island.setCurrentlyActive(true);\n\n            if (offset) {\n                island.setBonusWorth(island.getRawWorth().negate());\n                island.setBonusLevel(island.getRawLevel().negate());\n            }\n        } finally {\n            island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n        }\n\n        IslandsDatabaseBridge.insertIsland(island, affectedChunks);\n\n        Location homeLocation = schematic.adjustRotation(islandLocation);\n        if (spawnOffset != null)\n            homeLocation = spawnOffset.applyToLocation(homeLocation);\n\n        island.setIslandHome(defaultDimension, SWorldPosition.of(homeLocation));\n\n        BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> {\n            if (updateGameMode)\n                player.setGameMode(GameMode.SURVIVAL);\n\n            if (!teleportPlayer) {\n                Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Do not teleport player\");\n\n                Message.CREATE_ISLAND.send(builder.owner, Formatters.LOCATION_FORMATTER.format(\n                        islandLocation), System.currentTimeMillis() - startTime);\n            } else {\n                Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\", \"Teleporting player\");\n\n                builder.owner.teleport(island, result -> {\n                    Log.debugResult(Debug.CREATE_ISLAND, \"Creation Callback\",\n                            \"Teleported player. Result: \" + result);\n\n                    Message.CREATE_ISLAND.send(builder.owner, Formatters.LOCATION_FORMATTER.format(\n                            islandLocation), System.currentTimeMillis() - startTime);\n\n                    if (result) {\n                        if (affectedChunks != null) {\n                            BukkitExecutor.sync(() -> {\n                                IslandUtils.resetChunksExcludedFromList(island, affectedChunks);\n                                island.setBiome(biome, true);\n                            }, 10L);\n                        }\n\n                        if (defaultDimension.getEnvironment() == World.Environment.THE_END) {\n                            plugin.getNMSDragonFight().awardTheEndAchievement(player);\n                            this.dragonBattleService.get().resetEnderDragonBattle(island, defaultDimension);\n                        }\n\n                        PluginEventsFactory.callPostIslandCreateEvent(island, builder.owner);\n\n                        if (onTeleportCallback != null)\n                            onTeleportCallback.run();\n                    }\n                });\n            }\n        }), 1L);\n    }\n\n    @Override\n    public void setIslandCreationAlgorithm(@Nullable IslandCreationAlgorithm islandCreationAlgorithm) {\n        this.islandCreationAlgorithm = islandCreationAlgorithm != null ? islandCreationAlgorithm :\n                DefaultIslandCreationAlgorithm.getInstance();\n    }\n\n    @Override\n    public IslandCreationAlgorithm getIslandCreationAlgorithm() {\n        return Optional.ofNullable(this.islandCreationAlgorithm).orElse(DefaultIslandCreationAlgorithm.getInstance());\n    }\n\n    @Override\n    public boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return pendingCreationTasks.contains(superiorPlayer.getUniqueId());\n    }\n\n    @Override\n    public void startIslandPreview(SuperiorPlayer superiorPlayer, String schematicName, String islandName) {\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        startIslandPreview(superiorPlayer, plugin.getSchematics().getSchematic(schematicName), islandName);\n    }\n\n    public void startIslandPreview(SuperiorPlayer superiorPlayer, Schematic schematic, String islandName) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(schematic, \"schematic parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n\n        Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH));\n        if (previewLocation != null && previewLocation.getWorld() != null) {\n            superiorPlayer.teleport(previewLocation, result -> {\n                if (result) {\n                    this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schematic, islandName, superiorPlayer.asPlayer().getGameMode()));\n                    BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> player.setGameMode(plugin.getSettings().getIslandPreviews().getGameMode())));\n                    Message.ISLAND_PREVIEW_START.send(superiorPlayer, schematic.getName());\n                }\n            });\n        }\n    }\n\n    @Override\n    public void cancelIslandPreview(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        IslandPreview islandPreview = this.islandPreviews.endIslandPreview(superiorPlayer);\n        if (islandPreview != null) {\n            superiorPlayer.runIfOnline(player -> {\n                BukkitExecutor.ensureMain(() -> superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), teleportResult -> {\n                    if (teleportResult && superiorPlayer.isOnline())\n                        player.setGameMode(islandPreview.getPreviousGameMode());\n                }));\n                PlayerChat.remove(player);\n            });\n        }\n    }\n\n    @Override\n    public void cancelAllIslandPreviews() {\n        if (!Bukkit.isPrimaryThread()) {\n            BukkitExecutor.sync(this::cancelAllIslandPreviewsSync);\n        } else {\n            cancelAllIslandPreviewsSync();\n        }\n    }\n\n    private void cancelAllIslandPreviewsSync() {\n        if (!Bukkit.isPrimaryThread()) {\n            Log.warn(\"Trying to cancel all island previews asynchronous. Stack trace:\");\n            new Exception().printStackTrace();\n        }\n\n        this.islandPreviews.getActivePreviews().forEach(islandPreview -> {\n            SuperiorPlayer superiorPlayer = islandPreview.getPlayer();\n            superiorPlayer.runIfOnline(player -> {\n                superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                // We don't wait for the teleport to happen, as this method is called when the server is disabled.\n                // Therefore, we can't wait for the async task to occur.\n                player.setGameMode(GameMode.SURVIVAL);\n                PlayerChat.remove(player);\n            });\n        });\n    }\n\n    @Override\n    public IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return this.islandPreviews.getIslandPreview(superiorPlayer);\n    }\n\n    @Override\n    public void deleteIsland(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n\n        Log.debug(Debug.DELETE_ISLAND, island.getOwner().getName());\n\n        island.getAllPlayersInside().forEach(superiorPlayer -> {\n            MenuView<?, ?> openedView = superiorPlayer.getOpenedView();\n            if (openedView != null)\n                openedView.closeView();\n\n            island.removeEffects(superiorPlayer);\n\n            superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n            Message.ISLAND_GOT_DELETED_WHILE_INSIDE.send(superiorPlayer);\n        });\n\n        this.islandsContainer.removeIsland(island);\n\n        // Delete island from database\n        IslandsDatabaseBridge.deleteIsland(island);\n\n        for (Dimension dimension : Dimension.values()) {\n            if (dimension.getEnvironment() == World.Environment.THE_END)\n                this.dragonBattleService.get().stopEnderDragonBattle(island, dimension);\n        }\n    }\n\n    @Override\n    public Island getIsland(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return superiorPlayer.getIsland();\n    }\n\n    @Override\n    public Island getIsland(int index, SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        return this.islandsContainer.getIslandAtPosition(index, sortingType);\n    }\n\n    @Override\n    public int getIslandPosition(Island island, SortingType sortingType) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        return this.islandsContainer.getIslandPosition(island, sortingType);\n    }\n\n    @Override\n    public Island getIsland(UUID uuid) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid);\n        return superiorPlayer == null ? null : getIsland(superiorPlayer);\n    }\n\n    @Override\n    public Island getIslandByUUID(UUID uuid) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        return this.islandsContainer.getIslandByUUID(uuid);\n    }\n\n    @Override\n    public Island getIsland(String islandName) {\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        return this.islandsContainer.getIslandByName(islandName);\n    }\n\n    @Override\n    public Island getIslandAt(@Nullable Location location) {\n        if (location == null)\n            return null;\n\n        World world = location.getWorld();\n        if (world == null)\n            return null;\n\n        if (spawnIsland != null && spawnIsland.isInside(location))\n            return spawnIsland;\n\n        return this.islandsContainer.getIslandAt(location);\n    }\n\n    @Override\n    @Deprecated\n    public Island getIslandAt(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk argument cannot be null\");\n\n        if (!plugin.getGrid().isIslandsWorld(chunk.getWorld()))\n            return null;\n\n        Location cornerLocation;\n        try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n            cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0);\n        }\n\n        Island island;\n\n        // Checks corner at 0, y, 0\n        if ((island = getIslandAt(cornerLocation)) != null)\n            return island;\n\n        // Checks corner at 15, y, 0\n        cornerLocation.add(15, 0, 0);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            return island;\n\n        // Checks corner at 15, y, 15\n        cornerLocation.add(0, 0, 15);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            return island;\n\n        // Checks corner at 0, y, 15\n        cornerLocation.add(-15, 0, 0);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            return island;\n\n        return null;\n    }\n\n    @Override\n    public List<Island> getIslandsAt(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk argument cannot be null\");\n\n        if (!plugin.getGrid().isIslandsWorld(chunk.getWorld()))\n            return Collections.emptyList();\n\n        Set<Island> islands = new LinkedHashSet<>();\n\n        Location cornerLocation;\n        try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n            cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0);\n        }\n\n        Island island;\n\n        // Checks corner at 0, y, 0\n        if ((island = getIslandAt(cornerLocation)) != null)\n            islands.add(island);\n\n        // Checks corner at 15, y, 0\n        cornerLocation.add(15, 0, 0);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            islands.add(island);\n\n        // Checks corner at 15, y, 15\n        cornerLocation.add(0, 0, 15);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            islands.add(island);\n\n        // Checks corner at 0, y, 15\n        cornerLocation.add(-15, 0, 0);\n        if ((island = getIslandAt(cornerLocation)) != null)\n            islands.add(island);\n\n        return islands.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new LinkedList<>(islands));\n    }\n\n    @Override\n    public void transferIsland(UUID oldOwner, UUID newOwner) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getSize() {\n        return this.islandsContainer.getIslandsAmount();\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        sortIslands(sortingType, null);\n    }\n\n    public void forceSortIslands(SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        setForceSort(true);\n        sortIslands(sortingType, null);\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType, @Nullable Runnable onFinish) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n\n        Log.debug(Debug.SORT_ISLANDS, sortingType.getName());\n\n        boolean isSortedAlready = activeSortingTasks.get().readAndGet(\n                activeSortingTasks -> activeSortingTasks.contains(sortingType));\n        if (isSortedAlready) {\n            if (onFinish != null)\n                onFinish.run();\n            forceSort = false;\n            return;\n        }\n\n        activeSortingTasks.get().write(activeSortingTasks -> activeSortingTasks.add(sortingType));\n\n        this.islandsContainer.sortIslands(sortingType, forceSort, () -> {\n            plugin.getMenus().refreshTopIslands(sortingType);\n            activeSortingTasks.get().write(activeSortingTasks -> activeSortingTasks.remove(sortingType));\n            if (onFinish != null)\n                onFinish.run();\n        });\n\n        forceSort = false;\n    }\n\n    public void setForceSort(boolean forceSort) {\n        this.forceSort = forceSort;\n    }\n\n    @Override\n    public Island getSpawnIsland() {\n        if (spawnIsland == null)\n            updateSpawn();\n\n        return spawnIsland;\n    }\n\n    @Override\n    public World getIslandsWorld(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        if (island.isSpawn()) {\n            if (island instanceof SpawnIsland)\n                return ((SpawnIsland) island).getSpawnWorld();\n\n            return island.getIslandHome(dimension).getWorld();\n        }\n\n        return plugin.getProviders().getWorldsProvider().getIslandsWorld(island, dimension);\n    }\n\n    @Override\n    public Dimension getIslandsWorldDimension(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n\n        if (!isIslandsWorld(world))\n            return null;\n\n        if (customWorlds.contains(world.getUID()))\n            return Dimension.getByName(world.getName().toUpperCase(Locale.ENGLISH));\n\n        return plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world);\n    }\n\n    @Override\n    public WorldInfo getIslandsWorldInfo(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        if (island.isSpawn()) {\n            if (island instanceof SpawnIsland)\n                return ((SpawnIsland) island).getSpawnWorldInfo();\n\n            return WorldInfo.of(island.getIslandHome(dimension).getWorld());\n        }\n\n        WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider();\n\n        if (worldsProvider instanceof LazyWorldsProvider)\n            return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, dimension);\n\n        World world = this.getIslandsWorld(island, dimension);\n        return world == null ? null : WorldInfo.of(world);\n    }\n\n    @Nullable\n    @Override\n    public WorldInfo getIslandsWorldInfo(Island island, String worldName) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null.\");\n\n        if (island.isSpawn()) {\n            if (island instanceof SpawnIsland)\n                return ((SpawnIsland) island).getSpawnWorldInfo();\n\n            return WorldInfo.of(island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getWorld());\n        }\n\n        WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider();\n\n        if (worldsProvider instanceof LazyWorldsProvider)\n            return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, worldName);\n\n        World world = Bukkit.getWorld(worldName);\n        return world == null || !isIslandsWorld(world) ? null : WorldInfo.of(world);\n    }\n\n    @Override\n    public boolean isIslandsWorld(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        return customWorlds.contains(world.getUID()) || plugin.getProviders().getWorldsProvider().isIslandsWorld(world);\n    }\n\n    @Override\n    public void registerIslandWorld(World world) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n\n        String dimensionName = world.getName().toUpperCase(Locale.ENGLISH);\n        try {\n            Dimension.register(dimensionName, world.getEnvironment());\n        } catch (Exception error) {\n            throw new IllegalArgumentException(\"Dimension with the name \" + dimensionName + \" already exists.\");\n        }\n\n        customWorlds.add(world.getUID());\n    }\n\n    @Override\n    public List<World> getRegisteredWorlds() {\n        return new SequentialListBuilder<World>().build(customWorlds, Bukkit::getWorld);\n    }\n\n    @Override\n    @Deprecated\n    public List<UUID> getAllIslands(SortingType sortingType) {\n        return new SequentialListBuilder<UUID>()\n                .build(getIslands(sortingType), ISLAND_OWNERS_MAPPER);\n    }\n\n    @Override\n    public List<Island> getIslands() {\n        return this.islandsContainer.getIslandsUnsorted();\n    }\n\n    @Override\n    public List<Island> getIslands(SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n        return this.islandsContainer.getSortedIslands(sortingType);\n    }\n\n    @Override\n    @Deprecated\n    public int getBlockAmount(Block block) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return getBlockAmount(block.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    @Override\n    @Deprecated\n    public int getBlockAmount(Location location) {\n        return plugin.getStackedBlocks().getStackedBlockAmount(location);\n    }\n\n    @Override\n    @Deprecated\n    public void setBlockAmount(Block block, int amount) {\n        plugin.getStackedBlocks().setStackedBlock(block, amount);\n    }\n\n    @Override\n    public List<Location> getStackedBlocks() {\n        return new SequentialListBuilder<Location>().build(plugin.getStackedBlocks().getStackedBlocks().keySet());\n    }\n\n    @Override\n    public void calcAllIslands() {\n        calcAllIslands(null);\n    }\n\n    @Override\n    public void calcAllIslands(Runnable callback) {\n        Log.debug(Debug.CALCULATE_ALL_ISLANDS);\n\n        List<Island> islands = new ArrayList<>();\n\n        {\n            for (Island island : this.islandsContainer.getIslandsUnsorted()) {\n                if (!island.isBeingRecalculated())\n                    islands.add(island);\n            }\n        }\n\n        for (int i = 0; i < islands.size(); i++) {\n            islands.get(i).calcIslandWorth(null, i + 1 < islands.size() ? null : callback);\n        }\n    }\n\n    public void startCalcTask() {\n        this.activeCalcTasks.incrementAndGet();\n    }\n\n    public boolean stopCalcTask() {\n        int activeCalcTasks = this.activeCalcTasks.decrementAndGet();\n        if (activeCalcTasks < 0)\n            throw new IllegalStateException();\n        return activeCalcTasks == 0;\n    }\n\n    @Override\n    public void addIslandToPurge(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(island.getOwner(), \"island's owner cannot be null.\");\n\n        Log.debug(Debug.PURGE_ISLAND, island.getOwner().getName());\n\n        this.islandsPurger.scheduleIslandPurge(island);\n    }\n\n    @Override\n    public void removeIslandFromPurge(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(island.getOwner(), \"island's owner cannot be null.\");\n\n        Log.debug(Debug.UNPURGE_ISLAND, island.getOwner().getName());\n\n        this.islandsPurger.unscheduleIslandPurge(island);\n    }\n\n    @Override\n    public boolean isIslandPurge(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null.\");\n        Preconditions.checkNotNull(island.getOwner(), \"island's owner cannot be null.\");\n        return this.islandsPurger.isIslandPurgeScheduled(island);\n    }\n\n    @Override\n    public List<Island> getIslandsToPurge() {\n        return this.islandsPurger.getScheduledPurgedIslands();\n    }\n\n    @Override\n    public void registerSortingType(SortingType sortingType) {\n        Preconditions.checkNotNull(sortingType, \"sortingType parameter cannot be null.\");\n\n        Log.debug(Debug.REGISTER_SORTING_TYPE, sortingType.getName());\n\n        if (this.islandsContainer == null) {\n            pendingSortingTypes.add(sortingType);\n        } else {\n            this.islandsContainer.addSortingType(sortingType, true);\n        }\n    }\n\n    @Override\n    public BigDecimal getTotalWorth() {\n        long currentTime = System.currentTimeMillis();\n\n        if (currentTime - lastTimeWorthUpdate > 60000) {\n            lastTimeWorthUpdate = currentTime;\n            totalWorth = BigDecimal.ZERO;\n            for (Island island : getIslands())\n                totalWorth = totalWorth.add(island.getWorth());\n        }\n\n        return totalWorth;\n    }\n\n    @Override\n    public BigDecimal getTotalLevel() {\n        long currentTime = System.currentTimeMillis();\n\n        if (currentTime - lastTimeLevelUpdate > 60000) {\n            lastTimeLevelUpdate = currentTime;\n            totalLevel = BigDecimal.ZERO;\n            for (Island island : getIslands())\n                totalLevel = totalLevel.add(island.getIslandLevel());\n        }\n\n        return totalLevel;\n    }\n\n    @Override\n    @Deprecated\n    public Location getLastIslandLocation() {\n        return lastIsland.toLocation((World) null);\n    }\n\n    @Override\n    @Deprecated\n    public void setLastIslandLocation(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null\");\n        setLastIslandPosition(SBlockPosition.of(location));\n    }\n\n    @Override\n    public BlockPosition getLastIslandPosition() {\n        return this.lastIsland;\n    }\n\n    @Override\n    public void setLastIslandPosition(BlockPosition lastIsland) {\n        Preconditions.checkNotNull(lastIsland, \"lastIsland parameter cannot be null\");\n\n        Log.debug(Debug.SET_LAST_ISLAND, lastIsland);\n\n        if (Objects.equals(this.lastIsland, lastIsland))\n            return;\n\n        this.lastIsland = lastIsland;\n        GridDatabaseBridge.saveLastIsland(this, lastIsland);\n    }\n\n    @Override\n    public IslandsContainer getIslandsContainer() {\n        return this.islandsContainer;\n    }\n\n    @Override\n    public void setIslandsContainer(IslandsContainer islandsContainer) {\n        Preconditions.checkNotNull(islandsContainer, \"islandsContainer parameter cannot be null\");\n        this.islandsContainer = islandsContainer;\n        pendingSortingTypes.forEach(sortingType -> islandsContainer.addSortingType(sortingType, false));\n        pendingSortingTypes.clear();\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return databaseBridge;\n    }\n\n    public UUID generateIslandUUID() {\n        UUID uuid;\n\n        do {\n            uuid = UUID.randomUUID();\n        } while (getIslandByUUID(uuid) != null || plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid) != null);\n\n        return uuid;\n    }\n\n    public void disablePlugin() {\n        this.pluginDisable = true;\n        cancelAllIslandPreviews();\n    }\n\n    public boolean wasPluginDisabled() {\n        return this.pluginDisable;\n    }\n\n    public void loadGrid(DatabaseResult resultSet) {\n        resultSet.getString(\"last_island\").map(Serializers.BLOCK_POSITION_SERIALIZER::deserialize)\n                .ifPresent(lastIsland -> this.lastIsland = lastIsland);\n\n        int maxIslandSize = resultSet.getInt(\"max_island_size\").orElse(plugin.getSettings().getMaxIslandSize());\n        String world = resultSet.getString(\"world\").orElse(plugin.getSettings().getWorlds().getDefaultWorldName());\n\n        try {\n            if (plugin.getSettings().getMaxIslandSize() != maxIslandSize) {\n                Log.warn(\"You have changed the max-island-size value without deleting database.\");\n                Log.warn(\"Restoring it to the old value...\");\n                plugin.getSettings().updateValue(\"max-island-size\", maxIslandSize);\n            }\n\n            if (!plugin.getSettings().getWorlds().getDefaultWorldName().equals(world)) {\n                Log.warn(\"You have changed the island-world value without deleting database.\");\n                Log.warn(\"Restoring it to the old value...\");\n                plugin.getSettings().updateValue(\"worlds.normal-world\", world);\n            }\n        } catch (IOException error) {\n            Log.error(error, \"An unexpected error occurred while loading grid:\");\n            Bukkit.shutdown();\n        }\n    }\n\n    public void saveIslands() {\n        List<Island> onlineIslands = new SequentialListBuilder<Island>()\n                .filter(Objects::nonNull)\n                .build(Bukkit.getOnlinePlayers(), player -> plugin.getPlayers().getSuperiorPlayer(player).getIsland());\n\n        List<Island> modifiedIslands = new SequentialListBuilder<Island>()\n                .filter(IslandsDatabaseBridge::isModified)\n                .build(getIslands());\n\n        if (!onlineIslands.isEmpty())\n            onlineIslands.forEach(Island::updateLastTime);\n\n        if (!modifiedIslands.isEmpty())\n            modifiedIslands.forEach(IslandsDatabaseBridge::executeFutureSaves);\n\n        getIslands().forEach(Island::removeEffects);\n    }\n\n    private void initializeDatabaseBridge() {\n        databaseBridge = plugin.getFactory().createDatabaseBridge(this);\n        databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n    }\n\n    private void loadServerUuid() {\n        File bStatsFile = new File(plugin.getDataFolder().getParentFile(), \"bStats/config.yml\");\n        if (!bStatsFile.exists())\n            return;\n\n        YamlConfiguration config = YamlConfiguration.loadConfiguration(bStatsFile);\n        if (!config.isString(\"serverUuid\"))\n            return;\n\n        try {\n            this.serverUUID = UUID.fromString(config.getString(\"serverUuid\"));\n        } catch (Exception ignored) {\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Bukkit;\nimport org.bukkit.ChatColor;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport javax.annotation.Nullable;\nimport java.util.Collections;\nimport java.util.Locale;\n\npublic class IslandNames {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private IslandNames() {\n\n    }\n\n    public static boolean isValidName(SuperiorPlayer superiorPlayer, @Nullable Island currentIsland, String islandName) {\n        return isValidName(superiorPlayer.asPlayer(), currentIsland, islandName);\n    }\n\n    public static boolean isValidName(CommandSender sender, Island currentIsland, String islandName) {\n        String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName);\n\n        int maxLength = plugin.getSettings().getIslandNames().getMaxLength();\n        int minLength = plugin.getSettings().getIslandNames().getMinLength();\n\n        if (strippedName.length() > maxLength) {\n            Message.NAME_TOO_LONG.send(sender, maxLength);\n            return false;\n        }\n\n        if (strippedName.length() < minLength) {\n            Message.NAME_TOO_SHORT.send(sender, minLength);\n            return false;\n        }\n\n        if (plugin.getSettings().getIslandNames().isPreventPlayerNames() && plugin.getPlayers().getSuperiorPlayer(strippedName) != null) {\n            Message.NAME_SAME_AS_PLAYER.send(sender);\n            return false;\n        }\n\n        String lookupName = islandName.toLowerCase(Locale.ENGLISH);\n        if (plugin.getSettings().getIslandNames().getFilteredNames().stream().anyMatch(lookupName::contains)) {\n            Message.NAME_BLACKLISTED.send(sender);\n            return false;\n        }\n\n        if (currentIsland != null) {\n            String formattedName = Formatters.COLOR_FORMATTER.format(islandName);\n\n            if (currentIsland.getFormattedName().equalsIgnoreCase(formattedName)) {\n                Message.SAME_NAME_CHANGE.send(sender);\n                return false;\n            }\n        }\n\n        Island islandWithName = plugin.getGrid().getIsland(strippedName);\n        if (islandWithName != null && islandWithName != currentIsland) {\n            Message.ISLAND_ALREADY_EXIST.send(sender);\n            return false;\n        }\n\n        return true;\n    }\n\n    public static void announceChange(Island island, Message message, Object... args) {\n        if (plugin.getSettings().getIslandNames().isAnnounceChangeToAll())\n            for (Player player : Bukkit.getOnlinePlayers())\n                message.send(player, args);\n        else\n            IslandUtils.sendMessage(island, message, Collections.emptyList(), args);\n    }\n\n    public static String getNameForDatabase(Island island) {\n        return island.getFormattedName().replace(ChatColor.COLOR_CHAR, '&');\n    }\n\n    public static String getNameForLookup(String name) {\n        return Formatters.STRIP_COLOR_FORMATTER.format(name).toLowerCase(Locale.ENGLISH);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic class IslandUtils {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final EnumerateMap<Dimension, Biome> DEFAULT_WORLD_BIOMES = new EnumerateMap<>(Dimension.values());\n\n    private static Biome getDefaultBiomeForEnvironment(World.Environment environment) {\n        switch (environment) {\n            case NORMAL:\n                return Biome.PLAINS;\n            case NETHER:\n                return Optional.ofNullable(EnumHelper.getEnum(Biome.class, \"NETHER_WASTES\", \"NETHER\", \"HELL\"))\n                        .orElseThrow(IllegalArgumentException::new);\n            case THE_END:\n                return Optional.ofNullable(EnumHelper.getEnum(Biome.class, \"THE_END\", \"SKY\"))\n                        .orElseThrow(IllegalArgumentException::new);\n        }\n\n        throw new IllegalArgumentException();\n    }\n\n    static {\n        for (Dimension dimension : Dimension.values()) {\n            Biome biome = Optional.ofNullable(plugin.getSettings().getWorlds().getDimensionConfig(dimension))\n                    .map(config -> plugin.getNMSAlgorithms().getBiome(config.getBiome()))\n                    .orElseGet(() -> getDefaultBiomeForEnvironment(dimension.getEnvironment()));\n            DEFAULT_WORLD_BIOMES.put(dimension, biome);\n        }\n    }\n\n    private IslandUtils() {\n\n    }\n\n    public static List<ChunkPosition> getChunkCoords(Island island, WorldInfo worldInfo, @IslandChunkFlags int flags) {\n        List<ChunkPosition> chunkCoords = new LinkedList<>();\n\n        boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0;\n        boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0;\n\n        BlockPosition min = onlyProtected ? island.getMinimumProtectedPosition() : island.getMinimumPosition();\n        BlockPosition max = onlyProtected ? island.getMaximumProtectedPosition() : island.getMaximumPosition();\n\n        for (int x = min.getX() >> 4; x <= max.getX() >> 4; x++) {\n            for (int z = min.getZ() >> 4; z <= max.getZ() >> 4; z++) {\n                if (!noEmptyChunks || island.isChunkDirty(worldInfo.getName(), x, z)) {\n                    chunkCoords.add(ChunkPosition.of(worldInfo, x, z, false));\n                }\n            }\n        }\n\n        return chunkCoords;\n    }\n\n    public static Map<WorldInfo, List<ChunkPosition>> getChunkCoords(Island island, @IslandChunkFlags int flags) {\n        Map<WorldInfo, List<ChunkPosition>> chunkCoords = new ArrayMap<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) {\n                WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n                List<ChunkPosition> chunkPositions = getChunkCoords(island, worldInfo, flags);\n                if (!chunkPositions.isEmpty())\n                    chunkCoords.put(worldInfo, chunkPositions);\n            }\n        }\n\n        for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) {\n            WorldInfo worldInfo = WorldInfo.of(registeredWorld);\n            List<ChunkPosition> chunkPositions = getChunkCoords(island, worldInfo, flags);\n            if (!chunkPositions.isEmpty())\n                chunkCoords.put(worldInfo, chunkPositions);\n        }\n\n        return chunkCoords;\n    }\n\n    public static List<CompletableFuture<Chunk>> getAllChunksAsync(Island island, WorldInfo worldInfo, @IslandChunkFlags int flags,\n                                                                   ChunkLoadReason chunkLoadReason,\n                                                                   Consumer<Chunk> onChunkLoad) {\n        return new SequentialListBuilder<CompletableFuture<Chunk>>()\n                .mutable()\n                .build(IslandUtils.getChunkCoords(island, worldInfo, flags), chunkPosition ->\n                        ChunksProvider.loadChunk(chunkPosition, chunkLoadReason, onChunkLoad));\n    }\n\n    public static List<CompletableFuture<Chunk>> getAllChunksAsync(Island island, @IslandChunkFlags int flags,\n                                                                   ChunkLoadReason chunkLoadReason,\n                                                                   Consumer<Chunk> onChunkLoad) {\n        List<CompletableFuture<Chunk>> chunkCoords = new LinkedList<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) {\n                WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n                chunkCoords.addAll(getAllChunksAsync(island, worldInfo, flags, chunkLoadReason, onChunkLoad));\n            }\n        }\n\n        for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) {\n            chunkCoords.addAll(getAllChunksAsync(island, WorldInfo.of(registeredWorld), flags, chunkLoadReason, onChunkLoad));\n        }\n\n        return chunkCoords;\n    }\n\n    public static void updateIslandFly(Island island, SuperiorPlayer superiorPlayer) {\n        superiorPlayer.runIfOnline(player -> {\n            if (!player.getAllowFlight() && superiorPlayer.hasIslandFlyEnabled() && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) {\n                player.setAllowFlight(true);\n                player.setFlying(true);\n                Message.ISLAND_FLY_ENABLED.send(player);\n            } else if (player.getAllowFlight() && !island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) {\n                player.setAllowFlight(false);\n                player.setFlying(false);\n                Message.ISLAND_FLY_DISABLED.send(player);\n            }\n        });\n    }\n\n    public static void updateTradingMenus(Island island, SuperiorPlayer superiorPlayer) {\n        superiorPlayer.runIfOnline(player -> {\n            Inventory openInventory = player.getOpenInventory().getTopInventory();\n            if (openInventory != null && openInventory.getType() == InventoryType.MERCHANT && !island.hasPermission(superiorPlayer, IslandPrivileges.VILLAGER_TRADING))\n                player.closeInventory();\n        });\n    }\n\n    public static void resetChunksExcludedFromList(Island island, Collection<ChunkPosition> excludedChunkPositions) {\n        Map<WorldInfo, List<ChunkPosition>> chunksToDelete = IslandUtils.getChunkCoords(island, 0);\n        chunksToDelete.values().forEach(chunkPositions -> {\n            List<ChunkPosition> clonedChunkPositions = new LinkedList<>(chunkPositions);\n            clonedChunkPositions.removeAll(excludedChunkPositions);\n            deleteChunks(island, clonedChunkPositions, null);\n        });\n    }\n\n    public static void sendMessage(Island island, Message message, List<UUID> ignoredMembers, Object... args) {\n        for (SuperiorPlayer islandMember : island.getIslandMembers(true)) {\n            if (!ignoredMembers.contains(islandMember.getUniqueId()))\n                message.send(islandMember, args);\n        }\n    }\n\n    public static double getGeneratorPercentageDecimal(Island island, Key key, Dimension dimension) {\n        int totalAmount = island.getGeneratorTotalAmount(dimension);\n        return totalAmount == 0 ? 0 : (island.getGeneratorAmount(key, dimension) * 100D) / totalAmount;\n    }\n\n    public static boolean checkTransferRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) {\n        if (!superiorPlayer.getPlayerRole().isLastRole()) {\n            Message.NO_TRANSFER_PERMISSION.send(superiorPlayer);\n            return false;\n        }\n\n        if (!island.isMember(targetPlayer)) {\n            Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer);\n            return false;\n        }\n\n        if (island.getOwner().getUniqueId().equals(targetPlayer.getUniqueId())) {\n            Message.TRANSFER_ALREADY_LEADER.send(superiorPlayer);\n            return false;\n        }\n\n        return true;\n    }\n\n    public static void handleTransferIsland(SuperiorPlayer caller, Island island, SuperiorPlayer target) {\n        if (!PluginEventsFactory.callIslandTransferEvent(island, caller, target))\n            return;\n\n        island.transferIsland(target);\n\n        IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), target.getName());\n    }\n\n    public static boolean checkKickRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) {\n        if (!island.isMember(targetPlayer)) {\n            Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer);\n            return false;\n        }\n\n        if (!targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) {\n            Message.KICK_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer);\n            return false;\n        }\n\n        return true;\n    }\n\n    public static void handleLeaveIsland(SuperiorPlayer superiorPlayer, Island island) {\n        if (!PluginEventsFactory.callIslandQuitEvent(island, superiorPlayer))\n            return;\n\n        island.removeMember(superiorPlayer, MemberRemoveReason.LEAVE);\n\n        IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName());\n\n        Message.LEFT_ISLAND.send(superiorPlayer);\n    }\n\n    public static void handleKickPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) {\n        handleKickPlayer(caller, caller.getName(), island, target);\n    }\n\n    public static void handleKickPlayer(SuperiorPlayer caller, String callerName, Island island, SuperiorPlayer target) {\n        if (!PluginEventsFactory.callIslandKickEvent(island, caller, target))\n            return;\n\n        island.removeMember(target, MemberRemoveReason.KICK);\n\n        IslandUtils.sendMessage(island, Message.KICK_ANNOUNCEMENT, Collections.emptyList(), target.getName(), callerName);\n\n        Message.GOT_KICKED.send(target, callerName);\n    }\n\n    public static boolean checkBanRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) {\n        Island playerIsland = superiorPlayer.getIsland();\n        if (playerIsland != null && playerIsland.isMember(targetPlayer) &&\n                !targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) {\n            Message.BAN_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer);\n            return false;\n        }\n\n        if (island.isBanned(targetPlayer)) {\n            Message.PLAYER_ALREADY_BANNED.send(superiorPlayer);\n            return false;\n        }\n\n        return true;\n    }\n\n    public static void handleBanPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) {\n        if (!PluginEventsFactory.callIslandBanEvent(island, caller, target))\n            return;\n\n        island.banMember(target, caller);\n\n        IslandUtils.sendMessage(island, Message.BAN_ANNOUNCEMENT, Collections.emptyList(), target.getName(), caller.getName());\n\n        Message.GOT_BANNED.send(target, island.getOwner().getName());\n    }\n\n    public static void deleteChunks(Island island, List<ChunkPosition> chunkPositions, Runnable onFinish) {\n        SynchronizedTasks synchronizedTasks = new SynchronizedTasks(1, onFinish);\n        chunkPositions.forEach(chunkPosition -> {\n            plugin.getStackedBlocks().removeStackedBlocks(chunkPosition);\n            PluginEventsFactory.callIslandChunkResetEvent(island, chunkPosition);\n        });\n        plugin.getNMSChunks().deleteChunks(island, chunkPositions, synchronizedTasks::notifyTaskComplete);\n        synchronizedTasks.waitAllAsync();\n    }\n\n    public static boolean isValidRoleForLimit(PlayerRole playerRole) {\n        return playerRole.isRoleLadder() && !playerRole.isFirstRole() && !playerRole.isLastRole();\n    }\n\n    public static boolean isWarpNameLengthValid(String warpName) {\n        return warpName.length() <= getMaxWarpNameLength();\n    }\n\n    public static int getMaxWarpNameLength() {\n        return 255;\n    }\n\n    public static boolean handleBorderColorUpdate(SuperiorPlayer superiorPlayer, BorderColor borderColor) {\n        if (!superiorPlayer.hasWorldBorderEnabled()) {\n            if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer))\n                return false;\n\n            superiorPlayer.toggleWorldBorder();\n        }\n\n        if (!PluginEventsFactory.callPlayerChangeBorderColorEvent(superiorPlayer, borderColor))\n            return false;\n\n        superiorPlayer.setBorderColor(borderColor);\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            plugin.getNMSWorld().setWorldBorder(superiorPlayer,\n                    plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())));\n        }\n\n        Message.BORDER_PLAYER_COLOR_UPDATED.send(superiorPlayer,\n                Formatters.BORDER_COLOR_FORMATTER.format(borderColor, superiorPlayer.getUserLocale()));\n\n        return true;\n    }\n\n    public static Biome getDefaultWorldBiome(Dimension dimension) {\n        return Objects.requireNonNull(DEFAULT_WORLD_BIOMES.get(dimension));\n    }\n\n    public static List<Biome> getDefaultWorldBiomes() {\n        return new SequentialListBuilder<Biome>().build(DEFAULT_WORLD_BIOMES.values());\n    }\n\n    public static void handleIslandChat(Island island, SuperiorPlayer superiorPlayer, String message) {\n        PluginEvent<PluginEventArgs.IslandChat> event = PluginEventsFactory.callIslandChatEvent(island, superiorPlayer,\n                superiorPlayer.hasPermissionWithoutOP(\"superior.chat.color\") ? Formatters.COLOR_FORMATTER.format(message) : message);\n\n        if (event.isCancelled())\n            return;\n\n        IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(),\n                superiorPlayer.getPlayerRole(), superiorPlayer.getName(), event.getArgs().message);\n\n        Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole().getDisplayName(),\n                superiorPlayer.getName(), event.getArgs().message);\n\n        for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) {\n            SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer);\n            if (onlinePlayer.hasAdminSpyEnabled())\n                Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole().getDisplayName(),\n                        superiorPlayer.getName(), event.getArgs().message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.annotations.Size;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.BlockChangeResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PermissionNode;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.IslandArea;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableObject;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks;\nimport com.bgsoftware.superiorskyblock.core.value.DoubleValue;\nimport com.bgsoftware.superiorskyblock.core.value.IntValue;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl;\nimport com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.island.privilege.PrivilegeNodeAbstract;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.island.top.SortingComparators;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.bgsoftware.superiorskyblock.island.upgrade.DefaultUpgradeLevel;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel;\nimport com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades;\nimport com.bgsoftware.superiorskyblock.island.warp.SIslandWarp;\nimport com.bgsoftware.superiorskyblock.island.warp.SWarpCategory;\nimport com.bgsoftware.superiorskyblock.mission.MissionData;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects;\nimport com.bgsoftware.superiorskyblock.player.inventory.ClearActions;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport com.bgsoftware.superiorskyblock.world.GeneratorType;\nimport com.bgsoftware.superiorskyblock.world.WorldBlocks;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport com.google.common.base.Preconditions;\nimport com.google.common.collect.Sets;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.WeatherType;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.command.ConsoleCommandSender;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffect;\nimport org.bukkit.potion.PotionEffectType;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.UUID;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\npublic class SIsland implements Island {\n\n    private static final UUID CONSOLE_UUID = new UUID(0, 0);\n    private static final UUID[] EMPTY_IGNORED_MEMBERS = new UUID[0];\n    private static final Object[] EMPTY_MESSAGE_ARGS = new Object[0];\n\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private static EnumerateSet<IslandFlag> DEFAULT_FLAGS_CACHE;\n\n    private final DatabaseBridge databaseBridge;\n    private final IslandBank islandBank;\n    private final IslandCalculationAlgorithm calculationAlgorithm;\n    private final IslandBlocksTrackerAlgorithm blocksTracker;\n    private final IslandEntitiesTrackerAlgorithm entitiesTracker;\n    private final Synchronized<BukkitTask> bankInterestTask = Synchronized.of(null);\n    private final Synchronized<Set<BukkitTask>> activeTasks = Synchronized.of(Collections.newSetFromMap(new WeakHashMap<>()));\n    private final DirtyChunksContainer dirtyChunksContainer;\n    private final LazyReference<IslandCache> islandCache = new LazyReference<IslandCache>() {\n        @Override\n        protected IslandCache create() {\n            return new IslandCacheImpl(SIsland.this);\n        }\n    };\n    private final IslandArea entireArea = new IslandArea();\n    private final IslandArea protectedArea = new IslandArea();\n    /*\n     * Island Identifiers\n     */\n    private final UUID uuid;\n    private final BlockPosition center;\n    private final long creationTime;\n    @Nullable\n    private final String schematicName;\n    /*\n     * Island Upgrade Values\n     */\n    private final Synchronized<IntValue> islandSize = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<IntValue> warpsLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<IntValue> teamLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<IntValue> coopLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<DoubleValue> cropGrowth = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<DoubleValue> spawnerRates = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<DoubleValue> mobDrops = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n    private final Synchronized<Value<BigDecimal>> bankLimit = Synchronized.of(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE));\n    private final Synchronized<Int2ObjectMapView<IntValue>> roleLimits = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap());\n    private final Synchronized<EnumerateMap<Dimension, KeyMap<IntValue>>> cobbleGeneratorValues = Synchronized.of(new EnumerateMap<>(Dimension.values()));\n    private final Map<PotionEffectType, IntValue> islandEffects = new ConcurrentHashMap<>();\n    private final KeyMap<IntValue> blockLimits = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL);\n    private final KeyMap<IntValue> entityLimits = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE);\n    /*\n     * Island Player-Trackers\n     */\n    private final Synchronized<SortedSet<SuperiorPlayer>> members = Synchronized.of(new TreeSet<>(SortingComparators.PLAYER_NAMES_COMPARATOR));\n    private final Synchronized<SortedSet<SuperiorPlayer>> playersInside = Synchronized.of(new TreeSet<>(SortingComparators.PLAYER_NAMES_COMPARATOR));\n    private final Synchronized<SortedSet<UniqueVisitor>> uniqueVisitors = Synchronized.of(new TreeSet<>(SortingComparators.PAIRED_PLAYERS_NAMES_COMPARATOR));\n    private final Set<SuperiorPlayer> bannedPlayers = Sets.newConcurrentHashSet();\n    private final Set<SuperiorPlayer> coopPlayers = Sets.newConcurrentHashSet();\n    private final Set<SuperiorPlayer> invitedPlayers = Sets.newConcurrentHashSet();\n    private final Map<SuperiorPlayer, PlayerPrivilegeNode> playerPermissions = new ConcurrentHashMap<>();\n    private final Map<UUID, Rating> ratings = new ConcurrentHashMap<>();\n    /*\n     * Island Warps\n     */\n    private final Map<String, IslandWarp> warpsByName = new ConcurrentHashMap<>();\n    private final Synchronized<Location2ObjectMap<IslandWarp>> warpsByLocation = Synchronized.of(new Location2ObjectMap<>());\n    private final Map<String, WarpCategory> warpCategories = new ConcurrentHashMap<>();\n    /*\n     * General Settings\n     */\n    private final Synchronized<EnumerateMap<Dimension, WorldPosition>> islandHomes = Synchronized.of(new EnumerateMap<>(Dimension.values()));\n    private final Synchronized<EnumerateMap<Dimension, WorldPosition>> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values()));\n    private final Map<IslandPrivilege, Integer> rolePermissions = new ConcurrentHashMap<>();\n    private final Map<IslandFlag, Byte> islandFlags = new ConcurrentHashMap<>();\n    private final IslandUpgrades upgrades = new IslandUpgrades();\n    private final AtomicReference<BigDecimal> islandWorth = new AtomicReference<>(BigDecimal.ZERO);\n    private final AtomicReference<BigDecimal> islandLevel = new AtomicReference<>(BigDecimal.ZERO);\n    private final AtomicReference<BigDecimal> bonusWorth = new AtomicReference<>(BigDecimal.ZERO);\n    private final AtomicReference<BigDecimal> bonusLevel = new AtomicReference<>(BigDecimal.ZERO);\n    private final Map<MissionReference, Counter> completedMissions = new ConcurrentHashMap<>();\n    private final Synchronized<IslandChest[]> islandChests = Synchronized.of(createDefaultIslandChests());\n    private final Synchronized<CompletableFuture<Biome>> biomeGetterTask = Synchronized.of(null);\n    private final Synchronized<EnumerateSet<Dimension>> generatedSchematics = Synchronized.of(new EnumerateSet<>(Dimension.values()));\n    private final Synchronized<EnumerateSet<Dimension>> unlockedWorlds = Synchronized.of(new EnumerateSet<>(Dimension.values()));\n    @Nullable\n    private PersistentDataContainer persistentDataContainer;\n    /*\n     * Island Flags\n     */\n    private volatile boolean beingRecalculated = false;\n    private final AtomicReference<BigInteger> currentTotalBlockCounts = new AtomicReference<>(BigInteger.ZERO);\n    private volatile BigInteger lastSavedBlockCounts = BigInteger.ZERO;\n    private SuperiorPlayer owner;\n    private String creationTimeDate;\n    /*\n     * Island Time-Trackers\n     */\n    private volatile long lastTimeUpdate;\n    private volatile boolean currentlyActive = false;\n    private volatile long lastInterest;\n    private volatile long lastUpgradeTime = -1L;\n    private volatile boolean giveInterestFailed = false;\n    private volatile String discord;\n    private volatile String paypal;\n    private volatile boolean isLocked;\n    private volatile boolean isTopIslandsIgnored;\n    private volatile String formattedName;\n    private volatile String strippedName;\n    private volatile String description;\n    private volatile Biome biome = null;\n\n    public SIsland(IslandBuilderImpl builder) {\n        this.uuid = builder.uuid;\n        this.owner = builder.owner;\n\n        if (this.owner != null) {\n            this.owner.setPlayerRole(SPlayerRole.lastRole());\n            this.owner.setIsland(this);\n        }\n\n        this.center = builder.center;\n        this.creationTime = builder.creationTime;\n        setNameInternal(builder.islandName);\n        this.schematicName = builder.islandType;\n        this.discord = builder.discord;\n        this.paypal = builder.paypal;\n        this.bonusWorth.set(builder.bonusWorth);\n        this.bonusLevel.set(builder.bonusLevel);\n        this.isLocked = builder.isLocked;\n        this.isTopIslandsIgnored = builder.isIgnored;\n        this.description = builder.description;\n        this.generatedSchematics.set(builder.generatedSchematics);\n        this.unlockedWorlds.set(builder.unlockedWorlds);\n        this.lastTimeUpdate = builder.lastTimeUpdated;\n        this.islandHomes.write(islandHomes -> islandHomes.putAll(builder.islandHomes));\n        this.members.write(members -> {\n            members.addAll(builder.members);\n            members.forEach(member -> member.setIsland(this));\n        });\n        this.bannedPlayers.addAll(builder.bannedPlayers);\n        this.playerPermissions.putAll(builder.playerPermissions);\n        this.playerPermissions.values().forEach(permissionNode -> permissionNode.setIsland(this));\n        this.rolePermissions.putAll(builder.rolePermissions);\n        this.upgrades.setUpgradeLevels(builder.upgrades);\n        this.blockLimits.putAll(builder.blockLimits);\n        this.ratings.putAll(builder.ratings);\n        this.completedMissions.putAll(builder.completedMissions);\n        this.islandFlags.putAll(builder.islandFlags);\n        this.cobbleGeneratorValues.write(cobbleGeneratorValues -> cobbleGeneratorValues.putAll(builder.cobbleGeneratorValues));\n        this.uniqueVisitors.write(uniqueVisitors -> uniqueVisitors.addAll(builder.uniqueVisitors));\n        this.entityLimits.putAll(builder.entityLimits);\n        this.islandEffects.putAll(builder.islandEffects);\n        IslandChest[] islandChests = new IslandChest[builder.islandChests.size()];\n        for (int index = 0; index < islandChests.length; ++index) {\n            islandChests[index] = SIslandChest.createChest(this, index, builder.islandChests.get(index));\n        }\n        this.islandChests.set(islandChests);\n        this.roleLimits.write(roleLimits -> roleLimits.putAll(builder.roleLimits));\n        this.visitorHomes.set(builder.visitorHomes);\n        this.islandSize.set(builder.islandSize);\n        this.teamLimit.set(builder.teamLimit);\n        this.warpsLimit.set(builder.warpsLimit);\n        this.cropGrowth.set(builder.cropGrowth);\n        this.spawnerRates.set(builder.spawnerRates);\n        this.mobDrops.set(builder.mobDrops);\n        this.coopLimit.set(builder.coopLimit);\n        this.bankLimit.set(builder.bankLimit);\n        this.lastInterest = builder.lastInterestTime;\n\n        this.databaseBridge = plugin.getFactory().createDatabaseBridge(this);\n        this.islandBank = plugin.getFactory().createIslandBank(this, this::hasGiveInterestFailed);\n        this.calculationAlgorithm = plugin.getFactory().createIslandCalculationAlgorithm(this);\n        this.blocksTracker = plugin.getFactory().createIslandBlocksTrackerAlgorithm(this);\n        this.entitiesTracker = plugin.getFactory().createIslandEntitiesTrackerAlgorithm(this);\n        this.dirtyChunksContainer = new DirtyChunksContainer(this);\n\n        // We make sure the default world is always marked as generated.\n        if (!wasSchematicGenerated(plugin.getSettings().getWorlds().getDefaultWorldDimension())) {\n            setSchematicGenerate(plugin.getSettings().getWorlds().getDefaultWorldDimension());\n        }\n\n        builder.dirtyChunks.forEach(dirtyChunk -> {\n            try {\n                WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dirtyChunk.getWorldName());\n                if (worldInfo != null) {\n                    try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, dirtyChunk.getX(), dirtyChunk.getZ())) {\n                        this.dirtyChunksContainer.markDirty(chunkPosition, false);\n                    }\n                }\n            } catch (IllegalStateException ignored) {\n            }\n        });\n        if (!builder.blockCounts.isEmpty()) {\n            plugin.getProviders().addPricesLoadCallback(() -> {\n                accessBlocksTracker(true, unused -> {\n                    builder.blockCounts.forEach((block, count) -> handleBlockPlaceInternal(block, count, 0));\n                    return null;\n                });\n                this.lastSavedBlockCounts = this.currentTotalBlockCounts.get();\n            });\n        }\n\n        builder.warpCategories.forEach(warpCategoryRecord -> {\n            loadWarpCategory(warpCategoryRecord.name, warpCategoryRecord.slot, warpCategoryRecord.icon);\n        });\n\n        builder.warps.forEach(warpRecord -> {\n            WarpCategory warpCategory = null;\n\n            if (!warpRecord.category.isEmpty())\n                warpCategory = getWarpCategory(warpRecord.category);\n\n            WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, warpRecord.worldName);\n\n            loadIslandWarp(warpRecord.name, worldInfo, warpRecord.worldPosition, warpCategory, warpRecord.isPrivate, warpRecord.icon);\n        });\n\n        int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() *\n                (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D));\n        this.entireArea.update(this.center, islandDistance);\n        this.protectedArea.update(this.center, getIslandSize());\n\n        // We want to save all the limits to the custom block keys\n        plugin.getBlockValues().addCustomBlockKeys(builder.blockLimits.keySet());\n\n        updateDatesFormatter();\n        startBankInterest();\n        checkMembersDuplication();\n        updateOldUpgradeValues();\n        updateUpgrades();\n        updateIslandChests();\n\n        // We can only track entity counts after upgrades are set up\n        if (!builder.entityCounts.isEmpty()) {\n            builder.entityCounts.forEach((entity, count) -> this.entitiesTracker.trackEntity(entity, count.intValue()));\n        }\n\n        this.islandBank.setBalance(builder.balance);\n        builder.bankTransactions.forEach(this.islandBank::loadTransaction);\n        if (builder.persistentData.length > 0)\n            getPersistentDataContainer().load(builder.persistentData);\n\n        this.databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n    }\n\n    /*\n     *  General methods\n     */\n\n    @Override\n    public SuperiorPlayer getOwner() {\n        return owner;\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return uuid;\n    }\n\n    @Override\n    public long getCreationTime() {\n        return creationTime;\n    }\n\n    /*\n     *  Player related methods\n     */\n\n    @Override\n    public String getCreationTimeDate() {\n        return creationTimeDate;\n    }\n\n    @Override\n    public void updateDatesFormatter() {\n        this.creationTimeDate = Formatters.DATE_FORMATTER.format(new Date(creationTime * 1000));\n    }\n\n    @Override\n    public IslandCache getCache() {\n        return this.islandCache.get();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(boolean includeOwner) {\n        List<SuperiorPlayer> members = this.members.readAndGet(_members -> new SequentialListBuilder<SuperiorPlayer>()\n                .mutable()\n                .build(_members));\n\n        if (includeOwner)\n            members.add(owner);\n\n        return Collections.unmodifiableList(members);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(PlayerRole... playerRoles) {\n        Preconditions.checkNotNull(playerRoles, \"playerRoles parameter cannot be null.\");\n\n        List<PlayerRole> rolesToFilter = Arrays.asList(playerRoles);\n        List<SuperiorPlayer> members = this.members.readAndGet(_members -> new SequentialListBuilder<SuperiorPlayer>()\n                .mutable()\n                .filter(superiorPlayer -> rolesToFilter.contains(superiorPlayer.getPlayerRole()))\n                .build(_members));\n\n\n        if (rolesToFilter.contains(SPlayerRole.lastRole()))\n            members.add(owner);\n\n        return Collections.unmodifiableList(members);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getBannedPlayers() {\n        return new SequentialListBuilder<SuperiorPlayer>().build(this.bannedPlayers);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors() {\n        return getIslandVisitors(true);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors(boolean vanishPlayers) {\n        return playersInside.readAndGet(playersInside -> new SequentialListBuilder<SuperiorPlayer>()\n                .filter(superiorPlayer -> !isMember(superiorPlayer) && (vanishPlayers || superiorPlayer.isShownAsOnline()))\n                .build(playersInside));\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayersInside() {\n        return playersInside.readAndGet(playersInside -> new SequentialListBuilder<SuperiorPlayer>()\n                .filter(SuperiorPlayer::isOnline)\n                .build(playersInside));\n    }\n\n    @Override\n    public List<SuperiorPlayer> getUniqueVisitors() {\n        return uniqueVisitors.readAndGet(uniqueVisitors -> new SequentialListBuilder<SuperiorPlayer>()\n                .build(uniqueVisitors, UniqueVisitor::getSuperiorPlayer));\n    }\n\n    @Override\n    public List<Pair<SuperiorPlayer, Long>> getUniqueVisitorsWithTimes() {\n        return uniqueVisitors.readAndGet(uniqueVisitors -> new SequentialListBuilder<Pair<SuperiorPlayer, Long>>()\n                .build(uniqueVisitors, UniqueVisitor::toPair));\n    }\n\n    @Override\n    public void inviteMember(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.INVITE_MEMBER, owner.getName(), superiorPlayer.getName());\n\n        invitedPlayers.add(superiorPlayer);\n        superiorPlayer.addInvite(this);\n\n        //Revoke the invite after 5 minutes\n        registerTask(BukkitExecutor.sync(() -> revokeInvite(superiorPlayer), 6000L));\n    }\n\n    @Override\n    public void revokeInvite(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.REVOKE_INVITE, owner.getName(), superiorPlayer.getName());\n\n        invitedPlayers.remove(superiorPlayer);\n        superiorPlayer.removeInvite(this);\n    }\n\n    @Override\n    public boolean isInvited(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return invitedPlayers.contains(superiorPlayer);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getInvitedPlayers() {\n        return new SequentialListBuilder<SuperiorPlayer>().build(this.invitedPlayers);\n    }\n\n    @Override\n    public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n\n        Log.debug(Debug.ADD_MEMBER, owner.getName(), superiorPlayer.getName(), playerRole);\n\n        boolean addedNewMember = members.writeAndGet(members -> members.add(superiorPlayer));\n\n        // This player is already a member of the island\n        if (!addedNewMember)\n            return;\n\n        // Remove player from being cooped, invited and its ratings\n        removeCoop(superiorPlayer);\n        revokeInvite(superiorPlayer);\n        removeRating(superiorPlayer);\n\n        superiorPlayer.setIsland(this);\n\n        if (PluginEventsFactory.callPlayerChangeRoleEvent(superiorPlayer, playerRole)) {\n            superiorPlayer.setPlayerRole(playerRole);\n        } else {\n            superiorPlayer.setPlayerRole(SPlayerRole.defaultRole());\n        }\n\n        plugin.getMenus().refreshMembers(this);\n\n        updateLastTime();\n\n        ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnJoin(),\n                plugin.getSettings().isTeleportOnJoin() ? this : null);\n\n        if (superiorPlayer.isOnline()) {\n            updateIslandFly(superiorPlayer);\n            setCurrentlyActive();\n        }\n\n        IslandsDatabaseBridge.addMember(this, superiorPlayer, System.currentTimeMillis());\n    }\n\n    @Override\n    public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(reason, \"memberRemoveReason parameter cannot be null.\");\n        Preconditions.checkArgument(!superiorPlayer.equals(owner), \"superiorPlayer cannot be island owner.\");\n\n        removeMemberSafe(superiorPlayer, reason);\n    }\n\n    private void removeMemberSafe(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) {\n        if (reason == MemberRemoveReason.KICK)\n            Log.debug(Debug.KICK_MEMBER, owner.getName(), superiorPlayer.getName());\n        else if (reason == MemberRemoveReason.LEAVE)\n            Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName());\n\n        if (!superiorPlayer.equals(owner)) {\n            boolean removedMember = members.writeAndGet(members -> members.remove(superiorPlayer));\n\n            if (!removedMember) {\n                // If the remove method failed, we iterate through all the members and remove the member manually.\n                // Should fix issues if members are not in the correct order.\n                // Reference: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/734\n                removedMember = members.writeAndGet(members -> members.removeIf(superiorPlayer::equals));\n            }\n\n            // This player is not a member of the island.\n            if (!removedMember)\n                return;\n        }\n\n        boolean isInside = superiorPlayer.isInsideIsland();\n        superiorPlayer.setIsland(null);\n\n        if (reason == MemberRemoveReason.DISBAND) {\n            ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnDisband(),\n                    isInside ? plugin.getGrid().getSpawnIsland() : null);\n        } else if (reason == MemberRemoveReason.KICK) {\n            boolean shouldTeleport = plugin.getSettings().isTeleportOnKick() && isInside;\n            ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnKick(),\n                    shouldTeleport ? plugin.getGrid().getSpawnIsland() : null);\n            if (!shouldTeleport)\n                updateIslandFly(superiorPlayer);\n        } else if (reason == MemberRemoveReason.LEAVE) {\n            boolean shouldTeleport = plugin.getSettings().isTeleportOnLeave() && isInside;\n            ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnLeave(),\n                    shouldTeleport ? plugin.getGrid().getSpawnIsland() : null);\n            if (!shouldTeleport)\n                updateIslandFly(superiorPlayer);\n        }\n\n        superiorPlayer.runIfOnline(player -> {\n            MenuView<?, ?> openedView = superiorPlayer.getOpenedView();\n\n            if (openedView != null)\n                openedView.closeView();\n        });\n\n        plugin.getMissions().getPlayerMissions().forEach(mission -> {\n            MissionData missionData = plugin.getMissions().getMissionData(mission).orElse(null);\n\n            if (missionData == null)\n                return;\n\n            if ((reason == MemberRemoveReason.DISBAND && missionData.isDisbandReset()) ||\n                    ((reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) && missionData.isLeaveReset()))\n                superiorPlayer.resetMission(mission);\n        });\n\n        if (reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) {\n            plugin.getMenus().destroyMemberManage(superiorPlayer);\n            plugin.getMenus().destroyMemberRole(superiorPlayer);\n            plugin.getMenus().refreshMembers(this);\n\n            IslandsDatabaseBridge.removeMember(this, superiorPlayer);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public void kickMember(SuperiorPlayer superiorPlayer) {\n        removeMember(superiorPlayer, MemberRemoveReason.KICK);\n    }\n\n    @Override\n    public boolean isMember(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return owner.equals(superiorPlayer.getIslandLeader());\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer) {\n        banMember(superiorPlayer, null);\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.BAN_PLAYER, owner.getName(), superiorPlayer.getName(), whom);\n\n        boolean bannedPlayer = bannedPlayers.add(superiorPlayer);\n\n        // This player is already banned.\n        if (!bannedPlayer)\n            return;\n\n        if (isMember(superiorPlayer))\n            removeMember(superiorPlayer, MemberRemoveReason.KICK);\n\n        plugin.getMenus().refreshIslandBannedPlayers(this);\n\n        superiorPlayer.runIfOnline(player -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (isInside(player.getLocation(wrapper.getHandle())))\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n            }\n        });\n\n        IslandsDatabaseBridge.addBannedPlayer(this,\n                superiorPlayer, whom == null ? CONSOLE_UUID : whom.getUniqueId(),\n                System.currentTimeMillis());\n    }\n\n    @Override\n    public void unbanMember(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.UNBAN_PLAYER, owner.getName(), superiorPlayer.getName());\n\n        boolean unbannedPlayer = bannedPlayers.remove(superiorPlayer);\n\n        if (unbannedPlayer) {\n            plugin.getMenus().refreshIslandBannedPlayers(this);\n\n            IslandsDatabaseBridge.removeBannedPlayer(this, superiorPlayer);\n        }\n    }\n\n    @Override\n    public boolean isBanned(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return bannedPlayers.contains(superiorPlayer);\n    }\n\n    @Override\n    public void addCoop(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.ADD_COOP, owner.getName(), superiorPlayer.getName());\n\n        boolean coopPlayer = coopPlayers.add(superiorPlayer);\n\n        if (!coopPlayer)\n            return;\n\n        superiorPlayer.addCoop(this);\n        plugin.getMenus().refreshCoops(this);\n    }\n\n    @Override\n    public void removeCoop(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_COOP, owner.getName(), superiorPlayer.getName());\n\n        boolean uncoopPlayer = coopPlayers.remove(superiorPlayer);\n\n        // This player was not coop.\n        if (!uncoopPlayer)\n            return;\n\n        superiorPlayer.removeCoop(this);\n\n        superiorPlayer.runIfOnline(player -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (isLocked() && isInside(player.getLocation(wrapper.getHandle()))) {\n                    MenuView<?, ?> openedView = superiorPlayer.getOpenedView();\n                    if (openedView != null)\n                        openedView.closeView();\n\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                }\n            }\n        });\n\n        plugin.getMenus().refreshCoops(this);\n    }\n\n    @Override\n    public boolean isCoop(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return plugin.getSettings().isCoopMembers() && coopPlayers.contains(superiorPlayer);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getCoopPlayers() {\n        return new SequentialListBuilder<SuperiorPlayer>().build(this.coopPlayers);\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return this.coopLimit.readAndGet(IntValue::get);\n    }\n\n    @Override\n    public int getCoopLimitRaw() {\n        return this.coopLimit.readAndGet(coopLimit -> coopLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public void setCoopLimit(int coopLimit) {\n        coopLimit = Math.max(0, coopLimit);\n\n        Log.debug(Debug.SET_COOP_LIMIT, owner.getName(), coopLimit);\n\n        // Original and new coop limit are the same\n        if (coopLimit == getCoopLimitRaw())\n            return;\n\n        this.coopLimit.set(IntValue.fixed(coopLimit));\n        IslandsDatabaseBridge.saveCoopLimit(this);\n    }\n\n    /*\n     *  Location related methods\n     */\n\n    @Override\n    public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        if (inside) {\n            Log.debug(Debug.ENTER_ISLAND, owner.getName(), superiorPlayer.getName());\n        } else {\n            Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName());\n        }\n\n        boolean changePlayers = playersInside.writeAndGet(playersInside -> {\n            if (inside)\n                return playersInside.add(superiorPlayer);\n            else\n                return playersInside.remove(superiorPlayer);\n        });\n\n        // The players inside the player weren't changed.\n        if (!changePlayers)\n            return;\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_PLAYERS, this);\n\n        if (!isMember(superiorPlayer) && superiorPlayer.isShownAsOnline()) {\n            Optional<UniqueVisitor> uniqueVisitorOptional = uniqueVisitors.readAndGet(uniqueVisitors ->\n                    uniqueVisitors.stream().filter(pair -> pair.getSuperiorPlayer().equals(superiorPlayer)).findFirst());\n\n            long visitTime = System.currentTimeMillis();\n\n            boolean updateVisitor;\n\n            if (uniqueVisitorOptional.isPresent()) {\n                uniqueVisitorOptional.get().setLastVisitTime(visitTime);\n                updateVisitor = true;\n            } else {\n                updateVisitor = uniqueVisitors.writeAndGet(uniqueVisitors -> uniqueVisitors.add(new UniqueVisitor(superiorPlayer, visitTime)));\n            }\n\n            if (updateVisitor) {\n                plugin.getMenus().refreshUniqueVisitors(this);\n\n                IslandsDatabaseBridge.saveVisitor(this, superiorPlayer, visitTime);\n            }\n        }\n\n        updateLastTime();\n\n        plugin.getMenus().refreshVisitors(this);\n    }\n\n    @Override\n    public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatus) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        return !isMember(superiorPlayer) && (!includeCoopStatus || !isCoop(superiorPlayer));\n    }\n\n    @Override\n    public Location getCenter(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        World world = plugin.getGrid().getIslandsWorld(this, dimension);\n\n        Preconditions.checkNotNull(world, \"Couldn't find world for dimension \" + dimension + \".\");\n\n        return this.center.toWorldPosition().toLocation(world);\n    }\n\n    @Override\n    public BlockPosition getCenterPosition() {\n        return center;\n    }\n\n    @Override\n    public CompletableFuture<World> accessIslandWorld(Dimension dimension) {\n        CompletableFuture<World> completableFuture = new CompletableFuture<>();\n        IslandWorlds.accessIslandWorldAsync(this, dimension, true, islandWorldResult -> {\n            islandWorldResult.ifRight(completableFuture::completeExceptionally).ifLeft(completableFuture::complete);\n        });\n        return completableFuture;\n    }\n\n    @Override\n    public Location getIslandHome(Dimension dimension) {\n        WorldPosition islandHome = getIslandHomePosition(dimension);\n        return islandHome == null ? null : IslandWorlds.setWorldToLocation(this, dimension, islandHome);\n    }\n\n    @Override\n    public WorldPosition getIslandHomePosition(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        WorldPosition islandHome = islandHomes.readAndGet(islandHomes -> islandHomes.get(dimension));\n\n        return islandHome == null ? this.center.toWorldPosition() : islandHome;\n    }\n\n    @Override\n    public Map<Dimension, Location> getIslandHomesAsDimensions() {\n        Map<Dimension, Location> islandHomes = this.islandHomes.readAndGet(map ->\n                map.collect(Dimension.values(), this::worldPositionToLocation));\n        return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes);\n    }\n\n    @Override\n    public Map<Dimension, WorldPosition> getIslandHomes() {\n        Map<Dimension, WorldPosition> islandHomes = this.islandHomes.readAndGet(map ->\n                map.collect(Dimension.values()));\n        return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes);\n    }\n\n    @Override\n    public void setIslandHome(Location homeLocation) {\n        Preconditions.checkNotNull(homeLocation, \"homeLocation parameter cannot be null.\");\n        Preconditions.checkNotNull(homeLocation.getWorld(), \"homeLocation's world cannot be null.\");\n        Preconditions.checkArgument(isInside(homeLocation), \"homeLocation must be inside island.\");\n\n        Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(homeLocation.getWorld());\n        setIslandHome(dimension, SWorldPosition.of(homeLocation));\n    }\n\n    @Override\n    public void setIslandHome(Dimension dimension, @Nullable Location homeLocation) {\n        setIslandHome(dimension, homeLocation == null ? null : SWorldPosition.of(homeLocation));\n    }\n\n    @Override\n    public void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        Log.debug(Debug.SET_ISLAND_HOME, owner.getName(), dimension, homePosition);\n\n        WorldPosition newHome = adjustPositionToCenterOfBlock(homePosition);\n\n        WorldPosition oldHome = islandHomes.writeAndGet(islandHomes ->\n                newHome == null ? islandHomes.remove(dimension) : islandHomes.put(dimension, newHome));\n\n        if (!Objects.equals(oldHome, newHome))\n            IslandsDatabaseBridge.saveIslandHome(this, dimension, newHome);\n    }\n\n    @Nullable\n    @Override\n    public Location getVisitorsLocation(Dimension unused) {\n        WorldPosition visitorsPosition = getVisitorsPosition(null /*unused*/);\n        return visitorsPosition == null ? null : IslandWorlds.setWorldToLocation(\n                this, plugin.getSettings().getWorlds().getDefaultWorldDimension(), visitorsPosition);\n    }\n\n    @Override\n    public WorldPosition getVisitorsPosition(Dimension unused) {\n        Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n        return this.visitorHomes.readAndGet(visitorHomes ->\n                visitorHomes.get(defaultWorldDimension));\n    }\n\n    @Override\n    public void setVisitorsLocation(@Nullable Location visitorsLocation) {\n        setVisitorsLocation(null /*unused*/, visitorsLocation == null ? null : SWorldPosition.of(visitorsLocation));\n    }\n\n    @Override\n    public void setVisitorsLocation(Dimension unused, @Nullable WorldPosition visitorsPosition) {\n        Log.debug(Debug.SET_VISITOR_HOME, owner.getName(), visitorsPosition);\n\n        Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n\n        WorldPosition newHome = adjustPositionToCenterOfBlock(visitorsPosition);\n\n        WorldPosition oldHome = visitorHomes.writeAndGet(visitorHomes ->\n                newHome == null ? visitorHomes.remove(defaultWorldDimension) : visitorHomes.put(defaultWorldDimension, newHome));\n\n        if (!Objects.equals(oldHome, newHome))\n            IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, newHome);\n    }\n\n    @Override\n    public Location getMinimum() {\n        int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() *\n                (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D));\n        return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).subtract(islandDistance, 0, islandDistance);\n    }\n\n    @Override\n    public BlockPosition getMinimumPosition() {\n        int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() *\n                (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D));\n        return getCenterPosition().offset(-islandDistance, 0, -islandDistance);\n    }\n\n    @Override\n    public Location getMinimumProtected() {\n        int islandSize = getIslandSize();\n        return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).subtract(islandSize, 0, islandSize);\n    }\n\n    @Override\n    public BlockPosition getMinimumProtectedPosition() {\n        int islandSize = getIslandSize();\n        return getCenterPosition().offset(-islandSize, 0, -islandSize);\n    }\n\n    @Override\n    public Location getMaximum() {\n        int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() *\n                (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D));\n        return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).add(islandDistance, 0, islandDistance);\n    }\n\n    @Override\n    public BlockPosition getMaximumPosition() {\n        int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() *\n                (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D));\n        return getCenterPosition().offset(islandDistance, 0, islandDistance);\n    }\n\n    @Override\n    public Location getMaximumProtected() {\n        int islandSize = getIslandSize();\n        return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).add(islandSize, 0, islandSize);\n    }\n\n    @Override\n    public BlockPosition getMaximumProtectedPosition() {\n        int islandSize = getIslandSize();\n        return getCenterPosition().offset(islandSize, 0, islandSize);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks() {\n        return getAllChunks(0);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(int flags) {\n        List<Chunk> chunks = new LinkedList<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            try {\n                chunks.addAll(getAllChunks(dimension, flags));\n            } catch (NullPointerException ignored) {\n            }\n        }\n\n        return Collections.unmodifiableList(chunks);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(Dimension dimension) {\n        return getAllChunks(dimension, 0);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n\n        World world = getCenter(dimension).getWorld();\n        return new SequentialListBuilder<Chunk>().build(IslandUtils.getChunkCoords(this, WorldInfo.of(world), flags),\n                chunkPosition -> world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ()));\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks() {\n        return getLoadedChunks(0);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(@IslandChunkFlags int flags) {\n        List<Chunk> chunks = new LinkedList<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            try {\n                chunks.addAll(getLoadedChunks(dimension, flags));\n            } catch (NullPointerException ignored) {\n            }\n        }\n\n        return Collections.unmodifiableList(chunks);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension dimension) {\n        return getLoadedChunks(dimension, 0);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension);\n\n        return new SequentialListBuilder<Chunk>().filter(Objects::nonNull).build(\n                IslandUtils.getChunkCoords(this, worldInfo, flags), plugin.getNMSChunks()::getChunkIfLoaded);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension) {\n        return getAllChunksAsync(dimension, 0);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) {\n        return getAllChunksAsync(dimension, flags, null);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension,\n                                                            @Nullable Consumer<Chunk> onChunkLoad) {\n        return getAllChunksAsync(dimension, 0, onChunkLoad);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags,\n                                                            @Nullable Consumer<Chunk> onChunkLoad) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension);\n        return IslandUtils.getAllChunksAsync(this, worldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad);\n    }\n\n    @Override\n    public void resetChunks() {\n        resetChunks((Runnable) null);\n    }\n\n    @Override\n    public void resetChunks(@Nullable Runnable onFinish) {\n        resetChunks(0, onFinish);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension) {\n        resetChunks(dimension, 0);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @Nullable Runnable onFinish) {\n        resetChunks(dimension, 0, onFinish);\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags) {\n        resetChunks(flags, null);\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) {\n        final int realFlags = flags | IslandChunkFlags.NO_EMPTY_CHUNKS;\n\n        List<Dimension> dimensionList = new LinkedList<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) {\n                dimensionList.add(dimension);\n            }\n        }\n\n        List<World> customWorlds = plugin.getGrid().getRegisteredWorlds();\n\n        SynchronizedTasks synchronizedTasks = new SynchronizedTasks(dimensionList.size() + customWorlds.size(), onFinish);\n\n        customWorlds.forEach(registeredWorld -> {\n            WorldInfo worldInfo = WorldInfo.of(registeredWorld);\n            List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags);\n            if (!chunkPositions.isEmpty()) {\n                IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete);\n            } else {\n                synchronizedTasks.notifyTaskComplete();\n            }\n        });\n\n        dimensionList.forEach(dimension -> {\n            IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> {\n                result.ifLeft(world -> {\n                    WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension);\n                    List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags);\n                    if (!chunkPositions.isEmpty()) {\n                        IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete);\n                    } else {\n                        synchronizedTasks.notifyTaskComplete();\n                    }\n                }).ifRight(error -> {\n                    synchronizedTasks.notifyTaskComplete();\n                    throw new RuntimeException(error);\n                });\n            });\n        });\n\n        synchronizedTasks.waitAllAsync();\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        resetChunks(dimension, flags, null);\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n\n        IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> {\n            result.ifRight(error -> {\n                throw new RuntimeException(error);\n            }).ifLeft(world -> {\n                WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension);\n                List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS);\n                if (!chunkPositions.isEmpty()) {\n                    IslandUtils.deleteChunks(this, chunkPositions, onFinish);\n                } else if (onFinish != null) {\n                    onFinish.run();\n                }\n            });\n        });\n    }\n\n    @Override\n    public boolean isInside(Location location) {\n        return isInside(location, 0);\n    }\n\n    @Override\n    public boolean isInside(Location location, int extraRadius) {\n        return isInside(location, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Location location, double extraRadius) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return isIslandWorld(location) && this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition) {\n        return isInside(blockPosition, 0D);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, int extraRadius) {\n        return isInside(blockPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, double extraRadius) {\n        Preconditions.checkNotNull(blockPosition, \"blockPosition parameter cannot be null.\");\n        return this.entireArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition) {\n        return isInside(worldPosition, 0D);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, int extraRadius) {\n        return isInside(worldPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, double extraRadius) {\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n        return this.entireArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Chunk chunk) {\n        Preconditions.checkNotNull(chunk, \"chunk parameter cannot be null.\");\n        return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ());\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ) {\n        return isInside(world, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(world, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        return isIslandWorld(world) && isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return isInside(worldInfo, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        return isIslandWorld(worldInfo) && isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ) {\n        return isInside(chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, int extraRadius) {\n        return isInside(chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, double extraRadius) {\n        return this.entireArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location) {\n        return isInsideRange(location, 0);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, int extraRadius) {\n        return isInsideRange(location, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, double extraRadius) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return isIslandWorld(location) && this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition) {\n        return isInsideRange(blockPosition, 0D);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) {\n        return isInsideRange(blockPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) {\n        Preconditions.checkNotNull(blockPosition, \"blockPosition parameter cannot be null.\");\n        return this.protectedArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition) {\n        return isInsideRange(worldPosition, 0D);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) {\n        return isInsideRange(worldPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) {\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n        return this.protectedArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Chunk chunk) {\n        return isInsideRange(chunk.getWorld(), chunk.getX(), chunk.getZ());\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ) {\n        return isInsideRange(world, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) {\n        return isInsideRange(world, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        return isIslandWorld(world) && isInsideRange(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return isInsideRange(worldInfo, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return isInsideRange(worldInfo, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        return isIslandWorld(worldInfo) && isInsideRange(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ) {\n        return isInsideRange(chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) {\n        return isInsideRange(chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) {\n        return this.protectedArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4);\n    }\n\n    private boolean isIslandWorld(Location location) {\n        return isIslandWorld(LazyWorldLocation.getWorldName(location));\n    }\n\n    private boolean isIslandWorld(@Nullable World world) {\n        return world != null && isIslandWorld(world.getName());\n    }\n\n    private boolean isIslandWorld(@Nullable WorldInfo worldInfo) {\n        return worldInfo != null && isIslandWorld(worldInfo.getName());\n    }\n\n    private boolean isIslandWorld(@Nullable String worldName) {\n        if (worldName == null)\n            return false;\n\n        return plugin.getGrid().getIslandsWorldInfo(this, worldName) != null;\n    }\n\n    @Override\n    public boolean isNormalEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"NORMAL\"));\n    }\n\n    @Override\n    public void setNormalEnabled(boolean enabled) {\n        setDimensionEnabled(Dimension.getByName(\"NORMAL\"), enabled);\n    }\n\n    @Override\n    public boolean isNetherEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"NETHER\"));\n    }\n\n    @Override\n    public void setNetherEnabled(boolean enabled) {\n        setDimensionEnabled(Dimension.getByName(\"NETHER\"), enabled);\n    }\n\n    @Override\n    public boolean isEndEnabled() {\n        return isDimensionEnabled(Dimension.getByName(\"THE_END\"));\n    }\n\n    @Override\n    public void setEndEnabled(boolean enabled) {\n        setDimensionEnabled(Dimension.getByName(\"THE_END\"), enabled);\n    }\n\n    @Override\n    public boolean isDimensionEnabled(Dimension dimension) {\n        return plugin.getProviders().getWorldsProvider().isDimensionUnlocked(dimension) ||\n                unlockedWorlds.readAndGet(unlockedWorlds -> unlockedWorlds.contains(dimension));\n    }\n\n    @Override\n    public void setDimensionEnabled(Dimension dimension, boolean enabled) {\n        Log.debug(Debug.SET_DIMENSION_ENABLED, owner.getName(), dimension.getName(), enabled);\n\n        boolean updated = this.unlockedWorlds.writeAndGet(unlockedWorlds -> {\n            return enabled ? unlockedWorlds.add(dimension) : unlockedWorlds.remove(dimension);\n        });\n\n        if (updated)\n            IslandsDatabaseBridge.saveUnlockedWorlds(this);\n    }\n\n    @Override\n    public Set<Dimension> getUnlockedWorlds() {\n        return Collections.unmodifiableSet(this.unlockedWorlds.readAndGet(unlockedWorlds ->\n                unlockedWorlds.collect(Dimension.values())));\n    }\n\n    /*\n     *  Permissions related methods\n     */\n\n    @Override\n    public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(sender, \"sender parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        return sender instanceof ConsoleCommandSender || hasPermission(plugin.getPlayers().getSuperiorPlayer(sender), islandPrivilege);\n    }\n\n    @Override\n    public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        PermissionNode playerNode = getPermissionNode(superiorPlayer);\n        return superiorPlayer.hasBypassModeEnabled() || superiorPlayer.hasBypassPermission(islandPrivilege) ||\n                superiorPlayer.hasPermissionWithoutOP(\"superior.admin.bypass.*\") ||\n                (playerNode != null && playerNode.hasPermission(islandPrivilege));\n    }\n\n    @Override\n    public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        return getRequiredPlayerRole(islandPrivilege).getWeight() <= playerRole.getWeight();\n    }\n\n    @Override\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) {\n        if (value)\n            this.setPermission(playerRole, islandPrivilege);\n    }\n\n    @Override\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        Log.debug(Debug.SET_PERMISSION, owner.getName(), playerRole, islandPrivilege);\n\n        Integer oldRoleId = rolePermissions.put(islandPrivilege, playerRole.getId());\n\n        if (oldRoleId != null && oldRoleId == playerRole.getId())\n            return;\n\n        if (islandPrivilege == IslandPrivileges.FLY) {\n            getAllPlayersInside().forEach(this::updateIslandFly);\n        } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) {\n            getAllPlayersInside().forEach(superiorPlayer -> IslandUtils.updateTradingMenus(this, superiorPlayer));\n        }\n\n        IslandsDatabaseBridge.saveRolePermission(this, playerRole, islandPrivilege);\n    }\n\n    @Override\n    public void resetPermissions() {\n        Log.debug(Debug.RESET_PERMISSIONS, owner.getName());\n\n        if (rolePermissions.isEmpty())\n            return;\n\n        rolePermissions.clear();\n\n        getAllPlayersInside().forEach(superiorPlayer -> {\n            updateIslandFly(superiorPlayer);\n            IslandUtils.updateTradingMenus(this, superiorPlayer);\n        });\n\n        IslandsDatabaseBridge.clearRolePermissions(this);\n\n        plugin.getMenus().refreshPermissions(this);\n    }\n\n    @Override\n    public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        Log.debug(Debug.SET_PERMISSION, owner.getName(),\n                superiorPlayer.getName(), islandPrivilege, value);\n\n        PlayerPrivilegeNode privilegeNode = playerPermissions.computeIfAbsent(superiorPlayer,\n                s -> new PlayerPrivilegeNode(superiorPlayer, this));\n\n        privilegeNode.setPermission(islandPrivilege, value);\n\n        superiorPlayer.runIfOnline(player -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (isInside(player.getLocation(wrapper.getHandle()))) {\n                    if (islandPrivilege == IslandPrivileges.FLY) {\n                        updateIslandFly(superiorPlayer);\n                    } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) {\n                        IslandUtils.updateTradingMenus(this, superiorPlayer);\n                    }\n                }\n            }\n        });\n\n        IslandsDatabaseBridge.savePlayerPermission(this, superiorPlayer, islandPrivilege, value);\n\n        plugin.getMenus().refreshPermissions(this, superiorPlayer);\n    }\n\n    @Override\n    public void resetPermissions(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.RESET_PERMISSIONS, owner.getName(), superiorPlayer.getName());\n\n        PlayerPrivilegeNode oldPrivilegeNode = playerPermissions.remove(superiorPlayer);\n\n        if (oldPrivilegeNode == null)\n            return;\n\n        if (superiorPlayer.isOnline()) {\n            updateIslandFly(superiorPlayer);\n            IslandUtils.updateTradingMenus(this, superiorPlayer);\n        }\n\n        IslandsDatabaseBridge.clearPlayerPermission(this, superiorPlayer);\n\n        plugin.getMenus().refreshPermissions(this, superiorPlayer);\n    }\n\n    @Override\n    public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        return playerPermissions.getOrDefault(superiorPlayer, new PlayerPrivilegeNode(superiorPlayer, this));\n    }\n\n    @Override\n    public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        Integer playerRoleId = rolePermissions.get(islandPrivilege);\n\n        if (playerRoleId != null)\n            return plugin.getRoles().getPlayerRoleFromId(playerRoleId);\n\n        return plugin.getRoles().getRoles().stream()\n                .filter(_playerRole -> {\n                    if (!plugin.getSettings().isCoopMembers() && _playerRole == SPlayerRole.coopRole())\n                        return false;\n\n                    return ((SPlayerRole) _playerRole).getDefaultPermissions().hasPermission(islandPrivilege);\n                })\n                .min(Comparator.comparingInt(PlayerRole::getWeight)).orElse(SPlayerRole.lastRole());\n    }\n\n    /*\n     *  General methods\n     */\n\n    @Override\n    public Map<SuperiorPlayer, PermissionNode> getPlayerPermissions() {\n        return Collections.unmodifiableMap(playerPermissions);\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> getRolePermissions() {\n        return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue())\n        )));\n    }\n\n    @Override\n    public boolean isSpawn() {\n        return false;\n    }\n\n    @Override\n    public String getName() {\n        return plugin.getSettings().getIslandNames().isColorSupport() ? getFormattedName() : getStrippedName();\n    }\n\n    @Override\n    public void setName(String islandName) {\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n\n        String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName);\n\n        Log.debug(Debug.SET_NAME, owner.getName(), strippedName);\n\n        String oldName = this.strippedName;\n\n        setNameInternal(islandName);\n\n        if (Objects.equals(strippedName, oldName))\n            return;\n\n        plugin.getGrid().getIslandsContainer().updateIslandName(this, oldName);\n\n        IslandsDatabaseBridge.saveName(this);\n    }\n\n    private void setNameInternal(String name) {\n        this.formattedName = Formatters.COLOR_FORMATTER.format(name);\n        this.strippedName = Formatters.STRIP_COLOR_FORMATTER.format(name);\n    }\n\n    @Override\n    public String getRawName() {\n        return getStrippedName();\n    }\n\n    @Override\n    public String getStrippedName() {\n        return this.strippedName;\n    }\n\n    @Override\n    public String getFormattedName() {\n        return this.formattedName;\n    }\n\n    @Override\n    public String getDescription() {\n        return description;\n    }\n\n    @Override\n    public void setDescription(String description) {\n        Preconditions.checkNotNull(description, \"description parameter cannot be null.\");\n\n        Log.debug(Debug.SET_DESCRIPTION, owner.getName(), description);\n\n        if (Objects.equals(this.description, description))\n            return;\n\n        this.description = description;\n\n        IslandsDatabaseBridge.saveDescription(this);\n    }\n\n    @Override\n    public void disbandIsland() {\n        long profilerId = Profiler.start(ProfileType.DISBAND_ISLAND, 2);\n\n        forEachIslandMember(EMPTY_IGNORED_MEMBERS, false, islandMember -> {\n            removeMemberSafe(islandMember, MemberRemoveReason.DISBAND);\n        });\n\n        this.activeTasks.write(activeTasks -> {\n            activeTasks.forEach(BukkitTask::cancel);\n        });\n        this.bankInterestTask.set((BukkitTask) null);\n\n        invitedPlayers.forEach(invitedPlayer -> invitedPlayer.removeInvite(this));\n        coopPlayers.forEach(coopPlayer -> coopPlayer.removeCoop(this));\n\n        if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) {\n            BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund();\n            plugin.getProviders().depositMoney(getOwner(), islandBank.getBalance().multiply(disbandRefund));\n        }\n\n        plugin.getMissions().getIslandMissions().forEach(this::resetMission);\n\n        resetChunks(IslandChunkFlags.ONLY_PROTECTED, () -> Profiler.end(profilerId));\n\n        plugin.getGrid().deleteIsland(this);\n\n        Profiler.end(profilerId);\n    }\n\n    @Override\n    public boolean transferIsland(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        if (superiorPlayer.equals(owner))\n            return false;\n\n        SuperiorPlayer previousOwner = getOwner();\n\n        if (!PluginEventsFactory.callIslandTransferEvent(this, previousOwner, superiorPlayer))\n            return false;\n\n        Log.debug(Debug.TRANSFER_ISLAND, owner.getName(), superiorPlayer.getName());\n\n        //Kick member without saving to database\n        members.write(members -> members.remove(superiorPlayer));\n\n        superiorPlayer.setPlayerRole(SPlayerRole.lastRole());\n\n        //Add member without saving to database\n        members.write(members -> members.add(previousOwner));\n\n        PlayerRole previousRole = SPlayerRole.lastRole().getPreviousRole();\n        previousOwner.setPlayerRole(previousRole == null ? SPlayerRole.lastRole() : previousRole);\n\n        //Changing owner of the island.\n        owner = superiorPlayer;\n\n        IslandsDatabaseBridge.saveIslandLeader(this);\n        IslandsDatabaseBridge.addMember(this, previousOwner, getCreationTime());\n\n        plugin.getMissions().getIslandMissions().forEach(mission ->\n                mission.transferData(previousOwner, owner));\n\n        return true;\n    }\n\n    @Override\n    public void replacePlayers(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) {\n        Preconditions.checkNotNull(originalPlayer, \"originalPlayer parameter cannot be null.\");\n        Preconditions.checkState(originalPlayer != newPlayer, \"originalPlayer and newPlayer cannot equal.\");\n\n        Log.debug(Debug.REPLACE_PLAYER, owner, originalPlayer, newPlayer);\n\n        if (owner.equals(originalPlayer)) {\n            if (newPlayer == null) {\n                Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Disband Island\");\n                this.disbandIsland();\n            } else {\n                Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Replace Owner\");\n                owner = newPlayer;\n            }\n        } else if (isMember(originalPlayer)) {\n            Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Replace Member\");\n            members.write(members -> {\n                members.remove(originalPlayer);\n                if (newPlayer != null)\n                    members.add(newPlayer);\n            });\n        }\n\n        replaceVisitor(originalPlayer, newPlayer);\n        replaceBannedPlayer(originalPlayer, newPlayer);\n        replacePermissions(originalPlayer, newPlayer);\n    }\n\n    @Override\n    public void calcIslandWorth(@Nullable SuperiorPlayer asker) {\n        calcIslandWorth(asker, null);\n    }\n\n    @Override\n    public void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) {\n        Log.debug(Debug.CALCULATE_ISLAND, owner.getName(), asker);\n\n        long lastUpdateTime = getLastTimeUpdate();\n\n        if (lastUpdateTime != -1 && (System.currentTimeMillis() / 1000) - lastUpdateTime >= 600) {\n            Log.debugResult(Debug.CALCULATE_ISLAND, \"Result Cooldown\", owner.getName());\n            finishCalcIsland(asker, callback, getIslandLevel(), getWorth());\n            return;\n        }\n\n        registerTask(BukkitExecutor.ensureMain(() -> {\n            calcIslandWorthInternal(asker, callback);\n        }));\n    }\n\n    @Override\n    public IslandCalculationAlgorithm getCalculationAlgorithm() {\n        return this.calculationAlgorithm;\n    }\n\n    @Override\n    public void updateBorder() {\n        Log.debug(Debug.UPDATE_BORDER, owner.getName());\n        getAllPlayersInside().forEach(superiorPlayer -> superiorPlayer.updateWorldBorder(this));\n    }\n\n    @Override\n    public void updateIslandFly(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        IslandUtils.updateIslandFly(this, superiorPlayer);\n    }\n\n    @Override\n    public int getIslandSize() {\n        if (plugin.getSettings().isBuildOutsideIsland())\n            return (int) Math.round(plugin.getSettings().getMaxIslandSize() * 1.5);\n\n        return this.islandSize.readAndGet(IntValue::get);\n    }\n\n    @Override\n    public void setIslandSize(int islandSize) {\n        islandSize = Math.max(1, islandSize);\n\n        Preconditions.checkArgument(islandSize <= plugin.getSettings().getMaxIslandSize(), \"Border size \" + islandSize + \" cannot be larger than max island size: \" + plugin.getSettings().getMaxIslandSize());\n\n        Log.debug(Debug.SET_SIZE, owner.getName(), islandSize);\n\n        if (islandSize == getIslandSizeRaw())\n            return;\n\n        setIslandSizeInternal(IntValue.fixed(islandSize));\n\n        IslandsDatabaseBridge.saveSize(this);\n    }\n\n    private void setIslandSizeInternal(IntValue islandSize) {\n        boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class);\n\n        MutableObject<List<Chunk>> oldChunks = new MutableObject<>(null);\n\n\n        if (cropGrowthEnabled) {\n            // We first collect all the chunks that are currently being ticked\n            oldChunks.setValue(getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED));\n        }\n\n        // Changing the size of the island\n        this.islandSize.set(islandSize);\n\n        if (cropGrowthEnabled) {\n            // We now collect the new chunks after the size was changed\n            List<Chunk> newChunks = getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED);\n\n            registerTask(BukkitExecutor.ensureMain(() -> {\n                // We stop all old chunks from being ticked.\n                oldChunks.getValue().forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, true));\n                // We start ticking all the new chunks\n                newChunks.forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, false));\n            }));\n        }\n\n        this.protectedArea.update(this.center, getIslandSize());\n\n        updateBorder();\n    }\n\n    @Override\n    public int getIslandSizeRaw() {\n        return this.islandSize.readAndGet(islandSize -> islandSize.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public String getDiscord() {\n        return discord;\n    }\n\n    @Override\n    public void setDiscord(String discord) {\n        Preconditions.checkNotNull(discord, \"discord parameter cannot be null.\");\n\n        Log.debug(Debug.SET_DISCORD, owner.getName(), discord);\n\n        if (Objects.equals(discord, this.discord))\n            return;\n\n        this.discord = discord;\n        IslandsDatabaseBridge.saveDiscord(this);\n    }\n\n    @Override\n    public String getPaypal() {\n        return paypal;\n    }\n\n    @Override\n    public void setPaypal(String paypal) {\n        Preconditions.checkNotNull(paypal, \"paypal parameter cannot be null.\");\n\n        Log.debug(Debug.SET_PAYPAL, owner.getName(), paypal);\n\n        if (Objects.equals(paypal, this.paypal))\n            return;\n\n        this.paypal = paypal;\n        IslandsDatabaseBridge.savePaypal(this);\n    }\n\n    @Override\n    public Biome getBiome() {\n        if (biome == null) {\n            biomeGetterTask.set(this::getBiomeAsyncTask);\n            return IslandUtils.getDefaultWorldBiome(plugin.getSettings().getWorlds().getDefaultWorldDimension());\n        }\n\n        return biome;\n    }\n\n    private CompletableFuture<Biome> getBiomeAsyncTask(CompletableFuture<Biome> currentTask) {\n        if (currentTask != null)\n            return currentTask;\n\n        Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n        BlockPosition centerBlockPosition = getCenterPosition();\n\n        CompletableFuture<Biome> newTask = new CompletableFuture<>();\n\n        IslandWorlds.accessIslandWorldAsync(this, defaultWorldDimension, true, islandWorldResult -> {\n            if (islandWorldResult.getRight() != null) {\n                newTask.completeExceptionally(islandWorldResult.getRight());\n                return;\n            }\n\n            World world = islandWorldResult.getLeft();\n\n            ChunkPosition centerChunkPosition =\n                    ChunkPosition.of(world, centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4);\n\n            ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null)\n                    .thenApply(chunk -> centerBlockPosition.toLocation(world).getBlock().getBiome())\n                    .whenComplete((biome, error) -> {\n                        if (error != null)\n                            newTask.completeExceptionally(error);\n                        else {\n                            this.biome = biome;\n                            biomeGetterTask.set((CompletableFuture<Biome>) null);\n                            newTask.complete(biome);\n                        }\n                    });\n        });\n\n        return newTask;\n    }\n\n\n    @Override\n    public void setBiome(Biome biome) {\n        setBiome(biome, true);\n    }\n\n    @Override\n    public void setBiome(Biome biome, boolean updateBlocks) {\n        Preconditions.checkNotNull(biome, \"biome parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BIOME, owner.getName(), biome, updateBlocks);\n\n        this.biome = biome;\n\n        if (!updateBlocks)\n            return;\n\n\n        IslandWorlds.accessIslandWorldsAsync(this, false, result -> {\n            result.ifLeft(world -> {\n                WorldInfo worldInfo = WorldInfo.of(world);\n                Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == worldInfo.getDimension() ?\n                        biome : IslandUtils.getDefaultWorldBiome(worldInfo.getDimension());\n                List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0);\n                List<Player> playersToUpdate;\n                try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) {\n                    playersToUpdate = strategy.getPlayers(worldInfo);\n                }\n                plugin.getNMSChunks().setBiome(chunkPositions, worldBiome, playersToUpdate);\n            });\n        });\n\n        try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) {\n            for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) {\n                WorldInfo worldInfo = WorldInfo.of(registeredWorld);\n                List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0);\n                List<Player> playersToUpdate = strategy.getPlayers(worldInfo);\n                plugin.getNMSChunks().setBiome(chunkPositions, biome, playersToUpdate);\n            }\n        }\n    }\n\n    @Override\n    public boolean isLocked() {\n        return isLocked;\n    }\n\n    @Override\n    public void setLocked(boolean locked) {\n        Log.debug(Debug.SET_LOCKED, owner.getName(), locked);\n\n        if (this.isLocked == locked)\n            return;\n\n        this.isLocked = locked;\n\n        if (this.isLocked) {\n            for (SuperiorPlayer victimPlayer : getAllPlayersInside()) {\n                if (!hasPermission(victimPlayer, IslandPrivileges.CLOSE_BYPASS)) {\n                    victimPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                    Message.ISLAND_WAS_CLOSED.send(victimPlayer);\n                }\n            }\n        }\n\n        IslandsDatabaseBridge.saveLockedStatus(this);\n    }\n\n    @Override\n    public boolean isIgnored() {\n        return isTopIslandsIgnored;\n    }\n\n    @Override\n    public void setIgnored(boolean ignored) {\n        Log.debug(Debug.SET_IGNORED, owner.getName(), ignored);\n\n        if (this.isTopIslandsIgnored == ignored)\n            return;\n\n        this.isTopIslandsIgnored = ignored;\n\n        // We want top islands to get sorted again even if only 1 island exists\n        plugin.getGrid().setForceSort(true);\n\n        IslandsDatabaseBridge.saveIgnoredStatus(this);\n    }\n\n    @Override\n    public void sendMessage(String message) {\n        sendMessage(message, EMPTY_IGNORED_MEMBERS);\n    }\n\n    @Override\n    public void sendMessage(String message, UUID... ignoredMembers) {\n        Preconditions.checkNotNull(message, \"message parameter cannot be null.\");\n        Preconditions.checkNotNull(ignoredMembers, \"ignoredMembers parameter cannot be null.\");\n\n        Log.debug(Debug.SEND_MESSAGE, owner.getName(), message, Arrays.toString(ignoredMembers));\n\n        forEachIslandMember(ignoredMembers, false, islandMember -> {\n            String playerMessage = message;\n\n            if (!Text.isBlank(playerMessage))\n                playerMessage = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerMessage);\n\n            Message.CUSTOM.send(islandMember, playerMessage, false);\n        });\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent) {\n        sendMessage(messageComponent, EMPTY_MESSAGE_ARGS);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, Object... args) {\n        this.sendMessage(messageComponent, Collections.emptyList(), args);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers) {\n        sendMessage(messageComponent, ignoredMembers, EMPTY_MESSAGE_ARGS);\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers, Object... args) {\n        Preconditions.checkNotNull(messageComponent, \"messageComponent parameter cannot be null.\");\n        Preconditions.checkNotNull(ignoredMembers, \"ignoredMembers parameter cannot be null.\");\n\n        Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(args), ignoredMembers, Arrays.asList(args));\n\n        Set<UUID> ignoredMembersSet = ignoredMembers.isEmpty() ? Collections.emptySet() : new HashSet<>(ignoredMembers);\n\n        forEachIslandMember(ignoredMembersSet, false,\n                islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args));\n    }\n\n    @Override\n    public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) {\n        sendTitle(title, subtitle, fadeIn, duration, fadeOut, EMPTY_IGNORED_MEMBERS);\n    }\n\n    @Override\n    public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration,\n                          int fadeOut, UUID... ignoredMembers) {\n        Preconditions.checkNotNull(ignoredMembers, \"ignoredMembers parameter cannot be null.\");\n\n        Log.debug(Debug.SEND_TITLE, owner.getName(), title, subtitle, fadeIn, duration, fadeOut, Arrays.toString(ignoredMembers));\n\n        forEachIslandMember(ignoredMembers, true, islandMember -> {\n            String playerTitle = title;\n            String playerSubtitle = subtitle;\n\n            Player player = islandMember.asPlayer();\n\n            if (!Text.isBlank(playerTitle))\n                playerTitle = placeholdersService.get().parsePlaceholders(player, playerTitle);\n            if (!Text.isBlank(playerSubtitle))\n                playerSubtitle = placeholdersService.get().parsePlaceholders(player, playerSubtitle);\n\n            plugin.getNMSPlayers().sendTitle(player, playerTitle, playerSubtitle, fadeIn, duration, fadeOut);\n        });\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers) {\n        executeCommand(command, onlyOnlineMembers, EMPTY_IGNORED_MEMBERS);\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) {\n        Preconditions.checkNotNull(command, \"command parameter cannot be null.\");\n        Preconditions.checkNotNull(ignoredMembers, \"ignoredMembers parameter cannot be null.\");\n\n        Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, Arrays.toString(ignoredMembers));\n\n        registerTask(BukkitExecutor.ensureMain(() -> {\n            forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> {\n                String playerCommand = command;\n\n                if (!Text.isBlank(playerCommand)) {\n                    playerCommand = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerCommand)\n                            .replace(\"{player-name}\", islandMember.getName());\n                }\n\n                Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand);\n            });\n        }));\n    }\n\n    @Override\n    public boolean isBeingRecalculated() {\n        return beingRecalculated;\n    }\n\n    @Override\n    public void updateLastTime() {\n        setLastTimeUpdate(System.currentTimeMillis() / 1000);\n    }\n\n    @Override\n    public void setCurrentlyActive() {\n        setCurrentlyActive(true);\n    }\n\n    @Override\n    public void setCurrentlyActive(boolean active) {\n        Log.debug(Debug.ISLAND_ACTIVE, getOwner().getName(), active);\n        this.currentlyActive = active;\n    }\n\n    @Override\n    public boolean isCurrentlyActive() {\n        return this.currentlyActive;\n    }\n\n    @Override\n    public long getLastTimeUpdate() {\n        return this.currentlyActive ? -1 : lastTimeUpdate;\n    }\n\n    @Override\n    public void setLastTimeUpdate(long lastTimeUpdate) {\n        Log.debug(Debug.SET_ISLAND_LAST_TIME_UPDATED, owner.getName(), lastTimeUpdate);\n\n        if (this.lastTimeUpdate == lastTimeUpdate)\n            return;\n\n        this.lastTimeUpdate = lastTimeUpdate;\n\n        if (!isCurrentlyActive())\n            IslandsDatabaseBridge.saveLastTimeUpdate(this);\n    }\n\n    @Override\n    public IslandBank getIslandBank() {\n        return islandBank;\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return this.bankLimit.readAndGet(Value::get);\n    }\n\n    /*\n     *  Bank related methods\n     */\n\n    @Override\n    public void setBankLimit(BigDecimal bankLimit) {\n        Preconditions.checkNotNull(bankLimit, \"bankLimit parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BANK_LIMIT, owner.getName(), bankLimit);\n\n        if (Objects.equals(bankLimit, getBankLimitRaw()))\n            return;\n\n        if (bankLimit.compareTo(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE) <= 0) {\n            this.bankLimit.set(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE));\n\n            getUpgrades().forEach((upgradeName, level) -> {\n                Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName);\n                if (upgrade != null) {\n                    UpgradeLevel upgradeLevel = upgrade.getUpgradeLevel(level);\n                    if (upgradeLevel.getBankLimit().compareTo(getBankLimit()) > 0) {\n                        this.bankLimit.set(Value.syncedFixed(upgradeLevel.getBankLimit()));\n                    }\n                }\n            });\n        } else {\n            this.bankLimit.set(Value.fixed(bankLimit));\n        }\n\n        // Trying to give interest again if the last one failed.\n        if (hasGiveInterestFailed())\n            giveInterest(false);\n\n        IslandsDatabaseBridge.saveBankLimit(this);\n    }\n\n    @Override\n    public BigDecimal getBankLimitRaw() {\n        return this.bankLimit.readAndGet(bankLimit -> bankLimit.getNonSynced(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE));\n    }\n\n    @Override\n    public boolean giveInterest(boolean checkOnlineOwner) {\n        Log.debug(Debug.GIVE_BANK_INTEREST, owner.getName());\n\n        long currentTime = System.currentTimeMillis() / 1000;\n\n        int bankInterestRecentActive = BuiltinModules.BANK.getConfiguration().getBankInterestRecentActive();\n        if (checkOnlineOwner && bankInterestRecentActive > 0 && !owner.isOnline() &&\n                currentTime - owner.getLastTimeStatus() > bankInterestRecentActive) {\n            Log.debugResult(Debug.GIVE_BANK_INTEREST, \"Return Cooldown\", owner.getName());\n            return false;\n        }\n\n        int bankInterestPercentage = BuiltinModules.BANK.getConfiguration().getBankInterestPercentage();\n\n        BigDecimal balance = islandBank.getBalance().max(BigDecimal.ONE);\n        BigDecimal balanceToGive = balance.multiply(new BigDecimal(bankInterestPercentage / 100D));\n\n        // If the money that will be given exceeds limit, we want to give money later.\n        if (!islandBank.canDepositMoney(balanceToGive)) {\n            Log.debugResult(Debug.GIVE_BANK_INTEREST, \"Return Cannot Deposit Money\", owner.getName());\n            giveInterestFailed = true;\n            return false;\n        }\n\n        Log.debugResult(Debug.GIVE_BANK_INTEREST, \"Return Success\", owner.getName());\n\n        giveInterestFailed = false;\n\n        islandBank.depositAdminMoney(Bukkit.getConsoleSender(), balanceToGive);\n\n        setLastInterestTime(currentTime);\n\n        return true;\n    }\n\n    @Override\n    public long getLastInterestTime() {\n        return lastInterest;\n    }\n\n    @Override\n    public void setLastInterestTime(long lastInterest) {\n        if (this.lastInterest == lastInterest)\n            return;\n\n        if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) {\n            long ticksToNextInterest = BuiltinModules.BANK.getConfiguration().getBankInterestInterval() * 20L;\n            resetBankInterestTask(ticksToNextInterest);\n        }\n\n        this.lastInterest = lastInterest;\n        IslandsDatabaseBridge.saveLastInterestTime(this);\n    }\n\n    @Override\n    public long getNextInterest() {\n        long currentTime = System.currentTimeMillis() / 1000;\n        int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval();\n        return bankInterestInterval - (currentTime - lastInterest);\n    }\n\n    private void resetBankInterestTask(long ticksToNextInterest) {\n        this.bankInterestTask.set(bankInterestTask -> {\n            if (bankInterestTask != null)\n                bankInterestTask.cancel();\n            return registerTask(BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest));\n        });\n    }\n\n    /*\n     *  Worth related methods\n     */\n\n    @Override\n    public void handleBlockPlace(Block block) {\n        handleBlockPlace(block, 1);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block) {\n        return handleBlockPlaceWithResult(block, 1);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key) {\n        handleBlockPlace(key, 1);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key) {\n        return handleBlockPlaceWithResult(key, 1);\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount) {\n        handleBlockPlace(block, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) {\n        return handleBlockPlaceWithResult(block, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount) {\n        handleBlockPlace(key, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) {\n        return handleBlockPlaceWithResult(key, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        handleBlockPlace(Keys.of(block), amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        return handleBlockPlaceWithResult(Keys.of(block), amount, flags);\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        handleBlockPlaceWithResult(key, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkArgument(amount > 0, \"amount parameter must be positive.\");\n\n        BigInteger amountBig = BigInteger.valueOf(amount);\n\n        return handleBlockPlaceInternal(key, amountBig, flags);\n    }\n\n    private BlockChangeResult handleBlockPlaceInternal(Key key, @Size BigInteger amount, @IslandBlockFlags int flags) {\n        boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0;\n\n        boolean trackedBlock = accessBlocksTracker(rawBlocks,\n                blocksTracker -> blocksTracker.trackBlock(key, amount));\n\n        if (!trackedBlock)\n            return BlockChangeResult.MISSING_BLOCK_VALUE;\n\n        BigInteger newTotalBlocksCount = this.currentTotalBlockCounts.updateAndGet(count -> count.add(amount));\n\n        BigDecimal oldWorth = getWorth();\n        BigDecimal oldLevel = getIslandLevel();\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(key);\n        BigDecimal blockWorth = blockValue.getWorth();\n        BigDecimal blockLevel = blockValue.getLevel();\n\n        boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0;\n        boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0;\n\n        if (blockWorth.compareTo(BigDecimal.ZERO) != 0) {\n            islandWorth.updateAndGet(islandWorth -> islandWorth.add(blockWorth.multiply(new BigDecimal(amount))));\n            if (saveBlockCounts)\n                plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);\n        }\n\n        if (blockLevel.compareTo(BigDecimal.ZERO) != 0) {\n            islandLevel.updateAndGet(islandLevel -> islandLevel.add(blockLevel.multiply(new BigDecimal(amount))));\n            if (saveBlockCounts)\n                plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);\n        }\n\n        if (updateLastTimeStatus)\n            updateLastTime();\n\n        if (saveBlockCounts)\n            saveBlockCounts(newTotalBlocksCount, oldWorth, oldLevel);\n\n        return BlockChangeResult.SUCCESS;\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Block block, @Size int amount, boolean save) {\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n        handleBlockPlace(block, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, @Size int amount, boolean save) {\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n        handleBlockPlace(key, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, @Size BigInteger amount, boolean save) {\n        Preconditions.checkNotNull(key, \"key argument cannot be null\");\n        Preconditions.checkNotNull(amount, \"amount argument cannot be null\");\n\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n\n        handleBlockPlace(key, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, @Size BigInteger amount, boolean save, boolean updateLastTimeStatus) {\n        Preconditions.checkNotNull(key, \"key argument cannot be null\");\n        Preconditions.checkNotNull(amount, \"amount argument cannot be null\");\n\n        int flags = 0;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n        if (updateLastTimeStatus) flags |= IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n\n        handleBlockPlace(key, amount, flags);\n    }\n\n    @Deprecated\n    private void handleBlockPlace(Key key, @Size BigInteger amount, @IslandBlockFlags int flags) {\n        BigInteger MAX_INT_VALUE = BigInteger.valueOf(Integer.MAX_VALUE);\n        while (amount.compareTo(MAX_INT_VALUE) > 0) {\n            handleBlockPlace(key, Integer.MAX_VALUE, flags);\n            amount = amount.subtract(MAX_INT_VALUE);\n        }\n\n        handleBlockPlace(key, amount.intValueExact(), flags);\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks) {\n        handleBlocksPlace(blocks, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks) {\n        return handleBlocksPlaceWithResult(blocks,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        handleBlocksPlaceWithResult(blocks, flags);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        Preconditions.checkNotNull(blocks, \"blocks parameter cannot be null.\");\n\n        if (blocks.isEmpty())\n            return KeyMaps.createEmptyMap();\n\n        BigDecimal oldWorth = getWorth();\n        BigDecimal oldLevel = getIslandLevel();\n\n        boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0;\n\n        KeyMap<BlockChangeResult> result = accessBlocksTracker(rawBlocks, blocksTracker -> {\n            KeyMap<BlockChangeResult> resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n            blocks.forEach((blockKey, amount) -> {\n                BlockChangeResult blockResult = handleBlockPlaceWithResult(blockKey, amount, 0);\n                if (blockResult != BlockChangeResult.SUCCESS)\n                    resultMap.put(blockKey, blockResult);\n            });\n            return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap);\n        });\n\n        boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0;\n        boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0;\n\n        if (saveBlockCounts)\n            saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel);\n\n        if (updateLastTimeStatus)\n            updateLastTime();\n\n        return result;\n    }\n\n    @Override\n    public void handleBlockBreak(Block block) {\n        handleBlockBreak(block, 1);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block) {\n        return handleBlockBreakWithResult(block, 1);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key) {\n        handleBlockBreak(key, 1);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key) {\n        return handleBlockBreakWithResult(key, 1);\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount) {\n        handleBlockBreak(block, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) {\n        return handleBlockBreakWithResult(block, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount) {\n        handleBlockBreak(key, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) {\n        return handleBlockBreakWithResult(key, amount,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        handleBlockBreak(Keys.of(block), amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, int flags) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        return handleBlockBreakWithResult(Keys.of(block), amount, flags);\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        handleBlockBreakWithResult(key, amount, flags);\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, int flags) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkArgument(amount > 0, \"amount parameter must be positive.\");\n\n        BigInteger amountBig = BigInteger.valueOf(amount);\n\n        boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0;\n\n        boolean untrackedBlocks = accessBlocksTracker(rawBlocks,\n                blocksTracker -> blocksTracker.untrackBlock(key, amountBig));\n\n        if (!untrackedBlocks)\n            return BlockChangeResult.MISSING_BLOCK_VALUE;\n\n        BigInteger newTotalBlocksCount = this.currentTotalBlockCounts.updateAndGet(count -> count.subtract(amountBig));\n\n        BigDecimal oldWorth = getWorth(), oldLevel = getIslandLevel();\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(key);\n        BigDecimal blockWorth = blockValue.getWorth();\n        BigDecimal blockLevel = blockValue.getLevel();\n\n        boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0;\n        boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0;\n\n        if (blockWorth.compareTo(BigDecimal.ZERO) != 0) {\n            this.islandWorth.updateAndGet(islandWorth -> islandWorth.subtract(blockWorth.multiply(new BigDecimal(amount))));\n            if (saveBlockCounts)\n                plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);\n        }\n\n        if (blockLevel.compareTo(BigDecimal.ZERO) != 0) {\n            this.islandLevel.updateAndGet(islandLevel -> islandLevel.subtract(blockLevel.multiply(new BigDecimal(amount))));\n            if (saveBlockCounts)\n                plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);\n        }\n\n        if (updateLastTimeStatus)\n            updateLastTime();\n\n        if (saveBlockCounts)\n            saveBlockCounts(newTotalBlocksCount, oldWorth, oldLevel);\n\n        return BlockChangeResult.SUCCESS;\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Block block, @Size int amount, boolean save) {\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n        handleBlockBreak(block, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, @Size int amount, boolean save) {\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n        handleBlockBreak(key, amount, flags);\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, @Size BigInteger amount, boolean save) {\n        Preconditions.checkNotNull(key, \"key argument cannot be null\");\n        Preconditions.checkNotNull(amount, \"amount argument cannot be null\");\n\n        int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n        if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n\n        BigInteger MAX_INT_VALUE = BigInteger.valueOf(Integer.MAX_VALUE);\n        while (amount.compareTo(MAX_INT_VALUE) > 0) {\n            handleBlockBreak(key, Integer.MAX_VALUE, flags);\n            amount = amount.subtract(MAX_INT_VALUE);\n        }\n\n        handleBlockBreak(key, amount.intValueExact(), flags);\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks) {\n        handleBlocksBreak(blocks,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks) {\n        return handleBlocksBreakWithResult(blocks,\n                IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS);\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        handleBlocksBreakWithResult(blocks, flags);\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks, int flags) {\n        Preconditions.checkNotNull(blocks, \"blocks parameter cannot be null.\");\n\n        if (blocks.isEmpty())\n            return KeyMaps.createEmptyMap();\n\n        BigDecimal oldWorth = getWorth();\n        BigDecimal oldLevel = getIslandLevel();\n\n        boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0;\n\n        KeyMap<BlockChangeResult> result = accessBlocksTracker(rawBlocks, blocksTracker -> {\n            KeyMap<BlockChangeResult> resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n            blocks.forEach((blockKey, amount) -> {\n                BlockChangeResult blockResult = handleBlockBreakWithResult(blockKey, amount, 0);\n                if (blockResult != BlockChangeResult.SUCCESS)\n                    resultMap.put(blockKey, blockResult);\n            });\n            return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap);\n        });\n\n        boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0;\n        boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0;\n\n        if (saveBlockCounts)\n            saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel);\n\n        if (updateLastTimeStatus)\n            updateLastTime();\n\n        return result;\n    }\n\n    @Override\n    public boolean isChunkDirty(World world, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(world, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        return this.isChunkDirty(world.getName(), chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null.\");\n        return isChunkDirty(plugin.getGrid().getIslandsWorldInfo(this, worldName), chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        Preconditions.checkArgument(worldInfo != null && isInside(chunkX, chunkZ),\n                \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) {\n            return this.dirtyChunksContainer.isMarkedDirty(chunkPosition);\n        }\n    }\n\n    @Override\n    public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        markChunkDirty(WorldInfo.of(world), chunkX, chunkZ, save);\n    }\n\n    @Override\n    public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), \"Chunk {\" + worldInfo.getName() + \",\" + chunkX + \",\" + chunkZ + \"} must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markDirty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        markChunkEmpty(WorldInfo.of(world), chunkX, chunkZ, save);\n    }\n\n    @Override\n    public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), \"Chunk {\" + worldInfo.getName() + \",\" + chunkX + \",\" + chunkZ + \"} must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markEmpty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public BigInteger getBlockCountAsBigInteger(Key key) {\n        return this.blocksTracker.getBlockCount(key);\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCountsAsBigInteger() {\n        return this.blocksTracker.getBlockCounts();\n    }\n\n    @Override\n    public BigInteger getExactBlockCountAsBigInteger(Key key) {\n        return this.blocksTracker.getExactBlockCount(key);\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        blocksTracker.clearBlockCounts();\n        this.currentTotalBlockCounts.set(BigInteger.ZERO);\n\n        islandWorth.set(BigDecimal.ZERO);\n        islandLevel.set(BigDecimal.ZERO);\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);\n    }\n\n    @Override\n    public IslandBlocksTrackerAlgorithm getBlocksTracker() {\n        return this.blocksTracker;\n    }\n\n    @Override\n    public BigDecimal getWorth() {\n        double bankWorthRate = BuiltinModules.BANK.getConfiguration().getBankWorthRate();\n\n        BigDecimal islandWorth = this.islandWorth.get();\n        BigDecimal islandBank = this.islandBank.getBalance();\n        BigDecimal bonusWorth = this.bonusWorth.get();\n        BigDecimal finalIslandWorth = (bankWorthRate <= 0 ? getRawWorth() : islandWorth.add(\n                islandBank.multiply(BigDecimal.valueOf(bankWorthRate)))).add(bonusWorth);\n\n        if (!plugin.getSettings().isNegativeWorth() && finalIslandWorth.compareTo(BigDecimal.ZERO) < 0)\n            return BigDecimal.ZERO;\n\n        return finalIslandWorth;\n    }\n\n    @Override\n    public BigDecimal getRawWorth() {\n        return islandWorth.get();\n    }\n\n    @Override\n    public BigDecimal getBonusWorth() {\n        return bonusWorth.get();\n    }\n\n    @Override\n    public void setBonusWorth(BigDecimal bonusWorth) {\n        Preconditions.checkNotNull(bonusWorth, \"bonusWorth parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BONUS_WORTH, owner.getName(), bonusWorth);\n\n        BigDecimal oldBonusWorth = this.bonusWorth.getAndSet(bonusWorth);\n\n        if (Objects.equals(oldBonusWorth, bonusWorth))\n            return;\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);\n        plugin.getGrid().sortIslands(SortingTypes.BY_WORTH);\n\n        IslandsDatabaseBridge.saveBonusWorth(this);\n    }\n\n    @Override\n    public BigDecimal getBonusLevel() {\n        return bonusLevel.get();\n    }\n\n    @Override\n    public void setBonusLevel(BigDecimal bonusLevel) {\n        Preconditions.checkNotNull(bonusLevel, \"bonusLevel parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BONUS_LEVEL, owner.getName(), bonusLevel);\n\n        BigDecimal oldBonusLevel = this.bonusLevel.getAndSet(bonusLevel);\n\n        if (Objects.equals(oldBonusLevel, bonusLevel))\n            return;\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);\n        plugin.getGrid().sortIslands(SortingTypes.BY_LEVEL);\n\n        IslandsDatabaseBridge.saveBonusLevel(this);\n    }\n\n    @Override\n    public BigDecimal getIslandLevel() {\n        BigDecimal bonusLevel = this.bonusLevel.get();\n        BigDecimal islandLevel = this.islandLevel.get().add(bonusLevel);\n\n        if (plugin.getSettings().isRoundedIslandLevels()) {\n            islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode());\n        }\n\n        if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0)\n            islandLevel = BigDecimal.ZERO;\n\n        return islandLevel;\n    }\n\n    @Override\n    public BigDecimal getRawLevel() {\n        BigDecimal islandLevel = this.islandLevel.get();\n\n        if (plugin.getSettings().isRoundedIslandLevels()) {\n            islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode());\n        }\n\n        if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0)\n            islandLevel = BigDecimal.ZERO;\n\n        return islandLevel;\n    }\n\n    @Override\n    public UpgradeLevel getUpgradeLevel(Upgrade upgrade) {\n        Preconditions.checkNotNull(upgrade, \"upgrade parameter cannot be null.\");\n        return upgrade.getUpgradeLevel(getUpgrades().getOrDefault(upgrade.getName(), 1));\n    }\n\n    @Override\n    public void setUpgradeLevel(Upgrade upgrade, int level) {\n        Preconditions.checkNotNull(upgrade, \"upgrade parameter cannot be null.\");\n\n        Log.debug(Debug.SET_UPGRADE, owner.getName(), upgrade.getName(), level);\n\n        int currentLevel = getUpgradeLevel(upgrade).getLevel();\n\n        if (currentLevel == level)\n            return;\n\n        this.upgrades.setUpgradeLevel(upgrade, level);\n\n        lastUpgradeTime = System.currentTimeMillis();\n\n        IslandsDatabaseBridge.saveUpgrade(this, upgrade, level);\n\n        UpgradeLevel upgradeLevel = getUpgradeLevel(upgrade);\n\n        // Level was downgraded, we need to clear the values of that level and sync all upgrades again\n        if (currentLevel > level) {\n            syncUpgrades(false);\n        } else {\n            syncUpgrade((SUpgradeLevel) upgradeLevel, false);\n        }\n\n        plugin.getMenus().refreshUpgrades(this);\n    }\n\n    @Override\n    public Map<String, Integer> getUpgrades() {\n        return this.upgrades.getUpgrades();\n    }\n\n    @Override\n    public void syncUpgrades() {\n        syncUpgrades(true);\n    }\n\n    /*\n     *  Upgrade related methods\n     */\n\n    @Override\n    public void updateUpgrades() {\n        clearUpgrades(false);\n        // We want to sync the default upgrade first, then the actual upgrades\n        syncUpgrade(DefaultUpgradeLevel.getInstance(), false);\n        // Syncing all real upgrades\n        plugin.getUpgrades().getUpgrades().forEach(upgrade -> syncUpgrade((SUpgradeLevel) getUpgradeLevel(upgrade), false));\n    }\n\n    @Override\n    public long getLastTimeUpgrade() {\n        return lastUpgradeTime;\n    }\n\n    @Override\n    public boolean hasActiveUpgradeCooldown() {\n        long lastTimeUpgrade = getLastTimeUpgrade();\n        long currentTime = System.currentTimeMillis();\n        long upgradeCooldown = plugin.getSettings().getUpgradeCooldown();\n        return upgradeCooldown > 0 && lastTimeUpgrade > 0 && currentTime - lastTimeUpgrade <= upgradeCooldown;\n    }\n\n    @Override\n    public double getCropGrowthMultiplier() {\n        return this.cropGrowth.readAndGet(DoubleValue::get);\n    }\n\n    @Override\n    public void setCropGrowthMultiplier(double cropGrowth) {\n        cropGrowth = Math.max(1, cropGrowth);\n\n        Log.debug(Debug.SET_CROP_GROWTH, owner.getName(), cropGrowth);\n\n        if (cropGrowth == getCropGrowthRaw())\n            return;\n\n        DoubleValue oldCropGrowth = this.cropGrowth.set(DoubleValue.fixed(cropGrowth));\n\n        if (cropGrowth == DoubleValue.getNonSynced(oldCropGrowth, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveCropGrowth(this);\n\n        notifyCropGrowthChange(cropGrowth);\n    }\n\n    @Override\n    public double getCropGrowthRaw() {\n        return this.cropGrowth.readAndGet(cropGrowth -> cropGrowth.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public double getSpawnerRatesMultiplier() {\n        return this.spawnerRates.readAndGet(DoubleValue::get);\n    }\n\n    @Override\n    public void setSpawnerRatesMultiplier(double spawnerRates) {\n        spawnerRates = Math.max(1, spawnerRates);\n\n        Log.debug(Debug.SET_SPAWNER_RATES, owner.getName(), spawnerRates);\n\n        DoubleValue oldSpawnerRates = this.spawnerRates.set(DoubleValue.fixed(spawnerRates));\n\n        if (spawnerRates == DoubleValue.getNonSynced(oldSpawnerRates, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveSpawnerRates(this);\n    }\n\n    @Override\n    public double getSpawnerRatesRaw() {\n        return this.spawnerRates.readAndGet(spawnerRates -> spawnerRates.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public double getMobDropsMultiplier() {\n        return this.mobDrops.readAndGet(DoubleValue::get);\n    }\n\n    @Override\n    public void setMobDropsMultiplier(double mobDrops) {\n        mobDrops = Math.max(1, mobDrops);\n\n        Log.debug(Debug.SET_MOB_DROPS, owner.getName(), mobDrops);\n\n        DoubleValue oldMobDrops = this.mobDrops.set(DoubleValue.fixed(mobDrops));\n\n        if (mobDrops == DoubleValue.getNonSynced(oldMobDrops, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveMobDrops(this);\n    }\n\n    @Override\n    public double getMobDropsRaw() {\n        return this.mobDrops.readAndGet(mobDrops -> mobDrops.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public int getBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        IntValue blockLimit = blockLimits.get(key);\n        return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get();\n    }\n\n    @Override\n    public int getExactBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        IntValue blockLimit = blockLimits.getRaw(key, null);\n        return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get();\n    }\n\n    @Override\n    public Key getBlockLimitKey(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return blockLimits.getKey(key, key);\n    }\n\n    @Override\n    public Map<Key, Integer> getBlocksLimits() {\n        KeyMap<Integer> blockLimits = KeyMap.createKeyMap();\n        this.blockLimits.forEach((block, limit) -> blockLimits.put(block, limit.get()));\n        return Collections.unmodifiableMap(blockLimits);\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomBlocksLimits() {\n        return Collections.unmodifiableMap(this.blockLimits.entrySet().stream()\n                .filter(entry -> !entry.getValue().isSynced())\n                .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get())));\n    }\n\n    @Override\n    public void clearBlockLimits() {\n        Log.debug(Debug.CLEAR_BLOCK_LIMITS, owner.getName());\n\n        if (blockLimits.isEmpty())\n            return;\n\n        blockLimits.clear();\n        IslandsDatabaseBridge.clearBlockLimits(this);\n    }\n\n    @Override\n    public void setBlockLimit(Key key, int limit) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        int finalLimit = Math.max(0, limit);\n\n        Log.debug(Debug.SET_BLOCK_LIMIT, owner.getName(), key, finalLimit);\n\n        IntValue oldLimit = blockLimits.put(key, IntValue.fixed(finalLimit));\n\n        if (limit == IntValue.getNonSynced(oldLimit, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        plugin.getBlockValues().addCustomBlockKey(key);\n        IslandsDatabaseBridge.saveBlockLimit(this, key, limit);\n    }\n\n    @Override\n    public void removeBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_BLOCK_LIMIT, owner.getName(), key);\n\n        IntValue oldBlockLimit = blockLimits.remove(key);\n\n        if (oldBlockLimit == null)\n            return;\n\n        IslandsDatabaseBridge.removeBlockLimit(this, key);\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return hasReachedBlockLimit(key, 1);\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key, @Size int amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkArgument(amount >= 0, \"amount parameter must be non-negative.\");\n\n        int blockLimit = getExactBlockLimit(key);\n\n        //Checking for the specific provided key.\n        if (blockLimit >= 0) {\n            return getBlockCountAsBigInteger(key).add(BigInteger.valueOf(amount))\n                    .compareTo(BigInteger.valueOf(blockLimit)) > 0;\n        }\n\n        //Getting the global key values.\n        key = ((BaseKey<?>) key).toGlobalKey();\n        blockLimit = getBlockLimit(key);\n\n        return blockLimit >= 0 && getBlockCountAsBigInteger(key)\n                .add(BigInteger.valueOf(amount)).compareTo(BigInteger.valueOf(blockLimit)) > 0;\n    }\n\n    @Override\n    public int getEntityLimit(EntityType entityType) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return getEntityLimit(Keys.of(entityType));\n    }\n\n    @Override\n    public int getEntityLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        IntValue entityLimit = entityLimits.get(key);\n        return entityLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : entityLimit.get();\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesLimitsAsKeys() {\n        return Collections.unmodifiableMap(this.entityLimits.entrySet().stream().collect(\n                KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get())\n        ));\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomEntitiesLimits() {\n        return Collections.unmodifiableMap(this.entityLimits.entrySet().stream()\n                .filter(entry -> !entry.getValue().isSynced())\n                .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get())));\n    }\n\n    @Override\n    public void clearEntitiesLimits() {\n        Log.debug(Debug.CLEAR_ENTITY_LIMITS, owner.getName());\n\n        if (entityLimits.isEmpty())\n            return;\n\n        entityLimits.clear();\n        IslandsDatabaseBridge.clearEntityLimits(this);\n    }\n\n    @Override\n    public void setEntityLimit(EntityType entityType, int limit) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        setEntityLimit(Keys.of(entityType), limit);\n    }\n\n    @Override\n    public void setEntityLimit(Key key, int limit) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        int finalLimit = Math.max(0, limit);\n\n        Log.debug(Debug.SET_ENTITY_LIMIT, owner.getName(), key, finalLimit);\n\n        IntValue oldEntityLimit = entityLimits.put(key, IntValue.fixed(limit));\n\n        if (limit == IntValue.getNonSynced(oldEntityLimit, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveEntityLimit(this, key, limit);\n    }\n\n    @Override\n    public void removeEntityLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_ENTITY_LIMIT, owner.getName(), key);\n\n        IntValue oldEntityLimit = entityLimits.remove(key);\n\n        if (oldEntityLimit == null)\n            return;\n\n        IslandsDatabaseBridge.removeEntityLimit(this, key);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return hasReachedEntityLimit(Keys.of(entityType));\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return hasReachedEntityLimit(key, 1);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType, @Size int amount) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return hasReachedEntityLimit(Keys.of(entityType), amount);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key, @Size int amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkArgument(amount >= 0, \"amount parameter must be non-negative.\");\n\n        int entityLimit = getEntityLimit(key);\n\n        if (entityLimit < 0)\n            return CompletableFuture.completedFuture(false);\n\n        return CompletableFuture.completedFuture(this.entitiesTracker.getEntityCount(key) + amount > entityLimit);\n    }\n\n    @Override\n    public IslandEntitiesTrackerAlgorithm getEntitiesTracker() {\n        return this.entitiesTracker;\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return this.teamLimit.readAndGet(IntValue::get);\n    }\n\n    @Override\n    public void setTeamLimit(int teamLimit) {\n        teamLimit = Math.max(0, teamLimit);\n\n        Log.debug(Debug.SET_TEAM_LIMIT, owner.getName(), teamLimit);\n\n        IntValue oldTeamLimit = this.teamLimit.set(IntValue.fixed(teamLimit));\n\n        if (teamLimit == IntValue.getNonSynced(oldTeamLimit, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveTeamLimit(this);\n    }\n\n    @Override\n    public int getTeamLimitRaw() {\n        return this.teamLimit.readAndGet(teamLimit -> teamLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return this.warpsLimit.readAndGet(IntValue::get);\n    }\n\n    @Override\n    public void setWarpsLimit(int warpsLimit) {\n        warpsLimit = Math.max(0, warpsLimit);\n\n        Log.debug(Debug.SET_WARPS_LIMIT, owner.getName(), warpsLimit);\n\n        IntValue oldWarpsLimit = this.warpsLimit.set(IntValue.fixed(warpsLimit));\n\n        if (warpsLimit == IntValue.getNonSynced(oldWarpsLimit, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveWarpsLimit(this);\n    }\n\n    @Override\n    public int getWarpsLimitRaw() {\n        return this.warpsLimit.readAndGet(warpsLimit -> warpsLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE));\n    }\n\n    @Override\n    public void setPotionEffect(PotionEffectType type, int level) {\n        // Legacy support for levels can be set to <= 0 for removing the effect.\n        // Nowadays, removePotionEffect exists.\n        if (level <= 0) {\n            removePotionEffect(type);\n            return;\n        }\n\n        Preconditions.checkNotNull(type, \"potionEffectType parameter cannot be null.\");\n\n        Log.debug(Debug.SET_ISLAND_EFFECT, owner.getName(), type.getName(), level);\n\n        IntValue oldPotionLevel = islandEffects.put(type, IntValue.fixed(level));\n\n        if (level == IntValue.getNonSynced(oldPotionLevel, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> {\n            Player player = superiorPlayer.asPlayer();\n            assert player != null;\n            if (oldPotionLevel != null && oldPotionLevel.get() > level)\n                player.removePotionEffect(type);\n\n            PotionEffect potionEffect = new PotionEffect(type, Integer.MAX_VALUE, level - 1);\n            player.addPotionEffect(potionEffect, true);\n        })));\n\n        IslandsDatabaseBridge.saveIslandEffect(this, type, level);\n    }\n\n    @Override\n    public void removePotionEffect(PotionEffectType type) {\n        Preconditions.checkNotNull(type, \"potionEffectType parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_ISLAND_EFFECT, owner.getName(), type.getName());\n\n        IntValue oldEffectLevel = islandEffects.remove(type);\n\n        if (oldEffectLevel == null)\n            return;\n\n        registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> {\n            Player player = superiorPlayer.asPlayer();\n            if (player != null)\n                player.removePotionEffect(type);\n        })));\n\n        IslandsDatabaseBridge.removeIslandEffect(this, type);\n    }\n\n    @Override\n    public int getPotionEffectLevel(PotionEffectType type) {\n        Preconditions.checkNotNull(type, \"potionEffectType parameter cannot be null.\");\n        IntValue islandEffect = islandEffects.get(type);\n        return islandEffect == null ? 0 : islandEffect.get();\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getPotionEffects() {\n        Map<PotionEffectType, Integer> islandEffects = new ArrayMap<>();\n\n        this.islandEffects.forEach((potionEffectType, levelValue) -> {\n            int level = levelValue.get();\n            if (level > 0)\n                islandEffects.put(potionEffectType, level);\n        });\n\n        return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects);\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getCustomPotionEffects() {\n        Map<PotionEffectType, Integer> islandEffects = new ArrayMap<>();\n\n        this.islandEffects.forEach((potionEffectType, levelValue) -> {\n            int level = levelValue.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE);\n            if (level > 0)\n                islandEffects.put(potionEffectType, level);\n        });\n\n        return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects);\n    }\n\n    @Override\n    public void applyEffects(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class))\n            return;\n\n        applyEffectsNoUpgradeCheck(superiorPlayer);\n    }\n\n    @Override\n    public void applyEffects() {\n        if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class))\n            getAllPlayersInside().forEach(this::applyEffectsNoUpgradeCheck);\n    }\n\n    @Override\n    public void removeEffects(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class))\n            removeEffectsNoUpgradeCheck(superiorPlayer);\n    }\n\n    @Override\n    public void removeEffects() {\n        if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class))\n            getAllPlayersInside().forEach(this::removeEffectsNoUpgradeCheck);\n    }\n\n    @Override\n    public void clearEffects() {\n        Log.debug(Debug.CLEAR_ISLAND_EFFECTS, owner.getName());\n\n        if (islandEffects.isEmpty())\n            return;\n\n        islandEffects.clear();\n        removeEffects();\n\n        IslandsDatabaseBridge.clearIslandEffects(this);\n    }\n\n    @Override\n    public void setRoleLimit(PlayerRole playerRole, int limit) {\n        // Legacy support for limits can be set to < 0 for removing the limit.\n        // Nowadays, removeRoleLimit exists.\n        if (limit < 0) {\n            removeRoleLimit(playerRole);\n            return;\n        }\n\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n\n        Log.debug(Debug.SET_ROLE_LIMIT, owner.getName(), playerRole.getName(), limit);\n\n        IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits ->\n                roleLimits.put(playerRole.getId(), IntValue.fixed(limit)));\n\n        if (limit == IntValue.getNonSynced(oldRoleLimit, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveRoleLimit(this, playerRole, limit);\n    }\n\n    @Override\n    public void removeRoleLimit(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_ROLE_LIMIT, owner.getName(), playerRole.getName());\n\n        IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> roleLimits.remove(playerRole.getId()));\n\n        if (oldRoleLimit == null)\n            return;\n\n        IslandsDatabaseBridge.removeRoleLimit(this, playerRole);\n    }\n\n    @Override\n    public int getRoleLimit(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        IntValue roleLimit = roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId()));\n        return roleLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : roleLimit.get();\n    }\n\n    @Override\n    public int getRoleLimitRaw(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        return IntValue.getNonSynced(roleLimits.readAndGet(roleLimits ->\n                roleLimits.get(playerRole.getId())), IslandUpgradeConstants.SYNCED_VALUE);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getRoleLimits() {\n        if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty))\n            return Collections.emptyMap();\n\n        Map<PlayerRole, Integer> roleLimits = new HashMap<>();\n        this.roleLimits.read(roleLimitsMap -> {\n            Iterator<Int2ObjectMapView.Entry<IntValue>> iterator = roleLimitsMap.entryIterator();\n            while (iterator.hasNext()) {\n                Int2ObjectMapView.Entry<IntValue> entry = iterator.next();\n                roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get());\n            }\n        });\n\n        return Collections.unmodifiableMap(roleLimits);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getCustomRoleLimits() {\n        if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty))\n            return Collections.emptyMap();\n\n        Map<PlayerRole, Integer> roleLimits = new HashMap<>();\n        this.roleLimits.read(roleLimitsMap -> {\n            Iterator<Int2ObjectMapView.Entry<IntValue>> iterator = roleLimitsMap.entryIterator();\n            while (iterator.hasNext()) {\n                Int2ObjectMapView.Entry<IntValue> entry = iterator.next();\n                if (!entry.getValue().isSynced())\n                    roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get());\n            }\n        });\n\n        return Collections.unmodifiableMap(roleLimits);\n    }\n\n    @Override\n    public WarpCategory createWarpCategory(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        Log.debug(Debug.CREATE_WARP_CATEGORY, owner.getName(), name);\n\n        WarpCategory warpCategory = warpCategories.get(name.toLowerCase(Locale.ENGLISH));\n\n        if (warpCategory == null) {\n            Log.debugResult(Debug.CREATE_WARP_CATEGORY, \"Result New Category\", name);\n            List<Integer> occupiedSlots = warpCategories.values().stream().map(WarpCategory::getSlot).collect(Collectors.toList());\n\n            int slot = 0;\n            while (occupiedSlots.contains(slot))\n                ++slot;\n\n            warpCategory = loadWarpCategory(name, slot, null);\n\n            IslandsDatabaseBridge.saveWarpCategory(this, warpCategory);\n\n            plugin.getMenus().refreshWarpCategories(this);\n        } else {\n            Log.debugResult(Debug.CREATE_WARP_CATEGORY, \"Result Already Exists\", name);\n        }\n\n        return warpCategory;\n    }\n\n    @Override\n    public WarpCategory getWarpCategory(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return warpCategories.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public WarpCategory getWarpCategory(int slot) {\n        return warpCategories.values().stream().filter(warpCategory -> warpCategory.getSlot() == slot)\n                .findAny().orElse(null);\n    }\n\n    @Override\n    public void renameCategory(WarpCategory warpCategory, String newName) {\n        Preconditions.checkNotNull(warpCategory, \"warpCategory parameter cannot be null.\");\n        Preconditions.checkNotNull(newName, \"newName parameter cannot be null.\");\n\n        warpCategories.remove(warpCategory.getName().toLowerCase(Locale.ENGLISH));\n        warpCategories.put(newName.toLowerCase(Locale.ENGLISH), warpCategory);\n        warpCategory.setName(newName);\n    }\n\n    @Override\n    public void deleteCategory(WarpCategory warpCategory) {\n        Preconditions.checkNotNull(warpCategory, \"warpCategory parameter cannot be null.\");\n\n        Log.debug(Debug.DELETE_WARP_CATEGORY, owner.getName(), warpCategory.getName());\n\n        boolean validCategoryRemoval = warpCategories.remove(warpCategory.getName().toLowerCase(Locale.ENGLISH)) != null;\n\n        if (!validCategoryRemoval)\n            return;\n\n        IslandsDatabaseBridge.removeWarpCategory(this, warpCategory);\n\n        boolean shouldSaveWarps = !warpCategory.getWarps().isEmpty();\n\n        if (shouldSaveWarps) {\n            new LinkedList<>(warpCategory.getWarps()).forEach(islandWarp -> deleteWarp(islandWarp.getName()));\n            plugin.getMenus().destroyWarps(warpCategory);\n        }\n\n        plugin.getMenus().destroyWarpCategories(this);\n    }\n\n    @Override\n    public Map<String, WarpCategory> getWarpCategories() {\n        return Collections.unmodifiableMap(warpCategories);\n    }\n\n    @Override\n    public IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        if (!(location instanceof LazyWorldLocation))\n            Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n\n        WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, LazyWorldLocation.getWorldName(location));\n        WorldPosition worldPosition = SWorldPosition.of(location);\n\n        return createIslandInternal(name, worldInfo, worldPosition, warpCategory);\n    }\n\n    @Override\n    public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkNotNull(position, \"position parameter cannot be null.\");\n\n        return createIslandInternal(name, worldInfo, position, warpCategory);\n    }\n\n    private IslandWarp createIslandInternal(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkState(getWarp(name) == null, \"Warp already exists: \" + name);\n\n        Log.debug(Debug.CREATE_WARP, owner.getName(), name, worldInfo, worldPosition, warpCategory);\n\n        IslandWarp islandWarp = loadIslandWarp(name, worldInfo, worldPosition, warpCategory,\n                !plugin.getSettings().isPublicWarps(), null);\n\n        IslandsDatabaseBridge.saveWarp(this, islandWarp);\n\n        plugin.getMenus().refreshGlobalWarps();\n        plugin.getMenus().refreshWarps(islandWarp.getCategory());\n\n        return islandWarp;\n    }\n\n    /*\n     *  Warps related methods\n     */\n\n    @Override\n    public void renameWarp(IslandWarp islandWarp, String newName) {\n        Preconditions.checkNotNull(islandWarp, \"islandWarp parameter cannot be null.\");\n        Preconditions.checkNotNull(newName, \"newName parameter cannot be null.\");\n        Preconditions.checkArgument(IslandUtils.isWarpNameLengthValid(newName), \"Warp names must cannot be longer than 255 chars.\");\n        Preconditions.checkState(getWarp(newName) == null, \"Cannot rename warps to an already existing warps.\");\n\n        warpsByName.remove(islandWarp.getName().toLowerCase(Locale.ENGLISH));\n        warpsByName.put(newName.toLowerCase(Locale.ENGLISH), islandWarp);\n        islandWarp.setName(newName);\n    }\n\n    @Override\n    public IslandWarp getWarp(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n        return this.warpsByLocation.readAndGet(warpsByLocation -> warpsByLocation.get(location));\n    }\n\n    @Override\n    public IslandWarp getWarp(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return warpsByName.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) {\n        warpPlayer(superiorPlayer, warpName, false);\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(warpName, \"warp parameter cannot be null.\");\n\n        IslandWarp islandWarp = getWarp(warpName);\n\n        if (islandWarp == null) {\n            Message.INVALID_WARP.send(superiorPlayer, warpName);\n            return;\n        }\n\n        if (!force && !superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) {\n            if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer)\n                    .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) {\n                Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer);\n                return;\n            }\n\n            plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer,\n                    plugin.getSettings().getChargeOnWarp());\n        }\n\n        EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getWarpsWarmup(),\n                unused -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp));\n    }\n\n    @Override\n    public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        Preconditions.checkNotNull(location.getWorld(), \"location's world parameter cannot be null.\");\n\n        IslandWarp islandWarp = this.warpsByLocation.writeAndGet(\n                warpsByLocation -> warpsByLocation.remove(location));\n\n        if (islandWarp == null)\n            return;\n\n        deleteWarp(islandWarp.getName());\n\n        if (superiorPlayer != null)\n            Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName());\n    }\n\n    @Override\n    public void deleteWarp(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        Log.debug(Debug.DELETE_WARP, owner.getName(), name);\n\n        IslandWarp islandWarp = warpsByName.remove(name.toLowerCase(Locale.ENGLISH));\n        WarpCategory warpCategory = islandWarp == null ? null : islandWarp.getCategory();\n\n        if (islandWarp != null) {\n            try (ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n                Location location = islandWarp.getLocation(wrapper.getHandle());\n                this.warpsByLocation.write(warpsByLocation -> warpsByLocation.remove(location));\n            }\n\n            warpCategory.getWarps().remove(islandWarp);\n\n            IslandsDatabaseBridge.removeWarp(this, islandWarp);\n\n            if (warpCategory.getWarps().isEmpty())\n                deleteCategory(warpCategory);\n        }\n\n        plugin.getMenus().refreshGlobalWarps();\n\n        if (warpCategory != null)\n            plugin.getMenus().refreshWarps(warpCategory);\n    }\n\n    @Override\n    public Map<String, IslandWarp> getIslandWarps() {\n        return Collections.unmodifiableMap(warpsByName);\n    }\n\n    @Override\n    public Rating getRating(SuperiorPlayer superiorPlayer) {\n        return ratings.getOrDefault(superiorPlayer.getUniqueId(), Rating.UNKNOWN);\n    }\n\n    @Override\n    public void setRating(SuperiorPlayer superiorPlayer, Rating rating) {\n        // Legacy support for rating can be set to UNKNOWN in order to remove rating.\n        // Nowadays, removeRating exists.\n        if (rating == Rating.UNKNOWN) {\n            removeRating(superiorPlayer);\n            return;\n        }\n\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(rating, \"rating parameter cannot be null.\");\n\n        Log.debug(Debug.SET_RATING, owner.getName(), superiorPlayer.getName(), rating);\n\n        Rating oldRating = ratings.put(superiorPlayer.getUniqueId(), rating);\n\n        if (rating == oldRating)\n            return;\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);\n\n        IslandsDatabaseBridge.saveRating(this, superiorPlayer, rating, System.currentTimeMillis());\n\n        plugin.getMenus().refreshIslandRatings(this);\n    }\n\n    @Override\n    public void removeRating(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_RATING, owner.getName(), superiorPlayer.getName());\n\n        Rating oldRating = ratings.remove(superiorPlayer.getUniqueId());\n\n        if (oldRating == null)\n            return;\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);\n\n        IslandsDatabaseBridge.removeRating(this, superiorPlayer);\n\n        plugin.getMenus().refreshIslandRatings(this);\n    }\n\n    @Override\n    public double getTotalRating() {\n        double avg = 0;\n\n        for (Rating rating : ratings.values())\n            avg += rating.getValue();\n\n        return avg == 0 ? 0 : avg / getRatingAmount();\n    }\n\n    @Override\n    public int getRatingAmount() {\n        return ratings.size();\n    }\n\n    @Override\n    public Map<UUID, Rating> getRatings() {\n        return Collections.unmodifiableMap(ratings);\n    }\n\n    @Override\n    public void removeRatings() {\n        Log.debug(Debug.REMOVE_RATINGS, owner.getName());\n\n        if (ratings.isEmpty())\n            return;\n\n        ratings.clear();\n\n        plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);\n\n        IslandsDatabaseBridge.clearRatings(this);\n\n        plugin.getMenus().refreshIslandRatings(this);\n    }\n\n    @Override\n    public boolean hasSettingsEnabled(IslandFlag settings) {\n        Preconditions.checkNotNull(settings, \"settings parameter cannot be null.\");\n        return islandFlags.getOrDefault(settings, (byte) (DEFAULT_FLAGS_CACHE.contains(settings) ? 1 : 0)) == 1;\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> getAllSettings() {\n        return Collections.unmodifiableMap(islandFlags);\n    }\n\n    @Override\n    public void enableSettings(IslandFlag settings) {\n        Preconditions.checkNotNull(settings, \"settings parameter cannot be null.\");\n\n        Log.debug(Debug.ENABLE_ISLAND_FLAG, owner.getName(), settings.getName());\n\n        Byte oldStatus = islandFlags.put(settings, (byte) 1);\n\n        if (Objects.equals(oldStatus, 1))\n            return;\n\n        boolean disableTime = false;\n        boolean disableWeather = false;\n\n        //Updating times / weather if necessary\n        switch (settings.getName()) {\n            case \"ALWAYS_DAY\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerTime(0, false);\n                });\n                disableTime = true;\n                break;\n            case \"ALWAYS_MIDDLE_DAY\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerTime(6000, false);\n                });\n                disableTime = true;\n                break;\n            case \"ALWAYS_NIGHT\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerTime(14000, false);\n                });\n                disableTime = true;\n                break;\n            case \"ALWAYS_MIDDLE_NIGHT\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerTime(18000, false);\n                });\n                disableTime = true;\n                break;\n            case \"ALWAYS_SHINY\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerWeather(WeatherType.CLEAR);\n                });\n                disableWeather = true;\n                break;\n            case \"ALWAYS_RAIN\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.setPlayerWeather(WeatherType.DOWNFALL);\n                });\n                disableWeather = true;\n                break;\n            case \"PVP\":\n                if (plugin.getSettings().isTeleportOnPvPEnable())\n                    getIslandVisitors().forEach(superiorPlayer -> {\n                        superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                        Message.ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE.send(superiorPlayer);\n                    });\n                break;\n        }\n\n        if (disableTime) {\n            if (settings != IslandFlags.ALWAYS_DAY && islandFlags.remove(IslandFlags.ALWAYS_DAY) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_DAY);\n            if (settings != IslandFlags.ALWAYS_MIDDLE_DAY && islandFlags.remove(IslandFlags.ALWAYS_MIDDLE_DAY) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_MIDDLE_DAY);\n            if (settings != IslandFlags.ALWAYS_NIGHT && islandFlags.remove(IslandFlags.ALWAYS_NIGHT) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_NIGHT);\n            if (settings != IslandFlags.ALWAYS_MIDDLE_NIGHT && islandFlags.remove(IslandFlags.ALWAYS_MIDDLE_NIGHT) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_MIDDLE_NIGHT);\n        }\n\n        if (disableWeather) {\n            if (settings != IslandFlags.ALWAYS_RAIN && islandFlags.remove(IslandFlags.ALWAYS_RAIN) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_RAIN);\n            if (settings != IslandFlags.ALWAYS_SHINY && islandFlags.remove(IslandFlags.ALWAYS_SHINY) != null)\n                IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_SHINY);\n        }\n\n        IslandsDatabaseBridge.saveIslandFlag(this, settings, 1);\n\n        plugin.getMenus().refreshSettings(this);\n    }\n\n    /*\n     *  Ratings related methods\n     */\n\n    @Override\n    public void disableSettings(IslandFlag settings) {\n        Preconditions.checkNotNull(settings, \"settings parameter cannot be null.\");\n\n        Log.debug(Debug.DISABLE_ISLAND_FLAG, owner.getName(), settings.getName());\n\n        Byte oldStatus = islandFlags.put(settings, (byte) 0);\n\n        if (Objects.equals(oldStatus, 0))\n            return;\n\n        switch (settings.getName()) {\n            case \"ALWAYS_DAY\":\n            case \"ALWAYS_MIDDLE_DAY\":\n            case \"ALWAYS_NIGHT\":\n            case \"ALWAYS_MIDDLE_NIGHT\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.resetPlayerTime();\n                });\n                break;\n            case \"ALWAYS_RAIN\":\n            case \"ALWAYS_SHINY\":\n                getAllPlayersInside().forEach(superiorPlayer -> {\n                    Player player = superiorPlayer.asPlayer();\n                    if (player != null)\n                        player.resetPlayerWeather();\n                });\n                break;\n        }\n\n        IslandsDatabaseBridge.saveIslandFlag(this, settings, 0);\n\n        plugin.getMenus().refreshSettings(this);\n    }\n\n    @Override\n    public void resetSettings() {\n        Log.debug(Debug.RESET_ISLAND_FLAGS, owner.getName());\n\n        if (islandFlags.isEmpty())\n            return;\n\n        islandFlags.clear();\n\n        Long time = null;\n        WeatherType weather = null;\n        boolean enablePvP = false;\n\n        for (String islandFlag : plugin.getSettings().getDefaultSettings()) {\n            switch (islandFlag) {\n                case \"ALWAYS_DAY\":\n                    time = 0L;\n                    break;\n                case \"ALWAYS_MIDDLE_DAY\":\n                    time = 6000L;\n                    break;\n                case \"ALWAYS_NIGHT\":\n                    time = 14000L;\n                    break;\n                case \"ALWAYS_MIDDLE_NIGHT\":\n                    time = 18000L;\n                    break;\n                case \"ALWAYS_SHINY\":\n                    weather = WeatherType.CLEAR;\n                    break;\n                case \"ALWAYS_RAIN\":\n                    weather = WeatherType.DOWNFALL;\n                    break;\n                case \"PVP\":\n                    enablePvP = true;\n                    break;\n            }\n        }\n\n        boolean teleportOnPvPEnable = plugin.getSettings().isTeleportOnPvPEnable();\n\n        for (SuperiorPlayer superiorPlayer : getAllPlayersInside()) {\n            Player player = superiorPlayer.asPlayer();\n            if (player != null) {\n                if (time == null) player.resetPlayerTime();\n                else player.setPlayerTime(time, false);\n\n                if (weather == null) player.resetPlayerWeather();\n                else player.setPlayerWeather(weather);\n\n                if (enablePvP && teleportOnPvPEnable && isVisitor(superiorPlayer, false)) {\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                    Message.ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE.send(superiorPlayer);\n                }\n            }\n        }\n\n        IslandsDatabaseBridge.clearIslandFlags(this);\n\n        plugin.getMenus().refreshSettings(this);\n    }\n\n    @Override\n    public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) {\n        setGeneratorPercentage(key, percentage, dimension, null, false);\n    }\n\n    @Override\n    public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension,\n                                          @Nullable SuperiorPlayer caller, boolean callEvent) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        Log.debug(Debug.SET_GENERATOR_PERCENTAGE, owner.getName(), key, percentage, dimension.getName(), caller, callEvent);\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.writeAndGet(cobbleGeneratorValues ->\n                cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL)));\n\n        Preconditions.checkArgument(percentage >= 0 && percentage <= 100, \"Percentage must be between 0 and 100 - got \" + percentage + \".\");\n\n        if (percentage == 0) {\n            if (callEvent && !PluginEventsFactory.callIslandRemoveGeneratorRateEvent(this, caller, key, dimension))\n                return false;\n\n            removeGeneratorAmount(key, dimension);\n        } else if (percentage == 100) {\n            KeyMap<IntValue> cobbleGeneratorValuesOriginal = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL);\n            cobbleGeneratorValuesOriginal.putAll(worldGeneratorRates);\n            worldGeneratorRates.clear();\n\n            int generatorRate = 1;\n\n            if (callEvent) {\n                PluginEvent<PluginEventArgs.IslandChangeGeneratorRate> event =\n                        PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, generatorRate);\n                if (event.isCancelled()) {\n                    // Restore the original values\n                    worldGeneratorRates.putAll(cobbleGeneratorValuesOriginal);\n                    return false;\n                }\n                generatorRate = event.getArgs().generatorRate;\n            }\n\n            setGeneratorAmount(key, generatorRate, dimension);\n        } else {\n            //Removing the key from the generator\n            removeGeneratorAmount(key, dimension);\n\n            int totalAmount = getGeneratorTotalAmount(dimension);\n            double realPercentage = percentage / 100D;\n            double amount = (realPercentage * totalAmount) / (1 - realPercentage);\n            if (amount < 1) {\n                worldGeneratorRates.entrySet().forEach(entry -> {\n                    int newAmount = entry.getValue().get() * 10;\n                    if (entry.getValue().isSynced()) {\n                        entry.setValue(IntValue.syncedFixed(newAmount));\n                    } else {\n                        entry.setValue(IntValue.fixed(newAmount));\n                    }\n                });\n                amount *= 10;\n            }\n\n            PluginEvent<PluginEventArgs.IslandChangeGeneratorRate> event =\n                    PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, (int) Math.round(amount));\n\n            if (event.isCancelled())\n                return false;\n\n            setGeneratorAmount(key, event.getArgs().generatorRate, dimension);\n        }\n\n        return true;\n    }\n\n    @Override\n    public int getGeneratorPercentage(Key key, Dimension dimension) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        int totalAmount = getGeneratorTotalAmount(dimension);\n        return totalAmount == 0 ? 0 : (getGeneratorAmount(key, dimension) * 100) / totalAmount;\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorPercentages(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        return getGeneratorAmounts(dimension).keySet().stream().collect(Collectors.toMap(key -> key,\n                key -> getGeneratorAmount(Keys.ofMaterialAndData(key), dimension)));\n    }\n\n    @Override\n    public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Preconditions.checkArgument(amount >= 0, \"amount parameter must be non-negative.\");\n\n        Log.debug(Debug.SET_GENERATOR_RATE, owner.getName(), key, amount, dimension);\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.writeAndGet(cobbleGeneratorValues ->\n                cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL)));\n\n        IntValue oldGeneratorRate = worldGeneratorRates.put(key, IntValue.fixed(amount));\n\n        if (amount == IntValue.getNonSynced(oldGeneratorRate, IslandUpgradeConstants.SYNCED_VALUE))\n            return;\n\n        IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, amount);\n    }\n\n    @Override\n    public void removeGeneratorAmount(Key key, Dimension dimension) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        Log.debug(Debug.REMOVE_GENERATOR_RATE, owner.getName(), key, dimension);\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.readAndGet(\n                cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension));\n\n        if (worldGeneratorRates == null)\n            return;\n\n        IntValue oldGeneratorRate = worldGeneratorRates.get(key);\n\n        if (oldGeneratorRate == null || oldGeneratorRate.get() <= 0)\n            return;\n\n        if (oldGeneratorRate.isSynced()) {\n            // In case the old rate was upgrade-synced, we want to keep it in DB and cache as a 0 rate.\n            IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, 0);\n            worldGeneratorRates.put(key, IntValue.fixed(0));\n        } else {\n            IslandsDatabaseBridge.removeGeneratorRate(this, dimension, key);\n            worldGeneratorRates.remove(key);\n        }\n    }\n\n    @Override\n    public int getGeneratorAmount(Key key, Dimension dimension) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.readAndGet(\n                cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension));\n\n        if (worldGeneratorRates == null)\n            return 0;\n\n        IntValue generatorRate = worldGeneratorRates.get(key);\n        return generatorRate == null ? 0 : generatorRate.get();\n    }\n\n    @Override\n    public int getGeneratorTotalAmount(Dimension dimension) {\n        int totalAmount = 0;\n        for (int amt : getGeneratorAmounts(dimension).values())\n            totalAmount += amt;\n        return totalAmount;\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorAmounts(Dimension dimension) {\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.readAndGet(\n                cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension));\n\n        if (worldGeneratorRates == null)\n            return Collections.emptyMap();\n\n        Map<String, Integer> generatorAmountsResult = new HashMap<>();\n\n        worldGeneratorRates.forEach((blockKey, valueAmount) -> {\n            int amount = valueAmount.get();\n            if (amount > 0) {\n                generatorAmountsResult.put(blockKey.toString(), amount);\n            }\n        });\n\n        return generatorAmountsResult.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(generatorAmountsResult);\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomGeneratorAmounts(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.readAndGet(\n                cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension));\n\n        if (worldGeneratorRates == null)\n            return Collections.emptyMap();\n\n        return Collections.unmodifiableMap(worldGeneratorRates.entrySet().stream()\n                .filter(entry -> !entry.getValue().isSynced())\n                .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get())));\n    }\n\n    @Override\n    public void clearGeneratorAmounts(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        Log.debug(Debug.CLEAR_GENERATOR_RATES, owner.getName(), dimension.getName());\n\n        KeyMap<IntValue> worldGeneratorRates = this.cobbleGeneratorValues.readAndGet(\n                cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension));\n        if (worldGeneratorRates != null && !worldGeneratorRates.isEmpty()) {\n            worldGeneratorRates.clear();\n            IslandsDatabaseBridge.clearGeneratorRates(this, dimension);\n        }\n    }\n\n    @Nullable\n    @Override\n    public Key generateBlock(Location location, boolean optimizeDefaultBlock) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n        Preconditions.checkArgument(isInside(location), \"location must be inside island\");\n        Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(location.getWorld());\n        return generateBlock(location, dimension, optimizeDefaultBlock);\n    }\n\n    @Override\n    public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        Preconditions.checkNotNull(location.getWorld(), \"location's world cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"environment parameter cannot be null.\");\n\n        Log.debug(Debug.GENERATE_BLOCK, owner.getName(), location, dimension.getName(), optimizeDefaultBlock);\n\n        int totalGeneratorAmounts = getGeneratorTotalAmount(dimension);\n\n        if (totalGeneratorAmounts == 0) {\n            Log.debugResult(Debug.GENERATE_BLOCK, \"Return No Generator Rates\", \"null\");\n            return null;\n        }\n\n        Map<String, Integer> generatorAmounts = getGeneratorAmounts(dimension);\n\n        GeneratorType generatorType = GeneratorType.fromDimension(dimension);\n        Key defaultBlockKey = generatorType.getDefaultBlock();\n        Key newStateKey = defaultBlockKey;\n\n        if (totalGeneratorAmounts == 1) {\n            newStateKey = Keys.ofMaterialAndData(generatorAmounts.keySet().iterator().next());\n        } else {\n            int generatedIndex = ThreadLocalRandom.current().nextInt(totalGeneratorAmounts);\n            int currentIndex = 0;\n            for (Map.Entry<String, Integer> entry : generatorAmounts.entrySet()) {\n                currentIndex += entry.getValue();\n                if (generatedIndex < currentIndex) {\n                    newStateKey = Keys.ofMaterialAndData(entry.getKey());\n                    break;\n                }\n            }\n        }\n\n        PluginEvent<PluginEventArgs.IslandGenerateBlock> event =\n                PluginEventsFactory.callIslandGenerateBlockEvent(this, location, newStateKey);\n\n        if (event.isCancelled()) {\n            Log.debugResult(Debug.GENERATE_BLOCK, \"Return Event Cancelled\", \"null\");\n            return null;\n        }\n\n        Key generatedBlock = event.getArgs().block;\n\n        if (optimizeDefaultBlock && generatedBlock.equals(defaultBlockKey)) {\n            Log.debugResult(Debug.GENERATE_BLOCK, \"Return Default Block\", generatedBlock);\n            return generatedBlock;\n        }\n\n        // If the block is a custom block, and the event was cancelled - we need to call the handleBlockPlace manually.\n        handleBlockPlace(generatedBlock, 1);\n\n        // Checking whether the plugin should set the block in the world.\n        if (event.getArgs().placeBlock) {\n            int combinedId;\n\n            try {\n                Material generateBlockType = Material.valueOf(generatedBlock.getGlobalKey());\n                byte blockData = generatedBlock.getSubKey().isEmpty() ? 0 : Byte.parseByte(generatedBlock.getSubKey());\n                combinedId = plugin.getNMSAlgorithms().getCombinedId(generateBlockType, blockData);\n            } catch (IllegalArgumentException error) {\n                Log.error(\"Invalid block for generating block: \", generatedBlock);\n                combinedId = plugin.getNMSAlgorithms().getCombinedId(\n                        ((MaterialKey) defaultBlockKey).getMaterial(), (byte) 0);\n            }\n\n            plugin.getNMSWorld().setBlock(location, combinedId);\n        }\n\n        plugin.getNMSWorld().playGeneratorSound(location);\n\n        Log.debugResult(Debug.GENERATE_BLOCK, \"Return\", generatedBlock);\n\n        return generatedBlock;\n    }\n\n    @Override\n    public boolean wasSchematicGenerated(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        return this.generatedSchematics.readAndGet(generatedSchematics -> generatedSchematics.contains(dimension));\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        setSchematicGenerate(dimension, true);\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension, boolean generated) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n\n        Log.debug(Debug.SET_SCHEMATIC, dimension.getName(), generated);\n\n        boolean updated = this.generatedSchematics.writeAndGet(generatedSchematics ->\n                generated ? generatedSchematics.add(dimension) : generatedSchematics.remove(dimension));\n\n        if (!updated)\n            return;\n\n        IslandsDatabaseBridge.saveGeneratedSchematics(this);\n    }\n\n    @Override\n    public Set<Dimension> getGeneratedSchematics() {\n        return Collections.unmodifiableSet(this.generatedSchematics.readAndGet(generatedSchematics ->\n                generatedSchematics.collect(Dimension.values())));\n    }\n\n    @Override\n    public String getSchematicName() {\n        return this.schematicName == null ? \"\" : this.schematicName;\n    }\n\n    @Override\n    public int getPosition(SortingType sortingType) {\n        return plugin.getGrid().getIslandPosition(this, sortingType);\n    }\n\n    @Override\n    public IslandChest[] getChest() {\n        return islandChests.readAndGet(islandChests -> Arrays.copyOf(islandChests, islandChests.length));\n    }\n\n    /*\n     *  Generator related methods\n     */\n\n    @Override\n    public int getChestSize() {\n        return islandChests.readAndGet(islandChests -> islandChests.length);\n    }\n\n    @Override\n    public void setChestRows(int index, int rows) {\n        IslandChest[] islandChests = this.islandChests.get();\n        int oldSize = islandChests.length;\n\n        boolean updatedIslandChests = false;\n\n        if (index >= oldSize) {\n            updatedIslandChests = true;\n            islandChests = Arrays.copyOf(islandChests, index + 1);\n            this.islandChests.set(islandChests);\n            for (int i = oldSize; i <= index; i++) {\n                (islandChests[i] = new SIslandChest(this, i)).setRows(plugin.getSettings().getIslandChests().getDefaultSize());\n            }\n        }\n\n        IslandChest islandChest = islandChests[index];\n\n        if (!updatedIslandChests && islandChest.getRows() == rows)\n            return;\n\n        islandChests[index].setRows(rows);\n\n        IslandsDatabaseBridge.markIslandChestsToBeSaved(this, islandChests[index]);\n    }\n\n    private void calcIslandWorthInternal(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) {\n        try {\n            this.beingRecalculated = true;\n            plugin.getGrid().startCalcTask();\n            runCalcIslandWorthInternal(asker, callback);\n        } catch (Throwable error) {\n            // In case of an error, we get out of the recalculate state.\n            this.beingRecalculated = false;\n            plugin.getGrid().stopCalcTask();\n            throw error;\n        }\n    }\n\n    private void runCalcIslandWorthInternal(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) {\n        Log.debug(Debug.CALCULATE_ISLAND, owner.getName(), asker);\n\n        BigDecimal oldWorth = getWorth();\n        BigDecimal oldLevel = getIslandLevel();\n\n        CompletableFuture<IslandCalculationAlgorithm.IslandCalculationResult> calculationResult;\n\n        try {\n            // Legacy support\n            // noinspection deprecation\n            calculationResult = calculationAlgorithm.calculateIsland();\n        } catch (UnsupportedOperationException ex) {\n            calculationResult = calculationAlgorithm.calculateIsland(this);\n        }\n\n        calculationResult.whenComplete((result, error) -> {\n            beingRecalculated = false;\n            boolean isLastActiveTask = plugin.getGrid().stopCalcTask();\n\n            if (error != null) {\n                if (error instanceof TimeoutException) {\n                    if (asker != null)\n                        Message.ISLAND_WORTH_TIME_OUT.send(asker);\n                } else {\n                    Log.entering(owner.getName(), asker);\n                    Log.error(error, \"An unexpected error occurred while calculating island worth:\");\n\n                    if (asker != null)\n                        Message.ISLAND_WORTH_ERROR.send(asker);\n                }\n\n                return;\n            }\n\n            clearBlockCounts();\n            result.getBlockCounts().forEach((blockKey, amount) -> handleBlockPlaceInternal(blockKey, amount, 0));\n\n            BigDecimal newIslandLevel = getIslandLevel();\n            BigDecimal newIslandWorth = getWorth();\n\n            finishCalcIsland(asker, callback, newIslandLevel, newIslandWorth);\n\n            plugin.getMenus().refreshValues(this);\n            plugin.getMenus().refreshCounts(this);\n\n            saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel, true, isLastActiveTask);\n            updateLastTime();\n        });\n    }\n\n    private boolean hasGiveInterestFailed() {\n        return this.giveInterestFailed;\n    }\n\n    private void applyEffectsNoUpgradeCheck(SuperiorPlayer superiorPlayer) {\n        Player player = superiorPlayer.asPlayer();\n        if (player != null) {\n            getPotionEffects().forEach((potionEffectType, level) -> player.addPotionEffect(\n                    new PotionEffect(potionEffectType, Integer.MAX_VALUE, level - 1), true));\n        }\n    }\n\n    private void removeEffectsNoUpgradeCheck(SuperiorPlayer superiorPlayer) {\n        Player player = superiorPlayer.asPlayer();\n        if (player != null)\n            getPotionEffects().keySet().forEach(player::removePotionEffect);\n    }\n\n    private WarpCategory loadWarpCategory(String name, int slot, @Nullable ItemStack icon) {\n        WarpCategory warpCategory = new SWarpCategory(getUniqueId(), name, slot, icon);\n        warpCategories.put(name.toLowerCase(Locale.ENGLISH), warpCategory);\n        return warpCategory;\n    }\n\n    public IslandWarp loadIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory,\n                                     boolean isPrivate, @Nullable ItemStack icon) {\n        if (warpCategory == null)\n            warpCategory = warpCategories.values().stream().findFirst().orElseGet(() -> createWarpCategory(\"Default Category\"));\n\n        IslandWarp islandWarp = new SIslandWarp(name, worldInfo, worldPosition, warpCategory, isPrivate, icon);\n\n        islandWarp.getCategory().getWarps().add(islandWarp);\n\n        String warpName = islandWarp.getName().toLowerCase(Locale.ENGLISH);\n\n        if (warpsByName.containsKey(warpName))\n            deleteWarp(warpName);\n\n        warpsByName.put(warpName, islandWarp);\n\n        this.warpsByLocation.write(warpsByLocation ->\n                warpsByLocation.put(LazyWorldLocation.of(worldInfo, worldPosition), islandWarp));\n\n        return islandWarp;\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return databaseBridge;\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        if (persistentDataContainer == null)\n            persistentDataContainer = plugin.getFactory().createPersistentDataContainer(this);\n        return persistentDataContainer;\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return persistentDataContainer == null || persistentDataContainer.isEmpty();\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        IslandsDatabaseBridge.executeFutureSaves(this, IslandsDatabaseBridge.FutureSave.PERSISTENT_DATA);\n    }\n\n    /*\n     *  Schematic methods\n     */\n\n    private void replaceVisitor(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) {\n        uniqueVisitors.write(uniqueVisitors -> {\n            Iterator<UniqueVisitor> iterator = uniqueVisitors.iterator();\n            while (iterator.hasNext()) {\n                UniqueVisitor uniqueVisitor = iterator.next();\n                if (uniqueVisitor.getSuperiorPlayer().equals(originalPlayer)) {\n                    Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Replace Visitor\");\n                    if (newPlayer == null) {\n                        iterator.remove();\n                    } else {\n                        uniqueVisitor.setSuperiorPlayer(newPlayer);\n                    }\n                }\n            }\n        });\n    }\n\n    private void replaceBannedPlayer(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) {\n        if (bannedPlayers.remove(originalPlayer)) {\n            Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Replace Banned Player\");\n            if (newPlayer != null)\n                bannedPlayers.add(newPlayer);\n        }\n    }\n\n    private void replacePermissions(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) {\n        PlayerPrivilegeNode playerPermissionNode = playerPermissions.remove(originalPlayer);\n        if (playerPermissionNode != null) {\n            Log.debugResult(Debug.REPLACE_PLAYER, \"Action\", \"Replace Permissions\");\n            if (newPlayer != null)\n                playerPermissions.put(newPlayer, playerPermissionNode);\n        }\n    }\n\n    private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldWorth, BigDecimal oldLevel) {\n        saveBlockCounts(currentTotalBlocksCount, oldWorth, oldLevel, false, true);\n    }\n\n    private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldWorth, BigDecimal oldLevel,\n                                 boolean forceBlocksCountSave, boolean sortIslands) {\n        BigDecimal newWorth = getWorth();\n        BigDecimal newLevel = getIslandLevel();\n\n        if (oldLevel.compareTo(newLevel) != 0 || oldWorth.compareTo(newWorth) != 0) {\n            registerTask(BukkitExecutor.async(() ->\n                    PluginEventsFactory.callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L));\n        }\n\n        BigInteger deltaBlockCounts = this.lastSavedBlockCounts.subtract(currentTotalBlocksCount);\n        if (deltaBlockCounts.compareTo(BigInteger.ZERO) < 0)\n            deltaBlockCounts = deltaBlockCounts.negate();\n\n        if (forceBlocksCountSave || deltaBlockCounts.compareTo(plugin.getSettings().getBlockCountsSaveThreshold()) >= 0) {\n            this.lastSavedBlockCounts = currentTotalBlocksCount;\n            IslandsDatabaseBridge.saveBlockCounts(this);\n            plugin.getMenus().refreshValues(this);\n            plugin.getMenus().refreshCounts(this);\n            if (sortIslands) {\n                plugin.getGrid().sortIslands(SortingTypes.BY_WORTH);\n                plugin.getGrid().sortIslands(SortingTypes.BY_LEVEL);\n            }\n        } else {\n            IslandsDatabaseBridge.markBlockCountsToBeSaved(this);\n        }\n    }\n\n    public void syncUpgrades(boolean overrideCustom) {\n        clearUpgrades(overrideCustom);\n\n        // We want to sync the default upgrade first, then the actual upgrades\n        syncUpgrade(DefaultUpgradeLevel.getInstance(), overrideCustom);\n\n        // Syncing all real upgrades\n        plugin.getUpgrades().getUpgrades().forEach(upgrade -> syncUpgrade((SUpgradeLevel) getUpgradeLevel(upgrade), overrideCustom));\n    }\n\n    /*\n     *  Island top methods\n     */\n\n    private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp islandWarp) {\n        try (ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n            Location location = islandWarp.getLocation(wrapper.getHandle());\n\n            if (location.getWorld() == null) {\n                Location clonedLocation = location.clone();\n                IslandWorlds.accessIslandWorldAsync(this, location, true, islandWorldResult -> {\n                    islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> {\n                        clonedLocation.setWorld(world);\n                        warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, clonedLocation);\n                    });\n                });\n            } else {\n                warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, location);\n            }\n        }\n    }\n\n    private void warpPlayerWithoutWarmupWorldLoaded(SuperiorPlayer superiorPlayer, IslandWarp islandWarp, Location location) {\n        // Warp doesn't exist anymore.\n        if (getWarp(islandWarp.getName()) == null) {\n            Message.INVALID_WARP.send(superiorPlayer, islandWarp.getName());\n            deleteWarp(islandWarp.getName());\n            return;\n        }\n\n        superiorPlayer.setTeleportTask(null);\n\n        if (!isInsideRange(location) || !WorldBlocks.isSafeBlock(location.getBlock())) {\n            Message.UNSAFE_WARP.send(superiorPlayer);\n            if (plugin.getSettings().getDeleteUnsafeWarps())\n                deleteWarp(islandWarp.getName());\n            return;\n        }\n\n        superiorPlayer.teleport(location, success -> {\n            if (success) {\n                Message.TELEPORTED_TO_WARP.send(superiorPlayer);\n                if (superiorPlayer.isShownAsOnline()) {\n                    IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT,\n                            Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName());\n                }\n            }\n        });\n    }\n\n    /*\n     *  Vault related methods\n     */\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(mission.getIslandMission(), \"mission parameter must be island-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1));\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(mission.getIslandMission(), \"mission parameter must be island-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1));\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return getAmountMissionCompleted(mission) > 0;\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        if (!mission.getIslandMission())\n            return false;\n\n        Optional<MissionData> missionDataOptional = plugin.getMissions().getMissionData(mission);\n\n        if (missionDataOptional.isPresent()) {\n            int resetAmount = missionDataOptional.get().getResetAmount();\n            return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount;\n        }\n\n        return false;\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Counter finishCount = mission.getIslandMission() ? completedMissions.get(new MissionReference(mission)) : null;\n        return finishCount == null ? 0 : finishCount.get();\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(mission.getIslandMission(), \"mission parameter must be island-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount));\n    }\n\n    private void changeAmountMissionsCompletedInternal(Mission<?> mission, boolean clearData, Function<Counter, Integer> action) {\n        String missionName = mission.getName();\n\n        MissionReference missionReference = new MissionReference(mission);\n\n        Counter finishCount = completedMissions.computeIfAbsent(missionReference, r -> new Counter(0));\n        int oldFinishCount = action.apply(finishCount);\n        int newFinishCount = finishCount.get();\n\n        Log.debug(Debug.SET_ISLAND_MISSION_COMPLETED, missionName, finishCount);\n\n        if (clearData)\n            mission.clearData(getOwner());\n\n        if (newFinishCount > 0) {\n            if (newFinishCount == oldFinishCount)\n                return;\n\n            IslandsDatabaseBridge.saveMission(this, mission, newFinishCount);\n        } else {\n            completedMissions.remove(missionReference);\n\n            if (oldFinishCount <= 0)\n                return;\n\n            IslandsDatabaseBridge.removeMission(this, mission);\n        }\n\n        plugin.getMenus().refreshMissionsCategory(mission.getMissionCategory());\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return new SequentialListBuilder<MissionReference>()\n                .filter(MissionReference::isValid)\n                .map(completedMissions.keySet(), MissionReference::getMission);\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        Map<Mission<?>, Integer> completedMissions = new LinkedHashMap<>();\n\n        this.completedMissions.forEach((mission, finishCount) -> {\n            if (mission.isValid())\n                completedMissions.put(mission.getMission(), finishCount.get());\n        });\n\n        return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions);\n    }\n\n    /*\n     *  Object related methods\n     */\n\n    @Override\n    public int hashCode() {\n        return this.uuid.hashCode();\n    }\n\n    /*\n     *  Private methods\n     */\n\n    @Override\n    public boolean equals(Object obj) {\n        return obj instanceof Island && (this == obj || this.uuid.equals(((Island) obj).getUniqueId()));\n    }\n\n    @Override\n    @SuppressWarnings(\"all\")\n    public int compareTo(Island other) {\n        if (other == null)\n            return -1;\n\n        SortingType sortingType = SortingTypes.getIslandTopSorting();\n        Comparator<Island> comparator = sortingType.getComparator();\n\n        int result = comparator.compare(this, other);\n        if (result != 0)\n            return result;\n\n        return getOwner().getName().compareTo(other.getOwner().getName());\n    }\n\n    private IslandChest[] createDefaultIslandChests() {\n        IslandChest[] islandChests = new IslandChest[plugin.getSettings().getIslandChests().getDefaultPages()];\n        for (int i = 0; i < islandChests.length; i++) {\n            if (islandChests[i] == null) {\n                islandChests[i] = new SIslandChest(this, i);\n                islandChests[i].setRows(plugin.getSettings().getIslandChests().getDefaultSize());\n            }\n        }\n        return islandChests;\n    }\n\n    private void startBankInterest() {\n        if (!BuiltinModules.BANK.getConfiguration().isBankInterestEnabled())\n            return;\n\n        int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval();\n        long currentTime = System.currentTimeMillis() / 1000;\n        long ticksToNextInterest = (bankInterestInterval - (currentTime - this.lastInterest)) * 20;\n        if (ticksToNextInterest <= 0) {\n            giveInterest(true);\n        } else {\n            resetBankInterestTask(ticksToNextInterest);\n        }\n    }\n\n    private void checkMembersDuplication() {\n        members.write(members -> {\n            Iterator<SuperiorPlayer> iterator = members.iterator();\n            while (iterator.hasNext()) {\n                SuperiorPlayer superiorPlayer = iterator.next();\n                if (superiorPlayer.equals(owner) || !this.equals(superiorPlayer.getIsland())) {\n                    iterator.remove();\n                    IslandsDatabaseBridge.removeMember(this, superiorPlayer);\n                }\n            }\n        });\n    }\n\n    private void updateOldUpgradeValues() {\n        this.blockLimits.forEach((block, limit) -> {\n            Integer defaultValue = plugin.getSettings().getDefaultValues().getBlockLimits().get(block);\n            if (defaultValue != null && (int) limit.get() == defaultValue)\n                this.blockLimits.put(block, IntValue.syncedFixed(defaultValue));\n        });\n\n        this.entityLimits.forEach((entity, limit) -> {\n            Integer defaultValue = plugin.getSettings().getDefaultValues().getEntityLimits().get(entity);\n            if (defaultValue != null && (int) limit.get() == defaultValue)\n                this.entityLimits.put(entity, IntValue.syncedFixed(defaultValue));\n        });\n\n        this.cobbleGeneratorValues.write(cobbleGeneratorValues -> {\n            for (Dimension dimension : Dimension.values()) {\n                Map<Key, Integer> defaultGenerator = plugin.getSettings().getDefaultValues().getRealGeneratorsMap().get(dimension);\n                if (defaultGenerator != null) {\n                    KeyMap<IntValue> worldGeneratorRates = cobbleGeneratorValues.get(dimension);\n\n                    if (worldGeneratorRates == null)\n                        continue;\n\n                    worldGeneratorRates.forEach((key, rate) -> {\n                        Integer defaultValue = defaultGenerator.get(key);\n                        if (defaultValue != null && (int) rate.get() == defaultValue)\n                            worldGeneratorRates.put(key, IntValue.syncedFixed(defaultValue));\n                    });\n                }\n            }\n        });\n\n        if (getIslandSize() == plugin.getSettings().getDefaultValues().getIslandSize())\n            this.islandSize.set(DefaultUpgradeLevel.getInstance().getBorderSizeUpgradeValue());\n\n        if (getWarpsLimit() == plugin.getSettings().getDefaultValues().getWarpsLimit())\n            this.warpsLimit.set(DefaultUpgradeLevel.getInstance().getWarpsLimitUpgradeValue());\n\n        if (getTeamLimit() == plugin.getSettings().getDefaultValues().getTeamLimit())\n            this.teamLimit.set(DefaultUpgradeLevel.getInstance().getTeamLimitUpgradeValue());\n\n        if (getCoopLimit() == plugin.getSettings().getDefaultValues().getCoopLimit())\n            this.coopLimit.set(DefaultUpgradeLevel.getInstance().getCoopLimitUpgradeValue());\n\n        if (getCropGrowthMultiplier() == plugin.getSettings().getDefaultValues().getCropGrowth())\n            this.cropGrowth.set(DefaultUpgradeLevel.getInstance().getCropGrowthUpgradeValue());\n\n        if (getSpawnerRatesMultiplier() == plugin.getSettings().getDefaultValues().getSpawnerRates())\n            this.spawnerRates.set(DefaultUpgradeLevel.getInstance().getSpawnerRatesUpgradeValue());\n\n        if (getMobDropsMultiplier() == plugin.getSettings().getDefaultValues().getMobDrops())\n            this.mobDrops.set(DefaultUpgradeLevel.getInstance().getMobDropsUpgradeValue());\n    }\n\n    private void clearUpgrades(boolean overrideCustom) {\n        if (overrideCustom || this.islandSize.get().isSynced()) {\n            setIslandSizeInternal(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n        }\n\n        warpsLimit.set(warpsLimit -> {\n            if (overrideCustom || warpsLimit.isSynced()) {\n                return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n            return warpsLimit;\n        });\n\n        teamLimit.set(teamLimit -> {\n            if (overrideCustom || teamLimit.isSynced()) {\n                return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n            return teamLimit;\n        });\n\n        coopLimit.set(coopLimit -> {\n            if (overrideCustom || coopLimit.isSynced()) {\n                return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n            return coopLimit;\n        });\n\n        cropGrowth.set(cropGrowth -> {\n            if (overrideCustom || cropGrowth.isSynced()) {\n                notifyCropGrowthChange(IslandUpgradeConstants.SYNCED_VALUE);\n\n                return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n\n            return cropGrowth;\n        });\n\n        spawnerRates.set(spawnerRates -> {\n            if (overrideCustom || spawnerRates.isSynced()) {\n                return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n            return spawnerRates;\n        });\n\n        mobDrops.set(mobDrops -> {\n            if (overrideCustom || mobDrops.isSynced()) {\n                return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE);\n            }\n            return mobDrops;\n        });\n\n        bankLimit.set(bankLimit -> {\n            if (overrideCustom || bankLimit.isSynced()) {\n                return Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE);\n            }\n            return bankLimit;\n        });\n\n        blockLimits.entrySet().stream()\n                .filter(entry -> overrideCustom || entry.getValue().isSynced())\n                .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)));\n\n        entityLimits.entrySet().stream()\n                .filter(entry -> overrideCustom || entry.getValue().isSynced())\n                .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)));\n\n        cobbleGeneratorValues.write(cobbleGeneratorValues -> {\n            cobbleGeneratorValues.values().forEach(cobbleGeneratorValue -> {\n                cobbleGeneratorValue.entrySet().stream()\n                        .filter(entry -> overrideCustom || entry.getValue().isSynced())\n                        .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)));\n            });\n        });\n\n        islandEffects.entrySet().stream()\n                .filter(entry -> overrideCustom || entry.getValue().isSynced())\n                .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)));\n\n        roleLimits.write(roleLimits -> {\n            Iterator<Int2ObjectMapView.Entry<IntValue>> iterator = roleLimits.entryIterator();\n            while (iterator.hasNext()) {\n                Int2ObjectMapView.Entry<IntValue> entry = iterator.next();\n                if (overrideCustom || entry.getValue().isSynced())\n                    entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE));\n            }\n        });\n\n        if (overrideCustom)\n            IslandsDatabaseBridge.clearIslandSettings(this);\n    }\n\n    private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) {\n        if (upgradeLevel.hasCropGrowth()) {\n            cropGrowth.set(cropGrowth -> {\n                if (overrideCustom || cropGrowth.isSynced()) {\n                    notifyCropGrowthChange(upgradeLevel.getCropGrowth());\n                    return upgradeLevel.getCropGrowthUpgradeValue();\n                }\n\n                return cropGrowth;\n            });\n        }\n\n        if (upgradeLevel.hasSpawnerRates()) {\n            spawnerRates.set(spawnerRates -> {\n                if (overrideCustom || spawnerRates.isSynced())\n                    return upgradeLevel.getSpawnerRatesUpgradeValue();\n                return spawnerRates;\n            });\n        }\n\n        if (upgradeLevel.hasMobDrops()) {\n            mobDrops.set(mobDrops -> {\n                if (overrideCustom || mobDrops.isSynced())\n                    return upgradeLevel.getMobDropsUpgradeValue();\n                return mobDrops;\n            });\n        }\n\n        if (upgradeLevel.hasTeamLimit()) {\n            teamLimit.set(teamLimit -> {\n                if (overrideCustom || teamLimit.isSynced())\n                    return upgradeLevel.getTeamLimitUpgradeValue();\n                return teamLimit;\n            });\n        }\n\n        if (upgradeLevel.hasWarpsLimit()) {\n            warpsLimit.set(warpsLimit -> {\n                if (overrideCustom || warpsLimit.isSynced())\n                    return upgradeLevel.getWarpsLimitUpgradeValue();\n                return warpsLimit;\n            });\n        }\n\n        if (upgradeLevel.hasCoopLimit()) {\n            coopLimit.set(coopLimit -> {\n                if (overrideCustom || coopLimit.isSynced())\n                    return upgradeLevel.getCoopLimitUpgradeValue();\n                return coopLimit;\n            });\n        }\n\n        if (upgradeLevel.hasBorderSize()) {\n            IntValue islandSize = this.islandSize.get();\n            if (overrideCustom || islandSize.isSynced())\n                setIslandSizeInternal(upgradeLevel.getBorderSizeUpgradeValue());\n        }\n\n        if (upgradeLevel.hasBankLimit()) {\n            bankLimit.set(bankLimit -> {\n                if (overrideCustom || bankLimit.isSynced())\n                    return upgradeLevel.getBankLimitUpgradeValue();\n                return bankLimit;\n            });\n        }\n\n        for (Map.Entry<Key, IntValue> entry : upgradeLevel.getBlockLimitsUpgradeValue().entrySet()) {\n            IntValue currentValue = blockLimits.getRaw(entry.getKey(), null);\n            if (currentValue == null || overrideCustom || currentValue.isSynced()) {\n                if (entry.getValue().get() < 0) {\n                    blockLimits.remove(entry.getKey());\n                } else {\n                    blockLimits.put(entry.getKey(), entry.getValue());\n                }\n            }\n        }\n\n        for (Map.Entry<Key, IntValue> entry : upgradeLevel.getEntityLimitsUpgradeValue().entrySet()) {\n            IntValue currentValue = entityLimits.getRaw(entry.getKey(), null);\n            if (currentValue == null || overrideCustom || currentValue.isSynced()) {\n                if (entry.getValue().get() < 0) {\n                    entityLimits.remove(entry.getKey());\n                } else {\n                    entityLimits.put(entry.getKey(), entry.getValue());\n                }\n            }\n        }\n\n        EnumerateMap<Dimension, Map<Key, IntValue>> upgradeGeneratorRates = upgradeLevel.getGeneratorUpgradeValue();\n        if (!upgradeGeneratorRates.isEmpty()) {\n            this.cobbleGeneratorValues.write(cobbleGeneratorValues -> {\n                for (Dimension dimension : Dimension.values()) {\n                    Map<Key, IntValue> upgradeLevelGeneratorRates = upgradeGeneratorRates.get(dimension);\n\n                    if (upgradeLevelGeneratorRates == null)\n                        continue;\n\n                    KeyMap<IntValue> worldGeneratorRates = cobbleGeneratorValues.get(dimension);\n\n                    if (worldGeneratorRates != null && !upgradeLevelGeneratorRates.isEmpty()) {\n                        KeyMap<IntValue> worldGeneratorRatesCopy = worldGeneratorRates;\n                        worldGeneratorRatesCopy.removeIf(key -> worldGeneratorRatesCopy.get(key).isSynced());\n                    }\n\n                    for (Map.Entry<Key, IntValue> entry : upgradeLevelGeneratorRates.entrySet()) {\n                        Key block = entry.getKey();\n                        IntValue rate = entry.getValue();\n\n                        IntValue currentValue = worldGeneratorRates == null ? null : worldGeneratorRates.get(block);\n                        if (currentValue == null || overrideCustom || currentValue.isSynced()) {\n                            if (rate.get() < 0) {\n                                worldGeneratorRates.remove(block);\n                            } else {\n                                if (worldGeneratorRates == null) {\n                                    worldGeneratorRates = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL);\n                                    cobbleGeneratorValues.put(dimension, worldGeneratorRates);\n                                }\n\n                                worldGeneratorRates.put(block, rate);\n                            }\n                        }\n                    }\n                }\n            });\n        }\n\n        boolean editedIslandEffects = false;\n\n        for (Map.Entry<PotionEffectType, IntValue> entry : upgradeLevel.getPotionEffectsUpgradeValue().entrySet()) {\n            IntValue currentValue = islandEffects.get(entry.getKey());\n            if (currentValue == null || overrideCustom || currentValue.isSynced()) {\n                if (entry.getValue().get() < 0) {\n                    islandEffects.remove(entry.getKey());\n                } else {\n                    islandEffects.put(entry.getKey(), entry.getValue());\n                }\n                editedIslandEffects = true;\n            }\n        }\n\n        if (editedIslandEffects) {\n            applyEffects();\n        }\n\n        roleLimits.write(roleLimits -> {\n            for (Map.Entry<PlayerRole, IntValue> entry : upgradeLevel.getRoleLimitsUpgradeValue().entrySet()) {\n                IntValue currentValue = roleLimits.get(entry.getKey().getId());\n                if (currentValue == null || overrideCustom || currentValue.isSynced()) {\n                    if (entry.getValue().get() < 0) {\n                        roleLimits.remove(entry.getKey().getId());\n                    } else {\n                        roleLimits.put(entry.getKey().getId(), entry.getValue());\n                    }\n                }\n            }\n        });\n    }\n\n    private void updateIslandChests() {\n        List<IslandChest> islandChestList = new ArrayList<>(Arrays.asList(this.islandChests.get()));\n        boolean updatedChests = false;\n\n        while (islandChestList.size() < plugin.getSettings().getIslandChests().getDefaultPages()) {\n            IslandChest newIslandChest = new SIslandChest(this, islandChestList.size());\n            newIslandChest.setRows(plugin.getSettings().getIslandChests().getDefaultSize());\n            islandChestList.add(newIslandChest);\n            updatedChests = true;\n        }\n\n        if (updatedChests) {\n            this.islandChests.set(islandChestList.toArray(new IslandChest[0]));\n        }\n    }\n\n    private void finishCalcIsland(SuperiorPlayer asker, Runnable callback, BigDecimal islandLevel, BigDecimal islandWorth) {\n        PluginEventsFactory.callIslandWorthCalculatedEvent(this, asker, islandLevel, islandWorth);\n\n        if (asker != null)\n            Message.ISLAND_WORTH_RESULT.send(asker, islandWorth, islandLevel);\n\n        if (callback != null)\n            callback.run();\n    }\n\n    private void forEachIslandMember(UUID[] ignoredMembersArray, boolean onlyOnline, Consumer<SuperiorPlayer> islandMemberConsumer) {\n        Set<UUID> ignoredMembersSet;\n        if (ignoredMembersArray.length == 0) {\n            ignoredMembersSet = Collections.emptySet();\n        } else {\n            ignoredMembersSet = new HashSet<>();\n            Collections.addAll(ignoredMembersSet, ignoredMembersArray);\n        }\n\n        forEachIslandMember(ignoredMembersSet, onlyOnline, islandMemberConsumer);\n    }\n\n    private void forEachIslandMember(Set<UUID> ignoredMembers, boolean onlyOnline, Consumer<SuperiorPlayer> islandMemberConsumer) {\n        for (SuperiorPlayer islandMember : getIslandMembers(true)) {\n            if (!ignoredMembers.contains(islandMember.getUniqueId()) && (!onlyOnline || islandMember.isOnline())) {\n                islandMemberConsumer.accept(islandMember);\n            }\n        }\n    }\n\n    private void notifyCropGrowthChange(double newCropGrowth) {\n        if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class))\n            return;\n\n        // If the world is not loaded, we can skip this\n\n\n        final int flags = IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS;\n\n        double newCropGrowthMultiplier = newCropGrowth - 1;\n\n        IslandWorlds.accessIslandWorldsAsync(this, false, result -> {\n            result.ifLeft(world -> {\n                WorldInfo worldInfo = WorldInfo.of(world);\n                List<ChunkPosition> chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags);\n                if (!chunkPositions.isEmpty())\n                    plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier);\n            });\n        });\n    }\n\n    private Location worldPositionToLocation(Dimension dimension, WorldPosition worldPosition) {\n        return IslandWorlds.setWorldToLocation(this, dimension, worldPosition);\n    }\n\n    private <R> R accessBlocksTracker(boolean rawBlocks, Function<IslandBlocksTrackerAlgorithm, R> function) {\n        if (!rawBlocks)\n            return function.apply(this.blocksTracker);\n\n        try {\n            this.blocksTracker.setLoadingDataMode(true);\n            return function.apply(this.blocksTracker);\n        } finally {\n            this.blocksTracker.setLoadingDataMode(false);\n        }\n    }\n\n    private BukkitTask registerTask(@Nullable BukkitTask bukkitTask) {\n        if (bukkitTask != null) {\n            this.activeTasks.write(activeTasks -> activeTasks.add(bukkitTask));\n        }\n        return bukkitTask;\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        DEFAULT_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values());\n        plugin.getSettings().getDefaultSettings().forEach(islandFlagName -> {\n            try {\n                DEFAULT_FLAGS_CACHE.add(IslandFlag.getByName(islandFlagName));\n            } catch (Throwable ignored) {\n            }\n        });\n    }\n\n    private static WorldPosition adjustPositionToCenterOfBlock(@Nullable WorldPosition worldPosition) {\n        if (worldPosition == null)\n            return null;\n\n        boolean changed = false;\n\n        BlockPosition blockPosition = worldPosition.toBlockPosition();\n\n        double x = worldPosition.getX();\n        double z = worldPosition.getZ();\n\n        if (worldPosition.getX() - 0.5 != blockPosition.getX()) {\n            x = blockPosition.getX() + 0.5;\n            changed = true;\n        }\n\n        if (worldPosition.getZ() - 0.5 != blockPosition.getZ()) {\n            z = blockPosition.getZ() + 0.5;\n            changed = true;\n        }\n\n        return !changed ? worldPosition :\n                SWorldPosition.of(x, worldPosition.getY(), z, worldPosition.getYaw(), worldPosition.getPitch());\n    }\n\n    public static class UniqueVisitor {\n\n        private final Pair<SuperiorPlayer, Long> pair;\n\n        private SuperiorPlayer superiorPlayer;\n        private long lastVisitTime;\n\n        public UniqueVisitor(SuperiorPlayer superiorPlayer, long lastVisitTime) {\n            this.superiorPlayer = superiorPlayer;\n            this.lastVisitTime = lastVisitTime;\n            this.pair = new Pair<>(superiorPlayer, lastVisitTime);\n        }\n\n        public SuperiorPlayer getSuperiorPlayer() {\n            return superiorPlayer;\n        }\n\n        public void setSuperiorPlayer(SuperiorPlayer superiorPlayer) {\n            this.superiorPlayer = superiorPlayer;\n            this.pair.setKey(superiorPlayer);\n        }\n\n        public long getLastVisitTime() {\n            return lastVisitTime;\n        }\n\n        public void setLastVisitTime(long lastVisitTime) {\n            this.lastVisitTime = lastVisitTime;\n            this.pair.setValue(lastVisitTime);\n        }\n\n        public Pair<SuperiorPlayer, Long> toPair() {\n            return this.pair;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(superiorPlayer, lastVisitTime);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n            UniqueVisitor that = (UniqueVisitor) o;\n            return lastVisitTime == that.lastVisitTime && superiorPlayer.equals(that.superiorPlayer);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/SIslandChest.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Arrays;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class SIslandChest implements IslandChest {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private final AtomicBoolean updateFlag = new AtomicBoolean(false);\n    private final Island island;\n    private final int index;\n    private Inventory inventory = Bukkit.createInventory(this, 9, plugin.getSettings().getIslandChests().getChestTitle());\n    private int contentsUpdateCounter = 0;\n\n    public SIslandChest(Island island, int index) {\n        this.island = island;\n        this.index = index;\n    }\n\n    public static SIslandChest createChest(Island island, int index, ItemStack[] contents) {\n        SIslandChest islandChest = new SIslandChest(island, index);\n        islandChest.inventory = Bukkit.createInventory(islandChest, contents.length, plugin.getSettings().getIslandChests().getChestTitle());\n        islandChest.inventory.setContents(contents);\n        return islandChest;\n    }\n\n    @Override\n    public Island getIsland() {\n        return island;\n    }\n\n    @Override\n    public int getIndex() {\n        return index;\n    }\n\n    @Override\n    public int getRows() {\n        return inventory.getSize() / 9;\n    }\n\n    @Override\n    public void setRows(int rows) {\n        BukkitExecutor.ensureMain(() -> {\n            try {\n                updateFlag.set(true);\n                ItemStack[] oldContents = inventory.getContents();\n                Inventory oldInventory = inventory;\n                inventory = Bukkit.createInventory(this, 9 * rows, plugin.getSettings().getIslandChests().getChestTitle());\n                inventory.setContents(Arrays.copyOf(oldContents, 9 * rows));\n                inventory.getViewers().forEach(humanEntity -> {\n                    if (humanEntity.getOpenInventory().getTopInventory().equals(oldInventory))\n                        humanEntity.openInventory(inventory);\n                });\n            } finally {\n                updateFlag.set(false);\n            }\n        });\n    }\n\n    @Override\n    public ItemStack[] getContents() {\n        return inventory.getContents();\n    }\n\n    @Override\n    public void openChest(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        superiorPlayer.runIfOnline(player -> player.openInventory(getInventory()));\n    }\n\n    @Override\n    public Inventory getInventory() {\n        return inventory;\n    }\n\n    public boolean isUpdating() {\n        return updateFlag.get();\n    }\n\n    public void updateContents() {\n        if (++contentsUpdateCounter >= 50) {\n            contentsUpdateCounter = 0;\n            IslandsDatabaseBridge.saveIslandChest(island, this);\n        } else {\n            IslandsDatabaseBridge.markIslandChestsToBeSaved(island, this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java",
    "content": "package com.bgsoftware.superiorskyblock.island;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.annotations.Size;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.island.BlockChangeResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PermissionNode;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandArea;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.WorldInfoImpl;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl;\nimport com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.island.privilege.PrivilegeNodeAbstract;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.island.top.SortingComparators;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.bgsoftware.superiorskyblock.player.SSuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl;\nimport com.bgsoftware.superiorskyblock.world.Dimensions;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.command.ConsoleCommandSender;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.PriorityQueue;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic class SpawnIsland implements Island {\n\n    private static final UUID spawnUUID = new UUID(0, 0);\n    private static final LazyReference<SSuperiorPlayer> ownerPlayer = new LazyReference<SSuperiorPlayer>() {\n        @Override\n        protected SSuperiorPlayer create() {\n            return new SSuperiorPlayer((SuperiorPlayerBuilderImpl) SuperiorPlayer.newBuilder().setUniqueId(spawnUUID));\n        }\n    };\n    private static final IslandChest[] EMPTY_ISLAND_CHESTS = new IslandChest[0];\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static EnumerateSet<IslandFlag> DEFAULT_SPAWN_FLAGS_CACHE;\n    private static EnumerateSet<IslandPrivilege> DEFAULT_SPAWN_PRIVILEGES_CACHE;\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SpawnIsland::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        DEFAULT_SPAWN_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values());\n        plugin.getSettings().getSpawn().getSettings().forEach(flagName -> {\n            try {\n                DEFAULT_SPAWN_FLAGS_CACHE.add(IslandFlag.getByName(flagName));\n            } catch (Throwable ignored) {\n            }\n        });\n\n        DEFAULT_SPAWN_PRIVILEGES_CACHE = new EnumerateSet<>(IslandPrivilege.values());\n        plugin.getSettings().getSpawn().getPermissions().forEach(privilegeName -> {\n            try {\n                DEFAULT_SPAWN_PRIVILEGES_CACHE.add(IslandPrivilege.getByName(privilegeName));\n            } catch (Throwable ignored) {\n            }\n        });\n    }\n\n    private final PriorityQueue<SuperiorPlayer> playersInside = new PriorityQueue<>(SortingComparators.PLAYER_NAMES_COMPARATOR);\n    private final DirtyChunksContainer dirtyChunksContainer;\n    private final LazyReference<IslandCache> islandCache = new LazyReference<IslandCache>() {\n        @Override\n        protected IslandCache create() {\n            return new IslandCacheImpl(SpawnIsland.this);\n        }\n    };\n\n    private final WorldPosition center;\n    private final World spawnWorld;\n    private final WorldInfo spawnWorldInfo;\n    private final int islandSize;\n    private final IslandArea islandArea = new IslandArea();\n\n    private Biome biome = Biome.PLAINS;\n\n\n    public SpawnIsland() throws ManagerLoadException {\n        String spawnLocation = plugin.getSettings().getSpawn().getLocation();\n        Location centerLocation = Serializers.LOCATION_SPACED_CENTERED_SERIALIZER.deserialize(spawnLocation);\n        if (centerLocation == null) {\n            throw new ManagerLoadException(\"The spawn location could not be parsed\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        String worldName = spawnLocation.split(\", \")[0];\n\n        if (centerLocation.getWorld() == null)\n            plugin.getProviders().runWorldsListeners(worldName);\n\n        this.spawnWorld = centerLocation.getWorld();\n\n        if (this.spawnWorld == null)\n            throw new ManagerLoadException(\"The spawn location is in invalid world.\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        this.islandSize = plugin.getSettings().getSpawn().getSize();\n\n        this.center = SWorldPosition.of(centerLocation);\n        this.islandArea.update(this.center.toBlockPosition(), this.islandSize);\n        this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment()));\n\n        this.dirtyChunksContainer = new DirtyChunksContainer(this);\n\n        BukkitExecutor.sync(() -> biome = getCenter(null /* unused */).getBlock().getBiome());\n    }\n\n    @Override\n    public SuperiorPlayer getOwner() {\n        return ownerPlayer.get();\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return spawnUUID;\n    }\n\n    @Override\n    public long getCreationTime() {\n        return -1;\n    }\n\n    @Override\n    public String getCreationTimeDate() {\n        return \"\";\n    }\n\n    @Override\n    public void updateDatesFormatter() {\n        // Do nothing.\n    }\n\n    @Override\n    public IslandCache getCache() {\n        return this.islandCache.get();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(boolean includeOwner) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers(PlayerRole... playerRoles) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getBannedPlayers() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors() {\n        return getIslandVisitors(true);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandVisitors(boolean vanishPlayers) {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayersInside() {\n        return new SequentialListBuilder<SuperiorPlayer>().build(playersInside);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getUniqueVisitors() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<Pair<SuperiorPlayer, Long>> getUniqueVisitorsWithTimes() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public void inviteMember(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void revokeInvite(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isInvited(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public List<SuperiorPlayer> getInvitedPlayers() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void kickMember(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isMember(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void banMember(SuperiorPlayer superiorPlayer, SuperiorPlayer whom) {\n        // Do nothing.\n    }\n\n    @Override\n    public void unbanMember(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isBanned(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public void addCoop(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeCoop(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isCoop(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public List<SuperiorPlayer> getCoopPlayers() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return 0;\n    }\n\n    @Override\n    public void setCoopLimit(int coopLimit) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) {\n        if (inside)\n            playersInside.add(superiorPlayer);\n        else\n            playersInside.remove(superiorPlayer);\n    }\n\n    @Override\n    public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatus) {\n        return true;\n    }\n\n    @Override\n    public Location getCenter(Dimension unused) {\n        return this.center.toLocation(this.spawnWorld);\n    }\n\n    @Override\n    public BlockPosition getCenterPosition() {\n        return this.center.toBlockPosition();\n    }\n\n    @Override\n    public CompletableFuture<World> accessIslandWorld(Dimension unused) {\n        return CompletableFuture.completedFuture(this.spawnWorld);\n    }\n\n    public World getSpawnWorld() {\n        return spawnWorld;\n    }\n\n    public WorldInfo getSpawnWorldInfo() {\n        return spawnWorldInfo;\n    }\n\n    @Override\n    public Location getIslandHome(Dimension unused) {\n        return getCenter(null /*unused*/);\n    }\n\n    @Override\n    public WorldPosition getIslandHomePosition(Dimension unused) {\n        return getCenterPosition().toWorldPosition();\n    }\n\n    @Override\n    public Map<Dimension, Location> getIslandHomesAsDimensions() {\n        return Collections.singletonMap(\n                plugin.getSettings().getWorlds().getDefaultWorldDimension(),\n                getIslandHome(null /*unused*/));\n    }\n\n    @Override\n    @Deprecated\n    public Map<Dimension, WorldPosition> getIslandHomes() {\n        return Collections.singletonMap(\n                plugin.getSettings().getWorlds().getDefaultWorldDimension(),\n                getIslandHomePosition(null /*unused*/));\n    }\n\n    @Override\n    public void setIslandHome(Location homeLocation) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setIslandHome(Dimension dimension, Location homeLocation) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setIslandHome(Dimension dimension, WorldPosition homePosition) {\n        // Do nothing.\n    }\n\n    @Override\n    public Location getVisitorsLocation(Dimension unused) {\n        return this.getIslandHome(null /*unused*/);\n    }\n\n    @Override\n    public WorldPosition getVisitorsPosition(Dimension unused) {\n        return getIslandHomePosition(null /*unused*/);\n    }\n\n    @Override\n    public void setVisitorsLocation(Location visitorsLocation) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) {\n        // Do nothing.\n    }\n\n    @Override\n    public Location getMinimum() {\n        return this.getMinimumPosition().toWorldPosition().toLocation(this.spawnWorld);\n    }\n\n    @Override\n    public BlockPosition getMinimumPosition() {\n        return getCenterPosition().offset(-this.islandSize, 0, -this.islandSize);\n    }\n\n    @Override\n    public Location getMinimumProtected() {\n        return this.getMinimum();\n    }\n\n    @Override\n    public BlockPosition getMinimumProtectedPosition() {\n        return this.getMinimumPosition();\n    }\n\n    @Override\n    public Location getMaximum() {\n        return this.getMaximumPosition().toWorldPosition().toLocation(this.spawnWorld);\n    }\n\n    @Override\n    public BlockPosition getMaximumPosition() {\n        return getCenterPosition().offset(this.islandSize, 0, this.islandSize);\n    }\n\n    @Override\n    public Location getMaximumProtected() {\n        return this.getMaximum();\n    }\n\n    @Override\n    public BlockPosition getMaximumProtectedPosition() {\n        return this.getMaximumPosition();\n    }\n\n    @Override\n    public List<Chunk> getAllChunks() {\n        return getAllChunks(0);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(@IslandChunkFlags int flags) {\n        return getAllChunks(plugin.getSettings().getWorlds().getDefaultWorldDimension(), flags);\n    }\n\n    @Override\n    @Deprecated\n    public List<Chunk> getAllChunks(Dimension unused) {\n        return getAllChunks((Dimension) null /*unused*/, 0);\n    }\n\n    @Override\n    public List<Chunk> getAllChunks(Dimension unused, @IslandChunkFlags int flags) {\n        boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0;\n        boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0;\n\n        Location min = onlyProtected ? getMinimumProtected() : getMinimum();\n        Location max = onlyProtected ? getMaximumProtected() : getMaximum();\n        Chunk minChunk = min.getChunk();\n        Chunk maxChunk = max.getChunk();\n\n        List<Chunk> chunks = new LinkedList<>();\n\n        for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) {\n            for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) {\n                boolean addChunk;\n                try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, x, z)) {\n                    addChunk = !noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition);\n                }\n                if (addChunk)\n                    chunks.add(minChunk.getWorld().getChunkAt(x, z));\n            }\n        }\n\n\n        return Collections.unmodifiableList(chunks);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks() {\n        return getLoadedChunks(0);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(@IslandChunkFlags int flags) {\n        return getLoadedChunks(plugin.getSettings().getWorlds().getDefaultWorldDimension(), flags);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension unused) {\n        return getLoadedChunks((Dimension) null /*unused*/, 0);\n    }\n\n    @Override\n    public List<Chunk> getLoadedChunks(Dimension unused, @IslandChunkFlags int flags) {\n        boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0;\n        boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0;\n\n        Location min = onlyProtected ? getMinimumProtected() : getMinimum();\n        Location max = onlyProtected ? getMaximumProtected() : getMaximum();\n\n        List<Chunk> chunks = new LinkedList<>();\n\n        for (int chunkX = min.getBlockX() >> 4; chunkX <= max.getBlockX() >> 4; chunkX++) {\n            for (int chunkZ = min.getBlockZ() >> 4; chunkZ <= max.getBlockZ() >> 4; chunkZ++) {\n                boolean addChunk;\n                try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n                    addChunk = this.spawnWorld.isChunkLoaded(chunkX, chunkZ) &&\n                            (!noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition));\n                }\n                if (addChunk)\n                    chunks.add(this.spawnWorld.getChunkAt(chunkX, chunkZ));\n            }\n        }\n\n        return Collections.unmodifiableList(chunks);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension unused) {\n        return getAllChunksAsync((Dimension) null /*unused*/, 0);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension unused, @IslandChunkFlags int flags) {\n        return getAllChunksAsync((Dimension) null /*unused*/, flags, null);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension unused,\n                                                            @Nullable Consumer<Chunk> onChunkLoad) {\n        return getAllChunksAsync((Dimension) null /*unused*/, 0, onChunkLoad);\n    }\n\n    @Override\n    public List<CompletableFuture<Chunk>> getAllChunksAsync(Dimension unused,\n                                                            @IslandChunkFlags int flags,\n                                                            @Nullable Consumer<Chunk> onChunkLoad) {\n        return IslandUtils.getAllChunksAsync(this, spawnWorldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad);\n    }\n\n    @Override\n    public void resetChunks() {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(@Nullable Runnable onFinish) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @Nullable Runnable onFinish) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isInside(Location location) {\n        return isInside(location, 0D);\n    }\n\n    @Override\n    public boolean isInside(Location location, int extraRadius) {\n        return isInside(location, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Location location, double extraRadius) {\n        World bukkitWorld = location.getWorld();\n        if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld))\n            return false;\n\n        return this.islandArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition) {\n        return isInside(blockPosition, 0D);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, int extraRadius) {\n        return isInside(blockPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(BlockPosition blockPosition, double extraRadius) {\n        return this.islandArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition) {\n        return isInside(worldPosition, 0D);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, int extraRadius) {\n        return isInside(worldPosition, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldPosition worldPosition, double extraRadius) {\n        return this.islandArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius);\n    }\n\n    @Override\n    public boolean isInside(Chunk chunk) {\n        return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ());\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ) {\n        return isInside(world, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(world, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) {\n        return world.equals(this.spawnWorld) && isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return isInside(worldInfo, chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        return this.spawnWorldInfo.getName().equals(worldInfo.getName()) && isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ) {\n        return isInside(chunkX, chunkZ, 0D);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, int extraRadius) {\n        return isInside(chunkX, chunkZ, (double) extraRadius);\n    }\n\n    @Override\n    public boolean isInside(int chunkX, int chunkZ, double extraRadius) {\n        return this.islandArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location) {\n        return isInside(location);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, int extraRadius) {\n        return isInside(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Location location, double extraRadius) {\n        return isInside(location, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition) {\n        return isInside(blockPosition);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) {\n        return isInside(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) {\n        return isInside(blockPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition) {\n        return isInside(worldPosition);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) {\n        return isInside(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) {\n        return isInside(worldPosition, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(Chunk chunk) {\n        return isInside(chunk);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ) {\n        return isInside(world, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) {\n        return isInside(world, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        return isInside(worldInfo, chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) {\n        return isInside(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) {\n        return isInside(worldInfo, chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ) {\n        return isInside(chunkX, chunkZ);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) {\n        return isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) {\n        return isInside(chunkX, chunkZ, extraRadius);\n    }\n\n    @Override\n    public boolean isNormalEnabled() {\n        return false;\n    }\n\n    @Override\n    public void setNormalEnabled(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isNetherEnabled() {\n        return false;\n    }\n\n    @Override\n    public void setNetherEnabled(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isEndEnabled() {\n        return false;\n    }\n\n    @Override\n    public void setEndEnabled(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isDimensionEnabled(Dimension dimension) {\n        return false;\n    }\n\n    @Override\n    public void setDimensionEnabled(Dimension dimension, boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public Collection<Dimension> getUnlockedWorlds() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) {\n        return sender instanceof ConsoleCommandSender || hasPermission(plugin.getPlayers().getSuperiorPlayer(sender), islandPrivilege);\n    }\n\n    @Override\n    public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) {\n        boolean checkForProtection = islandPrivilege != IslandPrivileges.FLY;\n        return (checkForProtection && !plugin.getSettings().getSpawn().isProtected()) ||\n                superiorPlayer.hasBypassModeEnabled() ||\n                superiorPlayer.hasBypassPermission(islandPrivilege) ||\n                superiorPlayer.hasPermissionWithoutOP(\"superior.admin.bypass.*\") ||\n                hasPermission(SPlayerRole.guestRole(), islandPrivilege);\n    }\n\n    @Override\n    public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        return getRequiredPlayerRole(islandPrivilege).getWeight() <= playerRole.getWeight();\n    }\n\n    @Override\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetPermissions() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetPermissions(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) {\n        return PlayerPrivilegeNode.EmptyPlayerPermissionNode.INSTANCE;\n    }\n\n    @Override\n    public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) {\n        return DEFAULT_SPAWN_PRIVILEGES_CACHE.contains(islandPrivilege) ?\n                SPlayerRole.guestRole() : SPlayerRole.lastRole();\n    }\n\n    @Override\n    public Map<SuperiorPlayer, PermissionNode> getPlayerPermissions() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> getRolePermissions() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public boolean isSpawn() {\n        return true;\n    }\n\n    @Override\n    public String getName() {\n        return \"\";\n    }\n\n    @Override\n    public void setName(String islandName) {\n        // Do nothing.\n    }\n\n    @Override\n    public String getRawName() {\n        return \"\";\n    }\n\n    @Override\n    public String getStrippedName() {\n        return \"\";\n    }\n\n    @Override\n    public String getFormattedName() {\n        return \"\";\n    }\n\n    @Override\n    public String getDescription() {\n        return \"\";\n    }\n\n    @Override\n    public void setDescription(String description) {\n        // Do nothing.\n    }\n\n    @Override\n    public void disbandIsland() {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean transferIsland(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public void replacePlayers(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void calcIslandWorth(SuperiorPlayer asker) {\n        // Do nothing.\n    }\n\n    @Override\n    public void calcIslandWorth(SuperiorPlayer asker, Runnable callback) {\n        // Do nothing.\n    }\n\n    @Override\n    public IslandCalculationAlgorithm getCalculationAlgorithm() {\n        return SpawnIslandCalculationAlgorithm.getInstance();\n    }\n\n    @Override\n    public void updateBorder() {\n        getAllPlayersInside().forEach(superiorPlayer -> superiorPlayer.updateWorldBorder(this));\n    }\n\n    @Override\n    public void updateIslandFly(SuperiorPlayer superiorPlayer) {\n        IslandUtils.updateIslandFly(this, superiorPlayer);\n    }\n\n    @Override\n    public int getIslandSize() {\n        return islandSize;\n    }\n\n    @Override\n    public void setIslandSize(int islandSize) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getIslandSizeRaw() {\n        return islandSize;\n    }\n\n    @Override\n    public String getDiscord() {\n        return \"\";\n    }\n\n    @Override\n    public void setDiscord(String discord) {\n        // Do nothing.\n    }\n\n    @Override\n    public String getPaypal() {\n        return \"\";\n    }\n\n    @Override\n    public void setPaypal(String paypal) {\n        // Do nothing.\n    }\n\n    @Override\n    public Biome getBiome() {\n        return biome;\n    }\n\n    @Override\n    public void setBiome(Biome biome) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setBiome(Biome biome, boolean updateBlocks) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isLocked() {\n        return false;\n    }\n\n    @Override\n    public void setLocked(boolean locked) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isIgnored() {\n        return false;\n    }\n\n    @Override\n    public void setIgnored(boolean ignored) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(String message) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(String message, UUID... ignoredMembers) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, Object... args) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendMessage(IMessageComponent messageComponent, List<UUID> ignoredMembers, Object... args) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut) {\n        // Do nothing.\n    }\n\n    @Override\n    public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) {\n        // Do nothing.\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers) {\n        // Do nothing.\n    }\n\n    @Override\n    public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isBeingRecalculated() {\n        return false;\n    }\n\n    @Override\n    public void updateLastTime() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setCurrentlyActive() {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isCurrentlyActive() {\n        return true;\n    }\n\n    @Override\n    public void setCurrentlyActive(boolean active) {\n        // Do nothing.\n    }\n\n    @Override\n    public long getLastTimeUpdate() {\n        return -1;\n    }\n\n    @Override\n    public void setLastTimeUpdate(long lastTimeUpdate) {\n        // Do nothing.\n    }\n\n    @Override\n    public IslandBank getIslandBank() {\n        return null;\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE;\n    }\n\n    @Override\n    public void setBankLimit(BigDecimal bankLimit) {\n        // Do nothing.\n    }\n\n    @Override\n    public BigDecimal getBankLimitRaw() {\n        return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE;\n    }\n\n    @Override\n    public boolean giveInterest(boolean checkOnlineOwner) {\n        return false;\n    }\n\n    @Override\n    public long getLastInterestTime() {\n        return -1;\n    }\n\n    @Override\n    public void setLastInterestTime(long lastInterest) {\n        // Do nothing.\n    }\n\n    @Override\n    public long getNextInterest() {\n        return -1;\n    }\n\n    @Override\n    public void handleBlockPlace(Block block) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block) {\n        return BlockChangeResult.SUCCESS;\n    }\n\n    @Override\n    public void handleBlockPlace(Key key) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, int flags) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Block block, @Size int amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, @Size int amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, BigInteger amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockPlace(Key key, BigInteger amount, boolean save, boolean updateLastTimeStatus) {\n        // Do nothing.\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks) {\n        return KeyMaps.createEmptyMap();\n    }\n\n    @Override\n    public void handleBlocksPlace(Map<Key, Integer> blocks, int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksPlaceWithResult(Map<Key, Integer> blocks, int flags) {\n        return KeyMaps.createEmptyMap();\n    }\n\n    @Override\n    public void handleBlockBreak(Block block) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockBreak(Key key) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, int flags) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, int flags) {\n        return BlockChangeResult.SPAWN_ISLAND;\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Block block, @Size int amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, @Size int amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public void handleBlockBreak(Key key, BigInteger amount, boolean save) {\n        // Do nothing.\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks) {\n        return KeyMaps.createEmptyMap();\n    }\n\n    @Override\n    public void handleBlocksBreak(Map<Key, Integer> blocks, @IslandBlockFlags int flags) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<Key, BlockChangeResult> handleBlocksBreakWithResult(Map<Key, Integer> blocks, int flags) {\n        return KeyMaps.createEmptyMap();\n    }\n\n    @Override\n    public boolean isChunkDirty(World world, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(world, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            return this.dirtyChunksContainer.isMarkedDirty(chunkPosition);\n        }\n    }\n\n    @Override\n    public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null.\");\n        Preconditions.checkArgument(this.spawnWorldInfo.getName().equals(worldName) && isInside(chunkX, chunkZ),\n                \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            return this.dirtyChunksContainer.isMarkedDirty(chunkPosition);\n        }\n    }\n\n    @Override\n    public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            return this.dirtyChunksContainer.isMarkedDirty(chunkPosition);\n        }\n    }\n\n    @Override\n    public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(world, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markDirty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markDirty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(world, \"world parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(world, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markEmpty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), \"Chunk must be within the island boundaries.\");\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) {\n            this.dirtyChunksContainer.markEmpty(chunkPosition, save);\n        }\n    }\n\n    @Override\n    public BigInteger getBlockCountAsBigInteger(Key key) {\n        return BigInteger.ZERO;\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCountsAsBigInteger() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public BigInteger getExactBlockCountAsBigInteger(Key key) {\n        return BigInteger.ZERO;\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        // Do nothing.\n    }\n\n    @Override\n    public IslandBlocksTrackerAlgorithm getBlocksTracker() {\n        return SpawnIslandBlocksTrackerAlgorithm.getInstance();\n    }\n\n    @Override\n    public BigDecimal getWorth() {\n        return BigDecimal.ZERO;\n    }\n\n    @Override\n    public BigDecimal getRawWorth() {\n        return BigDecimal.ZERO;\n    }\n\n    @Override\n    public BigDecimal getBonusWorth() {\n        return BigDecimal.ZERO;\n    }\n\n    @Override\n    public void setBonusWorth(BigDecimal bonusWorth) {\n        // Do nothing.\n    }\n\n    @Override\n    public BigDecimal getBonusLevel() {\n        return BigDecimal.ZERO;\n    }\n\n    @Override\n    public void setBonusLevel(BigDecimal bonusLevel) {\n        // Do nothing.\n    }\n\n    @Override\n    public BigDecimal getIslandLevel() {\n        return getRawLevel();\n    }\n\n    @Override\n    public BigDecimal getRawLevel() {\n        return BigDecimal.ZERO;\n    }\n\n    @Override\n    public UpgradeLevel getUpgradeLevel(Upgrade upgrade) {\n        return upgrade.getUpgradeLevel(1);\n    }\n\n    @Override\n    public void setUpgradeLevel(Upgrade upgrade, int level) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<String, Integer> getUpgrades() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void syncUpgrades() {\n        // Do nothing.\n    }\n\n    @Override\n    public void updateUpgrades() {\n        // Do nothing.\n    }\n\n    @Override\n    public long getLastTimeUpgrade() {\n        return -1;\n    }\n\n    @Override\n    public boolean hasActiveUpgradeCooldown() {\n        return false;\n    }\n\n    @Override\n    public double getCropGrowthMultiplier() {\n        return 1;\n    }\n\n    @Override\n    public void setCropGrowthMultiplier(double cropGrowth) {\n        // Do nothing.\n    }\n\n    @Override\n    public double getCropGrowthRaw() {\n        return 1;\n    }\n\n    @Override\n    public double getSpawnerRatesMultiplier() {\n        return 1;\n    }\n\n    @Override\n    public void setSpawnerRatesMultiplier(double spawnerRates) {\n        // Do nothing.\n    }\n\n    @Override\n    public double getSpawnerRatesRaw() {\n        return 1;\n    }\n\n    @Override\n    public double getMobDropsMultiplier() {\n        return 1;\n    }\n\n    @Override\n    public void setMobDropsMultiplier(double mobDrops) {\n        // Do nothing.\n    }\n\n    @Override\n    public double getMobDropsRaw() {\n        return 1;\n    }\n\n    @Override\n    public int getBlockLimit(Key key) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public int getExactBlockLimit(Key key) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public Key getBlockLimitKey(Key key) {\n        return key;\n    }\n\n    @Override\n    public Map<Key, Integer> getBlocksLimits() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomBlocksLimits() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void clearBlockLimits() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setBlockLimit(Key key, int limit) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeBlockLimit(Key key) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key) {\n        return false;\n    }\n\n    @Override\n    public boolean hasReachedBlockLimit(Key key, @Size int amount) {\n        return false;\n    }\n\n    @Override\n    public int getEntityLimit(EntityType entityType) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public int getEntityLimit(Key key) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesLimitsAsKeys() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomEntitiesLimits() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void clearEntitiesLimits() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setEntityLimit(EntityType entityType, int limit) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setEntityLimit(Key key, int limit) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeEntityLimit(Key key) {\n        // Do nothing.\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType) {\n        return hasReachedEntityLimit(entityType, 1);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key) {\n        return hasReachedEntityLimit(key, 1);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(EntityType entityType, @Size int amount) {\n        return CompletableFuture.completedFuture(false);\n    }\n\n    @Override\n    public CompletableFuture<Boolean> hasReachedEntityLimit(Key key, @Size int amount) {\n        return CompletableFuture.completedFuture(false);\n    }\n\n    @Override\n    public IslandEntitiesTrackerAlgorithm getEntitiesTracker() {\n        return SpawnIslandEntitiesTrackerAlgorithm.getInstance();\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public void setTeamLimit(int teamLimit) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getTeamLimitRaw() {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public void setWarpsLimit(int warpsLimit) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getWarpsLimitRaw() {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public void setPotionEffect(PotionEffectType type, int level) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removePotionEffect(PotionEffectType type) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getPotionEffectLevel(PotionEffectType type) {\n        return 0;\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getPotionEffects() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getCustomPotionEffects() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void applyEffects(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void applyEffects() {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeEffects(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeEffects() {\n        // Do nothing.\n    }\n\n    @Override\n    public void clearEffects() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setRoleLimit(PlayerRole playerRole, int limit) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeRoleLimit(PlayerRole playerRole) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getRoleLimit(PlayerRole playerRole) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public int getRoleLimitRaw(PlayerRole playerRole) {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getRoleLimits() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getCustomRoleLimits() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public WarpCategory createWarpCategory(String name) {\n        return null;\n    }\n\n    @Override\n    public WarpCategory getWarpCategory(String name) {\n        return null;\n    }\n\n    @Override\n    public WarpCategory getWarpCategory(int slot) {\n        return null;\n    }\n\n    @Override\n    public void renameCategory(WarpCategory warpCategory, String newName) {\n        // Do nothing.\n    }\n\n    @Override\n    public void deleteCategory(WarpCategory warpCategory) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<String, WarpCategory> getWarpCategories() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public IslandWarp createWarp(String name, Location location, WarpCategory warpCategory) {\n        return null;\n    }\n\n    @Override\n    public IslandWarp createWarp(String s, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory) {\n        return null;\n    }\n\n    @Override\n    public void renameWarp(IslandWarp islandWarp, String newName) {\n        // Do nothing.\n    }\n\n    @Override\n    public IslandWarp getWarp(Location location) {\n        return null;\n    }\n\n    @Override\n    public IslandWarp getWarp(String name) {\n        return null;\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) {\n        // Do nothing.\n    }\n\n    @Override\n    public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) {\n        // Do nothing.\n    }\n\n    @Override\n    public void deleteWarp(SuperiorPlayer superiorPlayer, Location location) {\n        // Do nothing.\n    }\n\n    @Override\n    public void deleteWarp(String name) {\n        // Do nothing.\n    }\n\n    @Override\n    public Map<String, IslandWarp> getIslandWarps() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Rating getRating(SuperiorPlayer superiorPlayer) {\n        return Rating.UNKNOWN;\n    }\n\n    @Override\n    public void setRating(SuperiorPlayer superiorPlayer, Rating rating) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeRating(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public double getTotalRating() {\n        return 0;\n    }\n\n    @Override\n    public int getRatingAmount() {\n        return 0;\n    }\n\n    @Override\n    public Map<UUID, Rating> getRatings() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void removeRatings() {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasSettingsEnabled(IslandFlag islandFlag) {\n        return DEFAULT_SPAWN_FLAGS_CACHE.contains(islandFlag);\n    }\n\n    @Override\n    public Map<IslandFlag, Byte> getAllSettings() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void enableSettings(IslandFlag islandFlag) {\n        // Do nothing.\n    }\n\n    @Override\n    public void disableSettings(IslandFlag islandFlag) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetSettings() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension,\n                                          @Nullable SuperiorPlayer caller, boolean callEvent) {\n        return true;\n    }\n\n    @Override\n    public int getGeneratorPercentage(Key key, Dimension dimension) {\n        return 0;\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorPercentages(Dimension dimension) {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeGeneratorAmount(Key key, Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getGeneratorAmount(Key key, Dimension dimension) {\n        return 0;\n    }\n\n    @Override\n    public int getGeneratorTotalAmount(Dimension dimension) {\n        return 0;\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorAmounts(Dimension dimension) {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public Map<Key, Integer> getCustomGeneratorAmounts(Dimension dimension) {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void clearGeneratorAmounts(Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Nullable\n    @Override\n    public Key generateBlock(Location location, boolean optimizeDefaultBlock) {\n        return null;\n    }\n\n    @Override\n    public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) {\n        return null;\n    }\n\n    @Override\n    public boolean wasSchematicGenerated(Dimension dimension) {\n        return false;\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public void setSchematicGenerate(Dimension dimension, boolean generated) {\n        // Do nothing.\n    }\n\n    @Override\n    public Collection<Dimension> getGeneratedSchematics() {\n        return Collections.emptySet();\n    }\n\n    @Override\n    public String getSchematicName() {\n        return \"\";\n    }\n\n    @Override\n    public int getPosition(SortingType sortingType) {\n        return -1;\n    }\n\n    @Override\n    public IslandChest[] getChest() {\n        return EMPTY_ISLAND_CHESTS;\n    }\n\n    @Override\n    public int getChestSize() {\n        return 0;\n    }\n\n    @Override\n    public void setChestRows(int index, int rows) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getCoopLimitRaw() {\n        return IslandUpgradeConstants.NO_LIMIT_VALUE;\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return EmptyDatabaseBridge.getInstance();\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        return EmptyPersistentDataContainer.getInstance();\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return true;\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        // Do nothing.\n    }\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return false;\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        return false;\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        return 0;\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        // Do nothing.\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public int compareTo(Island o) {\n        return 0;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.MaterialKeySource;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.google.common.base.Preconditions;\n\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class DefaultIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final KeyMap<BigInteger> blockCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL);\n\n    private final Island island;\n    private boolean loadingDataMode = false;\n\n    public DefaultIslandBlocksTrackerAlgorithm(Island island) {\n        this.island = island;\n    }\n\n    @Override\n    public boolean trackBlock(Key key, BigInteger amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        if (amount.compareTo(BigInteger.ZERO) == 0)\n            return false;\n\n        if (!ServerVersion.isLegacy() && key instanceof MaterialKey &&\n                ((MaterialKey) key).getMaterialKeySource() == MaterialKeySource.ITEM)\n            key = ((MaterialKey) key).toGlobalKey();\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(key);\n        boolean increaseAmount = blockValue != BlockValue.ZERO;\n\n        boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE;\n        boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key);\n\n        if (increaseAmount || hasBlockLimit || valuesMenu) {\n            Log.debug(Debug.BLOCK_PLACE, island.getOwner().getName(), key, amount);\n\n            addCounts(key, amount);\n\n            return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean untrackBlock(Key key, BigInteger amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        if (amount.compareTo(BigInteger.ZERO) == 0)\n            return false;\n\n        if (!ServerVersion.isLegacy() && key instanceof MaterialKey &&\n                ((MaterialKey) key).getMaterialKeySource() == MaterialKeySource.ITEM)\n            key = ((MaterialKey) key).toGlobalKey();\n\n        BlockValue blockValue = plugin.getBlockValues().getBlockValue(key);\n\n        boolean decreaseAmount = blockValue != BlockValue.ZERO;\n\n        boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE;\n        boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key);\n\n        if (decreaseAmount || hasBlockLimit || valuesMenu) {\n            Log.debug(Debug.BLOCK_BREAK, island.getOwner().getName(), key, amount);\n\n            Key valueKey = plugin.getBlockValues().getBlockKey(key);\n            removeCounts(valueKey, amount);\n\n            if (loadingDataMode)\n                return true;\n\n            Key limitKey = island.getBlockLimitKey(valueKey);\n            Key globalKey = ((BaseKey<?>) valueKey).toGlobalKey();\n            boolean limitCount = false;\n\n            if (!limitKey.equals(valueKey)) {\n                removeCounts(limitKey, amount);\n                limitCount = true;\n            }\n\n            if (!globalKey.equals(valueKey) && (!limitCount || !globalKey.equals(limitKey))) {\n                blockValue = plugin.getBlockValues().getBlockValue(globalKey);\n                if (blockValue != BlockValue.ZERO)\n                    removeCounts(globalKey, amount);\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public BigInteger getBlockCount(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return blockCounts.getOrDefault(key, BigInteger.ZERO);\n    }\n\n    @Override\n    public BigInteger getExactBlockCount(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return blockCounts.getRaw(key, BigInteger.ZERO);\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCounts() {\n        return Collections.unmodifiableMap(this.blockCounts);\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        this.blockCounts.clear();\n    }\n\n    @Override\n    public void setLoadingDataMode(boolean loadingDataMode) {\n        this.loadingDataMode = loadingDataMode;\n    }\n\n    private void addCounts(Key key, BigInteger amount) {\n        Key valueKey = plugin.getBlockValues().getBlockKey(key);\n\n        Log.debug(Debug.BLOCK_COUNT_INCREASE, island.getOwner().getName(), key, amount);\n\n        BigInteger currentAmount = blockCounts.getRaw(valueKey, BigInteger.ZERO);\n        blockCounts.put(valueKey, currentAmount.add(amount));\n\n        if (loadingDataMode)\n            return;\n\n        Key limitKey = island.getBlockLimitKey(valueKey);\n        Key globalKey = ((BaseKey<?>) valueKey).toGlobalKey();\n        boolean limitCount = false;\n\n        if (!limitKey.equals(valueKey)) {\n            Log.debugResult(Debug.BLOCK_COUNT_INCREASE, \"Limit Key\", limitKey);\n            currentAmount = blockCounts.getRaw(limitKey, BigInteger.ZERO);\n            blockCounts.put(limitKey, currentAmount.add(amount));\n            limitCount = true;\n        }\n\n        if (!globalKey.equals(valueKey) && (!limitCount || !globalKey.equals(limitKey))) {\n            BlockValue blockValue = plugin.getBlockValues().getBlockValue(globalKey);\n            if (blockValue != BlockValue.ZERO) {\n                Log.debugResult(Debug.BLOCK_COUNT_INCREASE, \"Global Key\", globalKey);\n                currentAmount = blockCounts.getRaw(globalKey, BigInteger.ZERO);\n                blockCounts.put(globalKey, currentAmount.add(amount));\n            }\n        }\n    }\n\n    private void removeCounts(Key key, BigInteger amount) {\n        Log.debug(Debug.BLOCK_COUNT_DECREASE, island.getOwner().getName(), key, amount);\n        BigInteger currentAmount = blockCounts.getRaw(key, BigInteger.ZERO);\n        if (currentAmount.compareTo(amount) <= 0)\n            blockCounts.remove(key);\n        else\n            blockCounts.put(key, currentAmount.subtract(amount));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\nimport java.math.BigInteger;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\n\npublic class DefaultIslandCalculationAlgorithm implements IslandCalculationAlgorithm {\n\n    public static final Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> CACHED_CALCULATED_CHUNKS =\n            Synchronized.of(new Chunk2ObjectMap<>());\n\n    private static final List<Pair<Key, Key>> MINECART_BLOCK_TYPES = createMinecartBlockTypes();\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final DefaultIslandCalculationAlgorithm INSTANCE = new DefaultIslandCalculationAlgorithm();\n\n    private DefaultIslandCalculationAlgorithm() {\n\n    }\n\n    public static DefaultIslandCalculationAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public CompletableFuture<IslandCalculationResult> calculateIsland(Island island) {\n        CompletableFuture<IslandCalculationResult> result = new CompletableFuture<>();\n        BukkitExecutor.ensureMain(() -> calculateIslandInternal(island, result));\n        return result;\n    }\n\n    private void calculateIslandInternal(Island island, CompletableFuture<IslandCalculationResult> result) {\n        CompletableFutureList<List<CalculatedChunk.Blocks>> chunksToLoad = new CompletableFutureList<>(plugin.getSettings().getRecalcTaskTimeout());\n\n        long profiler = Profiler.start(ProfileType.CALCULATE_ISLAND);\n        Log.debug(Debug.CHUNK_CALCULATION_BLOCKS, island.getOwner().getName());\n\n        if (!plugin.getProviders().hasSnapshotsSupport()) {\n            IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS)\n                    .forEach((worldInfo, worldChunks) -> {\n                        // Load the world.\n                        World world = plugin.getProviders().getWorldsProvider().getIslandsWorld(island, worldInfo.getDimension());\n                        if (world != null)\n                            chunksToLoad.add(plugin.getNMSChunks().calculateChunks(worldChunks, CACHED_CALCULATED_CHUNKS));\n                    });\n        } else {\n            IslandUtils.getAllChunksAsync(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS,\n                    ChunkLoadReason.BLOCKS_RECALCULATE, plugin.getProviders()::takeSnapshots).forEach(completableFuture -> {\n                CompletableFuture<List<CalculatedChunk.Blocks>> calculateCompletable = new CompletableFuture<>();\n                completableFuture.whenComplete((chunk, ex) -> {\n                    try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n                        plugin.getNMSChunks().calculateChunks(Collections.singletonList(chunkPosition), CACHED_CALCULATED_CHUNKS)\n                                .whenComplete((pair, ex2) -> calculateCompletable.complete(pair));\n                    }\n                });\n                chunksToLoad.add(calculateCompletable);\n            });\n        }\n\n        BlockCountsTracker blockCounts = new BlockCountsTracker();\n        Set<SpawnerInfo> spawnersToCheck = new HashSet<>();\n        Set<ChunkPosition> chunksToCheck = new HashSet<>();\n\n        BukkitExecutor.createTask().runAsync(v -> {\n            chunksToLoad.forEachCompleted(worldCalculatedChunks -> worldCalculatedChunks.forEach(calculatedChunk -> {\n                Log.debugResult(Debug.CHUNK_CALCULATION_BLOCKS, \"Chunk Finished\", calculatedChunk.getPosition());\n\n                // We want to remove spawners from the chunkInfo, as it will be used later\n                calculatedChunk.getBlockCounts().removeIf(key -> key instanceof SpawnerKey);\n\n                blockCounts.addCounts(calculatedChunk.getBlockCounts());\n\n                // Load spawners\n                for (Location location : calculatedChunk.getSpawners()) {\n                    Pair<Integer, String> spawnerInfo = plugin.getProviders().getSpawnersProvider().getSpawner(location);\n\n                    if (spawnerInfo.getValue() == null) {\n                        spawnersToCheck.add(new SpawnerInfo(location, spawnerInfo.getKey()));\n                    } else {\n                        Key spawnerKey = Keys.ofSpawner(spawnerInfo.getValue(), location);\n                        blockCounts.addCounts(spawnerKey, spawnerInfo.getKey());\n                    }\n                }\n\n                ChunkPosition chunkPosition = calculatedChunk.getPosition();\n                if (!loadExternalBlocksForChunk(chunkPosition, blockCounts))\n                    chunksToCheck.add(chunkPosition);\n\n                // Load built-in stacked blocks\n                plugin.getStackedBlocks().forEach(calculatedChunk.getPosition(), stackedBlock ->\n                        blockCounts.addCounts(stackedBlock.getBlockKey(), stackedBlock.getAmount() - 1));\n\n                plugin.getProviders().releaseSnapshots(calculatedChunk.getPosition());\n            }), result::completeExceptionally);\n        }).runSync(v -> {\n            Key blockKey;\n            int blockCount;\n\n            // Calculate spawner counts\n            for (SpawnerInfo spawnerInfo : spawnersToCheck) {\n                try {\n                    blockKey = Keys.of(spawnerInfo.location.getBlock());\n                    blockCount = spawnerInfo.spawnerCount;\n\n                    if (blockCount <= 0) {\n                        Pair<Integer, String> spawnersProviderInfo = plugin.getProviders()\n                                .getSpawnersProvider().getSpawner(spawnerInfo.location);\n\n                        blockCount = spawnersProviderInfo.getKey();\n\n                        String entityType = spawnersProviderInfo.getValue();\n                        if (entityType != null) {\n                            blockKey = Keys.ofSpawner(entityType, spawnerInfo.location);\n                        }\n                    }\n\n                    blockCounts.addCounts(blockKey, blockCount);\n                } catch (Throwable ignored) {\n                }\n            }\n            spawnersToCheck.clear();\n\n            // Calculate stacked block counts\n            for (ChunkPosition chunkPosition : chunksToCheck) {\n                loadExternalBlocksForChunk(chunkPosition, blockCounts);\n            }\n\n            // Calculate minecart block counts\n            MINECART_BLOCK_TYPES.forEach(minecartTypes -> {\n                int count = island.getEntitiesTracker().getEntityCount(minecartTypes.getKey());\n                if (count > 0)\n                    blockCounts.addCounts(minecartTypes.getValue(), count);\n            });\n\n            chunksToCheck.clear();\n\n            Profiler.end(profiler);\n\n            result.complete(blockCounts);\n        });\n    }\n\n    private static List<Pair<Key, Key>> createMinecartBlockTypes() {\n        List<Pair<Key, Key>> minecartBlockTypes = new LinkedList<>();\n\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_COMMAND, ConstantKeys.COMMAND_BLOCK));\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_CHEST, ConstantKeys.CHEST));\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_FURNACE, ConstantKeys.FURNACE));\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_TNT, ConstantKeys.TNT));\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_HOPPER, ConstantKeys.HOPPER));\n        minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_MOB_SPAWNER, ConstantKeys.MOB_SPAWNER));\n\n        return Collections.unmodifiableList(minecartBlockTypes);\n    }\n\n    private boolean loadExternalBlocksForChunk(ChunkPosition chunkPosition, BlockCountsTracker blockCounts) {\n        // Load stacked blocks\n        Collection<Pair<Key, Integer>> stackedBlocks = plugin.getProviders().getStackedBlocksProvider()\n                .getBlocks(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ());\n\n        if (stackedBlocks == null)\n            return false;\n\n        BlockCountsTracker chunkBlockCounts = new BlockCountsTracker();\n\n        for (ICustomBlocksProvider customBlocksProvider : plugin.getProviders().getCustomBlocksProviders()) {\n            KeyMap<Integer> customBlocksCounts = customBlocksProvider.getBlockCountsForChunk(chunkPosition);\n            if (customBlocksCounts == null)\n                return false;\n\n            customBlocksCounts.forEach(chunkBlockCounts::addCounts);\n        }\n\n        chunkBlockCounts.blockCounts.forEach((block, count) ->\n                blockCounts.addCounts(block, count.intValue()));\n\n        for (Pair<Key, Integer> pair : stackedBlocks) {\n            blockCounts.addCounts(pair.getKey(), pair.getValue() - 1);\n        }\n\n        return true;\n    }\n\n    private static class BlockCountsTracker implements IslandCalculationResult {\n\n        private final KeyMap<BigInteger> blockCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL);\n\n        @Override\n        public Map<Key, BigInteger> getBlockCounts() {\n            return blockCounts;\n        }\n\n        public void addCounts(Key blockKey, int amount) {\n            blockCounts.put(blockKey, blockCounts.getRaw(blockKey, BigInteger.ZERO).add(BigInteger.valueOf(amount)));\n        }\n\n        public void addCounts(KeyMap<Counter> other) {\n            other.forEach((key, counter) -> addCounts(key, counter.get()));\n        }\n\n    }\n\n    private static class SpawnerInfo {\n\n        private final Location location;\n        private final int spawnerCount;\n\n        SpawnerInfo(Location location, int spawnerCount) {\n            this.location = location;\n            this.spawnerCount = spawnerCount;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.block.BlockFace;\n\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\n\npublic class DefaultIslandCreationAlgorithm implements IslandCreationAlgorithm {\n\n    private static final DefaultIslandCreationAlgorithm INSTANCE = new DefaultIslandCreationAlgorithm();\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private DefaultIslandCreationAlgorithm() {\n\n    }\n\n    public static DefaultIslandCreationAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public CompletableFuture<IslandCreationResult> createIsland(UUID islandUUID, SuperiorPlayer owner,\n                                                                BlockPosition lastIsland, String islandName,\n                                                                Schematic schematic) {\n        Preconditions.checkNotNull(islandUUID, \"islandUUID parameter cannot be null.\");\n        Preconditions.checkNotNull(owner, \"owner parameter cannot be null.\");\n        Preconditions.checkNotNull(lastIsland, \"lastIsland parameter cannot be null.\");\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        Preconditions.checkNotNull(schematic, \"schematic parameter cannot be null.\");\n        return createIsland(Island.newBuilder()\n                        .setOwner(owner)\n                        .setUniqueId(islandUUID)\n                        .setName(islandName)\n                        .setSchematicName(schematic.getName())\n                , lastIsland);\n    }\n\n    @Override\n    public CompletableFuture<IslandCreationResult> createIsland(Island.Builder builder, BlockPosition lastIsland) {\n        Preconditions.checkNotNull(builder, \"builder parameter cannot be null.\");\n        Preconditions.checkArgument(builder instanceof IslandBuilderImpl, \"Cannot create an island from custom builder.\");\n        Preconditions.checkNotNull(lastIsland, \"lastIsland parameter cannot be null.\");\n\n        try {\n            return createIslandInternal((IslandBuilderImpl) builder, lastIsland);\n        } catch (Throwable error) {\n            CompletableFuture<IslandCreationResult> result = new CompletableFuture<>();\n            result.completeExceptionally(error);\n            return result;\n        }\n    }\n\n    private CompletableFuture<IslandCreationResult> createIslandInternal(IslandBuilderImpl builder, BlockPosition lastIsland) {\n        Schematic schematic = builder.islandType == null ? null : plugin.getSchematics().getSchematic(builder.islandType);\n\n        Preconditions.checkArgument(builder.owner != null, \"Cannot create an island from builder with no valid owner.\");\n        Preconditions.checkArgument(schematic != null, \"Cannot create an island from builder with invalid schematic name.\");\n\n        Log.debug(Debug.CREATE_ISLAND, builder.owner.getName(), schematic.getName(), lastIsland);\n\n        // Making sure an island with the same name does not exist.\n        if (!Text.isBlank(builder.islandName) && plugin.getGrid().getIsland(builder.islandName) != null) {\n            Log.debugResult(Debug.CREATE_ISLAND, \"Creation Failed\", \"Island with the name \" + builder.islandName + \" already exists.\");\n            return CompletableFuture.completedFuture(new IslandCreationResult(IslandCreationResult.Status.NAME_OCCUPIED, null, null, false));\n        }\n\n        long profiler = Profiler.start(ProfileType.CREATE_ISLAND, schematic.getName());\n\n        Location islandLocation = plugin.getProviders().getWorldsProvider().getNextLocation(\n                lastIsland,\n                plugin.getSettings().getIslandHeight(),\n                plugin.getSettings().getMaxIslandSize(),\n                builder.owner.getUniqueId(),\n                builder.uuid\n        );\n\n        Log.debugResult(Debug.CREATE_ISLAND, \"Next Island Position\", islandLocation);\n\n        Island island = builder.setCenter(islandLocation.add(0.5, 0, 0.5)).build();\n\n        island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE);\n\n        PluginEvent<PluginEventArgs.IslandCreate> event = PluginEventsFactory.callIslandCreateEvent(island, builder.owner, builder.islandType, plugin.getSettings().isTeleportOnCreate());\n\n        if (event.isCancelled()) {\n            Log.debugResult(Debug.CREATE_ISLAND, \"Creation Failed\", \"Event was cancelled for creating the island '\" + builder.islandName + \"'.\");\n            return CompletableFuture.completedFuture(new IslandCreationResult(IslandCreationResult.Status.EVENT_CANCELLED, null, null, false));\n        }\n\n        CompletableFuture<IslandCreationResult> completableFuture = new CompletableFuture<>();\n\n        // Clone location as pasteSchematic uses the same location in later scheduled tasks\n        Location location = islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation();\n\n        schematic.pasteSchematic(island, location, () -> {\n            plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation,\n                    builder.owner.getUniqueId(), builder.uuid);\n            completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getArgs().canTeleport));\n            island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n            Profiler.end(profiler);\n        }, error -> {\n            island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n            plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation,\n                    builder.owner.getUniqueId(), builder.uuid);\n            completableFuture.completeExceptionally(error);\n            Profiler.end(profiler);\n        });\n\n        return completableFuture;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.World;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\npublic class DefaultIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm {\n\n    private static final Set<EntityType> TRACKABLE_ENTITIES = initializeTrackableEntities();\n    private static final long CALCULATE_DELAY = TimeUnit.MINUTES.toMillis(5);\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final KeyMap<Integer> entityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE);\n\n    private final Island island;\n\n    private volatile boolean beingRecalculated = false;\n    private volatile long lastCalculateTime = 0L;\n\n    public DefaultIslandEntitiesTrackerAlgorithm(Island island) {\n        this.island = island;\n    }\n\n    @Override\n    public boolean trackEntity(Key key, int amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), key, amount);\n\n        if (beingRecalculated) {\n            Log.debugResult(Debug.ENTITY_SPAWN, \"Return\", \"Recalculating\");\n            return false;\n        }\n\n        if (amount <= 0) {\n            Log.debugResult(Debug.ENTITY_SPAWN, \"Return\", \"Negative Amount\");\n            return false;\n        }\n\n        if (!canTrackEntity(key)) {\n            Log.debugResult(Debug.ENTITY_SPAWN, \"Return\", \"Cannot Track Entity\");\n            return false;\n        }\n\n        int currentAmount = entityCounts.getOrDefault(key, 0);\n        entityCounts.put(key, currentAmount + amount);\n\n        Log.debugResult(Debug.ENTITY_SPAWN, \"Return\", \"Success\");\n\n        return true;\n    }\n\n    @Override\n    public boolean untrackEntity(Key key, int amount) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n\n        Log.debug(Debug.ENTITY_DESPAWN, island.getOwner().getName(), key, amount);\n\n        if (beingRecalculated) {\n            Log.debugResult(Debug.ENTITY_DESPAWN, \"Return\", \"Recalculating\");\n            return false;\n        }\n\n        if (amount <= 0) {\n            Log.debugResult(Debug.ENTITY_DESPAWN, \"Return\", \"Negative Amount\");\n            return false;\n        }\n\n        if (!canTrackEntity(key)) {\n            Log.debugResult(Debug.ENTITY_DESPAWN, \"Return\", \"Cannot Untrack Entity\");\n            return false;\n        }\n\n        int currentAmount = entityCounts.getOrDefault(key, -1);\n\n        if (currentAmount != -1) {\n            if (currentAmount > amount) {\n                entityCounts.put(key, currentAmount - amount);\n            } else {\n                entityCounts.remove(key);\n            }\n        }\n\n        Log.debugResult(Debug.ENTITY_DESPAWN, \"Return\", \"Success\");\n\n        return true;\n    }\n\n    @Override\n    public int getEntityCount(Key key) {\n        return entityCounts.getOrDefault(key, 0);\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesCounts() {\n        return Collections.unmodifiableMap(entityCounts);\n    }\n\n    @Override\n    public void clearEntityCounts() {\n        this.entityCounts.clear();\n    }\n\n    @Override\n    public void recalculateEntityCounts() {\n        if (beingRecalculated || !canRecalculateEntityCounts())\n            return;\n\n        this.beingRecalculated = true;\n\n        Log.debug(Debug.CHUNK_CALCULATION_ENTITIES, island.getOwner().getName());\n\n        try {\n            this.lastCalculateTime = System.currentTimeMillis();\n\n            CompletableFutureList<List<CalculatedChunk.Entities>> chunkEntities = new CompletableFutureList<>(-1);\n\n            IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS)\n                    .forEach(((worldInfo, worldChunks) -> {\n                        // Load the world.\n                        World world = plugin.getProviders().getWorldsProvider().getIslandsWorld(island, worldInfo.getDimension());\n                        if (world != null)\n                            chunkEntities.add(plugin.getNMSChunks().calculateChunkEntities(worldChunks));\n                    }));\n\n            BukkitExecutor.async(() -> {\n                try {\n                    KeyMap<Counter> recalculatedEntityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE);\n\n                    chunkEntities.forEachCompleted(worldCalculatedChunk -> worldCalculatedChunk.forEach(calculatedChunk -> {\n                        Log.debugResult(Debug.CHUNK_CALCULATION_ENTITIES, \"Chunk Finished\", calculatedChunk.getPosition());\n                        calculatedChunk.getEntityCounts().forEach((entity, count) -> {\n                            if (canTrackEntity(entity))\n                                recalculatedEntityCounts.computeIfAbsent(entity, i -> new Counter(0)).inc(count.get());\n                        });\n                    }), error -> {\n                        error.printStackTrace();\n                        beingRecalculated = false;\n                    });\n\n                    if (!beingRecalculated)\n                        return;\n\n                    clearEntityCounts();\n\n                    if (!recalculatedEntityCounts.isEmpty()) {\n                        recalculatedEntityCounts.forEach((entity, count) -> {\n                            Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), entity, count.get());\n                            this.entityCounts.put(entity, count.get());\n                        });\n                    }\n                } finally {\n                    IslandsDatabaseBridge.saveEntityCounts(this.island);\n                    beingRecalculated = false;\n                }\n            });\n        } catch (Exception error) {\n            IslandsDatabaseBridge.saveEntityCounts(this.island);\n            beingRecalculated = false;\n            throw error;\n        }\n    }\n\n    @Override\n    public boolean canRecalculateEntityCounts() {\n        long currentTime = System.currentTimeMillis();\n        return currentTime - lastCalculateTime > CALCULATE_DELAY;\n    }\n\n    private boolean canTrackEntity(Key key) {\n        if (island.getEntityLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE)\n            return true;\n\n        if (key instanceof EntityTypeKey) {\n            return TRACKABLE_ENTITIES.contains(((EntityTypeKey) key).getEntityType());\n        } else {\n            return key.toString().contains(\"MINECART\");\n        }\n    }\n\n    private static Set<EntityType> initializeTrackableEntities() {\n        EnumSet<EntityType> trackableEntities = EnumSet.noneOf(EntityType.class);\n\n        for (EntityType entityType : EntityType.values()) {\n            if (entityType.name().contains(\"MINECART\")) {\n                trackableEntities.add(entityType);\n            }\n        }\n\n        return trackableEntities.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(trackableEntities);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandBlocksTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class SpawnIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm {\n\n    private static final SpawnIslandBlocksTrackerAlgorithm INSTANCE = new SpawnIslandBlocksTrackerAlgorithm();\n\n    private SpawnIslandBlocksTrackerAlgorithm() {\n    }\n\n    public static SpawnIslandBlocksTrackerAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public boolean trackBlock(Key key, BigInteger amount) {\n        return false;\n    }\n\n    @Override\n    public boolean untrackBlock(Key key, BigInteger amount) {\n        return false;\n    }\n\n    @Override\n    public BigInteger getBlockCount(Key key) {\n        return BigInteger.ZERO;\n    }\n\n    @Override\n    public BigInteger getExactBlockCount(Key key) {\n        return BigInteger.ZERO;\n    }\n\n    @Override\n    public Map<Key, BigInteger> getBlockCounts() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void clearBlockCounts() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setLoadingDataMode(boolean loadingDataMode) {\n        // Do nothing.\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandCalculationAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;\n\nimport java.util.Collections;\nimport java.util.concurrent.CompletableFuture;\n\npublic class SpawnIslandCalculationAlgorithm implements IslandCalculationAlgorithm {\n\n    private static final SpawnIslandCalculationAlgorithm INSTANCE = new SpawnIslandCalculationAlgorithm();\n    private static final IslandCalculationResult RESULT = Collections::emptyMap;\n\n    private SpawnIslandCalculationAlgorithm() {\n\n    }\n\n    public static SpawnIslandCalculationAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public CompletableFuture<IslandCalculationResult> calculateIsland(Island island) {\n        return CompletableFuture.completedFuture(RESULT);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandEntitiesTrackerAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.island.algorithm;\n\nimport com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\n\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class SpawnIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm {\n\n    private static final SpawnIslandEntitiesTrackerAlgorithm INSTANCE = new SpawnIslandEntitiesTrackerAlgorithm();\n\n    private SpawnIslandEntitiesTrackerAlgorithm() {\n    }\n\n    public static SpawnIslandEntitiesTrackerAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public boolean trackEntity(Key key, int amount) {\n        return false;\n    }\n\n    @Override\n    public boolean untrackEntity(Key key, int amount) {\n        return false;\n    }\n\n    @Override\n    public int getEntityCount(Key key) {\n        return 0;\n    }\n\n    @Override\n    public Map<Key, Integer> getEntitiesCounts() {\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void clearEntityCounts() {\n        // Do nothing.\n    }\n\n    @Override\n    public void recalculateEntityCounts() {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean canRecalculateEntityCounts() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/bank/SBankTransaction.java",
    "content": "package com.bgsoftware.superiorskyblock.island.bank;\n\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.util.Date;\nimport java.util.Optional;\nimport java.util.UUID;\n\npublic class SBankTransaction implements BankTransaction {\n\n    private final UUID player;\n    private final BankAction bankAction;\n    private final int position;\n    private final long time;\n    private final String date;\n    private final String failureReason;\n    private final BigDecimal amount;\n\n    public SBankTransaction(UUID player, BankAction bankAction, int position, long time, String failureReason, BigDecimal amount) {\n        this.player = player;\n        this.bankAction = bankAction;\n        this.position = position;\n        this.time = time;\n        this.date = Formatters.DATE_FORMATTER.format(new Date(time));\n        this.failureReason = failureReason == null ? \"\" : failureReason;\n        this.amount = amount.setScale(2, RoundingMode.HALF_EVEN);\n    }\n\n    public static Optional<BankTransaction> fromDatabase(DatabaseResult resultSet) {\n        Optional<BankAction> bankAction = resultSet.getEnum(\"bank_action\", BankAction.class);\n        if (!bankAction.isPresent()) {\n            Log.warn(\"Cannot load bank transaction with invalid bank action, skipping...\");\n            return Optional.empty();\n        }\n\n        Optional<BigDecimal> amount = resultSet.getBigDecimal(\"amount\");\n        if (!amount.isPresent()) {\n            Log.warn(\"Cannot load bank transaction with null amount, skipping...\");\n            return Optional.empty();\n        }\n\n        return Optional.of(new SBankTransaction(\n                resultSet.getUUID(\"player\").orElse(null),\n                bankAction.get(),\n                resultSet.getInt(\"position\").orElse(1),\n                resultSet.getLong(\"time\").orElse(System.currentTimeMillis()),\n                resultSet.getString(\"failure_reason\").orElse(\"\"),\n                amount.get()\n        ));\n    }\n\n    @Override\n    public UUID getPlayer() {\n        return player;\n    }\n\n    @Override\n    public BankAction getAction() {\n        return bankAction;\n    }\n\n    @Override\n    public int getPosition() {\n        return position;\n    }\n\n    @Override\n    public long getTime() {\n        return time;\n    }\n\n    @Override\n    public String getDate() {\n        return date;\n    }\n\n    @Override\n    public String getFailureReason() {\n        return failureReason;\n    }\n\n    @Override\n    public BigDecimal getAmount() {\n        return amount;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java",
    "content": "package com.bgsoftware.superiorskyblock.island.bank;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BankAction;\nimport com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.bank.logs.CacheBankLogs;\nimport com.bgsoftware.superiorskyblock.island.bank.logs.DatabaseBankLogs;\nimport com.bgsoftware.superiorskyblock.island.bank.logs.IBankLogs;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\npublic class SIslandBank implements IslandBank {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final BigDecimal MONEY_FAILURE = BigDecimal.valueOf(-1);\n    private static final UUID CONSOLE_UUID = UUID.fromString(\"00000000-0000-0000-0000-000000000000\");\n\n    private final AtomicReference<BigDecimal> balance = new AtomicReference<>(BigDecimal.ZERO);\n    private final Island island;\n    private final Supplier<Boolean> isGiveInterestFailed;\n    private final IBankLogs bankLogs;\n\n    public SIslandBank(Island island, Supplier<Boolean> isGiveInterestFailed) {\n        this.island = island;\n        this.isGiveInterestFailed = isGiveInterestFailed;\n        this.bankLogs = BuiltinModules.BANK.getConfiguration().isCacheAllLogs() ?\n                new CacheBankLogs() : new DatabaseBankLogs(island);\n    }\n\n    @Override\n    public BigDecimal getBalance() {\n        return balance.get();\n    }\n\n    @Override\n    public void setBalance(BigDecimal balance) {\n        this.balance.set(balance.setScale(2, RoundingMode.HALF_DOWN));\n\n        // Trying to give interest again if the last one failed.\n        if (isGiveInterestFailed.get())\n            island.giveInterest(false);\n    }\n\n    @Override\n    public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        Log.debug(Debug.DEPOSIT_MONEY, island.getOwner().getName(), superiorPlayer.getName(), amount);\n\n        BankTransaction bankTransaction;\n        String failureReason;\n\n        if (!island.hasPermission(superiorPlayer, IslandPrivileges.DEPOSIT_MONEY)) {\n            failureReason = \"No permission\";\n        } else if (amount.compareTo(BigDecimal.ZERO) <= 0) {\n            failureReason = \"Invalid amount\";\n        } else {\n            BigDecimal playerBalance = plugin.getProviders().getBankEconomyProvider().getBalance(superiorPlayer);\n\n            PluginEvent<PluginEventArgs.IslandBankDeposit> event = PluginEventsFactory.callIslandBankDepositEvent(island, superiorPlayer, amount);\n\n            if (event.isCancelled()) {\n                failureReason = event.getArgs().failureReason;\n            } else if (playerBalance.compareTo(amount) < 0) {\n                failureReason = \"Not enough money\";\n            } else if (!canDepositMoney(amount)) {\n                failureReason = \"Exceed bank limit\";\n            } else {\n                EconomyProvider.EconomyResult result = plugin.getProviders()\n                        .withdrawMoneyForBanks(superiorPlayer, amount);\n                failureReason = result.getErrorMessage();\n                amount = BigDecimal.valueOf(result.getTransactionMoney());\n            }\n        }\n\n        int position = this.bankLogs.getLastTransactionPosition() + 1;\n\n        if (Text.isBlank(failureReason)) {\n            Log.debugResult(Debug.DEPOSIT_MONEY, \"Return Success\", amount);\n            bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.DEPOSIT_COMPLETED,\n                    position, System.currentTimeMillis(), \"\", amount);\n            increaseBalance(amount);\n\n            addTransaction(bankTransaction, true);\n\n            IslandUtils.sendMessage(island, Message.DEPOSIT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(),\n                    Formatters.NUMBER_FORMATTER.format(amount));\n\n            plugin.getMenus().refreshBankLogs(island);\n            plugin.getMenus().refreshIslandBank(island);\n        } else {\n            Log.debugResult(Debug.DEPOSIT_MONEY, \"Return Failure\", failureReason);\n            bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.DEPOSIT_FAILED, position,\n                    System.currentTimeMillis(), failureReason, MONEY_FAILURE);\n        }\n\n        return bankTransaction;\n    }\n\n    @Override\n    public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount) {\n        Preconditions.checkNotNull(commandSender, \"commandSender parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        Log.debug(Debug.DEPOSIT_MONEY, island.getOwner().getName(), commandSender.getName(), amount);\n\n        PluginEvent<PluginEventArgs.IslandBankDeposit> event = PluginEventsFactory.callIslandBankDepositEvent(island, commandSender, amount);\n\n        UUID senderUUID = commandSender instanceof Player ? ((Player) commandSender).getUniqueId() : null;\n\n        int position = this.bankLogs.getLastTransactionPosition() + 1;\n\n        BankAction bankAction;\n        if (event.isCancelled()) {\n            bankAction = BankAction.DEPOSIT_FAILED;\n            Log.debugResult(Debug.DEPOSIT_MONEY, \"Return Failure\", \"Event Cancelled\");\n        } else {\n            bankAction = BankAction.DEPOSIT_COMPLETED;\n            Log.debugResult(Debug.DEPOSIT_MONEY, \"Return Success\", amount);\n        }\n\n        BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position,\n                System.currentTimeMillis(), event.getArgs().failureReason, amount);\n\n        addTransaction(bankTransaction, true);\n\n        if (!event.isCancelled())\n            increaseBalance(amount);\n\n        plugin.getMenus().refreshBankLogs(island);\n        plugin.getMenus().refreshIslandBank(island);\n\n        return bankTransaction;\n    }\n\n    @Override\n    public boolean canDepositMoney(BigDecimal amount) {\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        BigDecimal bankLimit = this.island.getBankLimit();\n        return bankLimit.compareTo(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE) <= 0 ||\n                this.balance.get().add(amount).compareTo(bankLimit) <= 0;\n    }\n\n    @Override\n    public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List<String> commandsToExecute) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        Log.debug(Debug.WITHDRAW_MONEY, island.getOwner().getName(), superiorPlayer.getName(), amount, commandsToExecute);\n\n        BigDecimal withdrawAmount = balance.get().min(amount);\n\n        BankTransaction bankTransaction;\n        String failureReason;\n\n        if (!island.hasPermission(superiorPlayer, IslandPrivileges.WITHDRAW_MONEY)) {\n            failureReason = \"No permission\";\n        } else if (this.balance.get().compareTo(BigDecimal.ZERO) <= 0) {\n            failureReason = \"Bank is empty\";\n        } else if (amount.compareTo(BigDecimal.ZERO) <= 0) {\n            failureReason = \"Invalid amount\";\n        } else {\n            PluginEvent<PluginEventArgs.IslandBankWithdraw> event = PluginEventsFactory.callIslandBankWithdrawEvent(island, superiorPlayer, withdrawAmount);\n\n            if (event.isCancelled()) {\n                failureReason = event.getArgs().failureReason;\n            } else if (commandsToExecute == null || commandsToExecute.isEmpty()) {\n                EconomyProvider.EconomyResult result = plugin.getProviders().depositMoneyForBanks(superiorPlayer, withdrawAmount);\n                failureReason = result.getErrorMessage();\n                withdrawAmount = BigDecimal.valueOf(result.getTransactionMoney());\n            } else {\n                String currentBalance = balance.get().toString();\n                failureReason = \"\";\n                commandsToExecute.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command\n                        .replace(\"{0}\", superiorPlayer.getName())\n                        .replace(\"{1}\", currentBalance)\n                ));\n            }\n        }\n\n        int position = this.bankLogs.getLastTransactionPosition() + 1;\n\n        if (Text.isBlank(failureReason)) {\n            Log.debugResult(Debug.WITHDRAW_MONEY, \"Return Success\", amount);\n            bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.WITHDRAW_COMPLETED, position, System.currentTimeMillis(), \"\", withdrawAmount);\n            decreaseBalance(withdrawAmount);\n\n            addTransaction(bankTransaction, true);\n\n            IslandUtils.sendMessage(island, Message.WITHDRAW_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(),\n                    Formatters.NUMBER_FORMATTER.format(withdrawAmount));\n\n            plugin.getMenus().refreshBankLogs(island);\n            plugin.getMenus().refreshIslandBank(island);\n\n        } else {\n            Log.debugResult(Debug.DEPOSIT_MONEY, \"Return Failure\", failureReason);\n            bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.WITHDRAW_FAILED, position, System.currentTimeMillis(), failureReason, MONEY_FAILURE);\n        }\n\n        return bankTransaction;\n    }\n\n    @Override\n    public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount) {\n        Preconditions.checkNotNull(commandSender, \"commandSender parameter cannot be null.\");\n        Preconditions.checkNotNull(amount, \"amount parameter cannot be null.\");\n\n        Log.debug(Debug.WITHDRAW_MONEY, island.getOwner().getName(), commandSender.getName(), amount);\n\n        UUID senderUUID = commandSender instanceof Player ? ((Player) commandSender).getUniqueId() : null;\n\n        int position = this.bankLogs.getLastTransactionPosition() + 1;\n\n        PluginEvent<PluginEventArgs.IslandBankWithdraw> event = PluginEventsFactory.callIslandBankWithdrawEvent(\n                island, commandSender, amount);\n\n        BankAction bankAction;\n        if (event.isCancelled()) {\n            bankAction = BankAction.DEPOSIT_FAILED;\n            Log.debugResult(Debug.WITHDRAW_MONEY, \"Return Failure\", \"Event Cancelled\");\n        } else {\n            bankAction = BankAction.DEPOSIT_COMPLETED;\n            Log.debugResult(Debug.WITHDRAW_MONEY, \"Return Success\", amount);\n        }\n        BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position,\n                System.currentTimeMillis(), event.getArgs().failureReason, amount);\n\n        if (!event.isCancelled())\n            decreaseBalance(amount);\n\n        addTransaction(bankTransaction, true);\n\n        plugin.getMenus().refreshBankLogs(island);\n        plugin.getMenus().refreshIslandBank(island);\n\n        return bankTransaction;\n    }\n\n    @Override\n    public List<BankTransaction> getAllTransactions() {\n        return this.bankLogs.getTransactions();\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions(SuperiorPlayer superiorPlayer) {\n        return this.bankLogs.getTransactions(superiorPlayer.getUniqueId());\n    }\n\n    @Override\n    public List<BankTransaction> getConsoleTransactions() {\n        return this.bankLogs.getTransactions(CONSOLE_UUID);\n    }\n\n    @Override\n    public void loadTransaction(BankTransaction bankTransaction) {\n        addTransaction(bankTransaction, false);\n    }\n\n    private void addTransaction(BankTransaction bankTransaction, boolean save) {\n        if (!BuiltinModules.BANK.getConfiguration().isBankLogs())\n            return;\n\n        UUID senderUUID = bankTransaction.getPlayer();\n\n        this.bankLogs.addTransaction(bankTransaction, senderUUID == null ? CONSOLE_UUID : senderUUID, !save);\n\n        if (save) {\n            IslandsDatabaseBridge.saveBankTransaction(island, bankTransaction);\n        }\n    }\n\n    private void decreaseBalance(BigDecimal amount) {\n        increaseBalance(amount.negate());\n    }\n\n    private void increaseBalance(BigDecimal amount) {\n        this.balance.updateAndGet(bigDecimal -> bigDecimal.add(amount).setScale(3, RoundingMode.HALF_DOWN));\n        IslandsDatabaseBridge.saveBankBalance(island);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java",
    "content": "package com.bgsoftware.superiorskyblock.island.bank.logs;\n\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.island.top.SortingComparators;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class CacheBankLogs implements IBankLogs {\n\n    private final Synchronized<SortedSet<BankTransaction>> transactions = Synchronized.of(new TreeSet<>(SortingComparators.BANK_TRANSACTIONS_COMPARATOR));\n    private final Map<UUID, Synchronized<List<BankTransaction>>> transactionsByPlayers = new ConcurrentHashMap<>();\n\n    @Override\n    public int getLastTransactionPosition() {\n        return this.transactions.readAndGet(set -> set.isEmpty() ? 0 : set.last().getPosition());\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions() {\n        return transactions.readAndGet(bankTransactions -> new SequentialListBuilder<BankTransaction>().build(bankTransactions));\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions(UUID playerUUID) {\n        Synchronized<List<BankTransaction>> transactions = this.transactionsByPlayers.get(playerUUID);\n        return transactions == null ? Collections.emptyList() : transactions.readAndGet(Collections::unmodifiableList);\n    }\n\n    @Override\n    public void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase) {\n        transactions.write(transactions -> transactions.add(bankTransaction));\n        transactionsByPlayers.computeIfAbsent(senderUUID, p -> Synchronized.of(new LinkedList<>()))\n                .write(transactions -> transactions.add(bankTransaction));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java",
    "content": "package com.bgsoftware.superiorskyblock.island.bank.logs;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseFilter;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.database.DatabaseResult;\nimport com.bgsoftware.superiorskyblock.island.bank.SBankTransaction;\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\n@SuppressWarnings(\"UnstableApiUsage\")\npublic class DatabaseBankLogs implements IBankLogs {\n\n    private final LoadingCache<Integer, List<BankTransaction>> cachedBankTransactions = CacheBuilder.newBuilder()\n            .maximumSize(1)\n            .expireAfterAccess(10, TimeUnit.MINUTES)\n            .build(new CacheLoader<Integer, List<BankTransaction>>() {\n                @Override\n                public List<BankTransaction> load(@NotNull Integer ignored) {\n                    sessionBankTransactions.invalidateAll();\n                    return loadTransactionsFromDatabase();\n                }\n            });\n    private final LoadingCache<Integer, List<BankTransaction>> sessionBankTransactions = CacheBuilder.newBuilder()\n            .maximumSize(1)\n            .expireAfterAccess(10, TimeUnit.MINUTES)\n            .build(new CacheLoader<Integer, List<BankTransaction>>() {\n                @Override\n                public List<BankTransaction> load(@NotNull Integer ignored) {\n                    return new LinkedList<>();\n                }\n            });\n\n    private final Island island;\n    private int lastTransactionPosition = -1;\n\n    public DatabaseBankLogs(Island island) {\n        this.island = island;\n    }\n\n    @Override\n    public int getLastTransactionPosition() {\n        if (lastTransactionPosition == -1) {\n            lastTransactionPosition = 0;\n            for (BankTransaction transaction : getTransactions()) {\n                int position = transaction.getPosition();\n                if (position > lastTransactionPosition) {\n                    lastTransactionPosition = position;\n                }\n            }\n        }\n\n        return lastTransactionPosition++;\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions() {\n        return collectBankTransactions();\n    }\n\n    @Override\n    public List<BankTransaction> getTransactions(UUID playerUUID) {\n        return new SequentialListBuilder<BankTransaction>()\n                .filter(bankTransaction -> playerUUID.equals(bankTransaction.getPlayer()))\n                .build(collectBankTransactions());\n    }\n\n    @Override\n    public void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase) {\n        sessionBankTransactions.getUnchecked(0).add(bankTransaction);\n    }\n\n    private List<BankTransaction> collectBankTransactions() {\n        List<BankTransaction> bankTransactionList = new LinkedList<>();\n        bankTransactionList.addAll(cachedBankTransactions.getUnchecked(0));\n        bankTransactionList.addAll(sessionBankTransactions.getUnchecked(0));\n        return bankTransactionList;\n    }\n\n    private List<BankTransaction> loadTransactionsFromDatabase() {\n        List<BankTransaction> bankTransactionsList = new LinkedList<>();\n        island.getDatabaseBridge().loadObject(\"bank_transactions\",\n                DatabaseFilter.fromFilter(\"island\", island.getUniqueId().toString()),\n                bankTransactionRow -> SBankTransaction.fromDatabase(new DatabaseResult(bankTransactionRow))\n                        .ifPresent(bankTransactionsList::add));\n        return bankTransactionsList;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/IBankLogs.java",
    "content": "package com.bgsoftware.superiorskyblock.island.bank.logs;\n\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\n\nimport java.util.List;\nimport java.util.UUID;\n\npublic interface IBankLogs {\n\n    int getLastTransactionPosition();\n\n    List<BankTransaction> getTransactions();\n\n    List<BankTransaction> getTransactions(UUID playerUUID);\n\n    void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.island.builder;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.Rating;\nimport com.bgsoftware.superiorskyblock.api.enums.SyncStatus;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PermissionNode;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.DirtyChunk;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.value.DoubleValue;\nimport com.bgsoftware.superiorskyblock.core.value.IntValue;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.island.SIsland;\nimport com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.IdentityHashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\n\npublic class IslandBuilderImpl implements Island.Builder {\n\n    private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2);\n    private static final int SYNCED_VALUE = -2;\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    @Nullable\n    public SuperiorPlayer owner;\n    public UUID uuid = null;\n    public BlockPosition center = null;\n    public String islandName = \"\";\n    @Nullable\n    public String islandType;\n    public long creationTime = System.currentTimeMillis() / 1000;\n    public String discord = \"None\";\n    public String paypal = \"None\";\n    public BigDecimal bonusWorth = BigDecimal.ZERO;\n    public BigDecimal bonusLevel = BigDecimal.ZERO;\n    public boolean isLocked = plugin.getSettings().isLockedIslands();\n    public boolean isIgnored = false;\n    public String description = \"\";\n    public EnumerateSet<Dimension> generatedSchematics = new EnumerateSet<>(Dimension.values());\n    public EnumerateSet<Dimension> unlockedWorlds = new EnumerateSet<>(Dimension.values());\n    public long lastTimeUpdated = System.currentTimeMillis() / 1000;\n    public final Set<DirtyChunk> dirtyChunks = new LinkedHashSet<>();\n    public final KeyMap<BigInteger> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n    public final KeyMap<BigInteger> entityCounts = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n    public final EnumerateMap<Dimension, WorldPosition> islandHomes = new EnumerateMap<>(Dimension.values());\n    public final List<SuperiorPlayer> members = new LinkedList<>();\n    public final List<SuperiorPlayer> bannedPlayers = new LinkedList<>();\n    public final Map<SuperiorPlayer, PlayerPrivilegeNode> playerPermissions = new LinkedHashMap<>();\n    public final Map<IslandPrivilege, Integer> rolePermissions = new LinkedHashMap<>();\n    public final Map<String, Integer> upgrades = new LinkedHashMap<>();\n    public final KeyMap<IntValue> blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n    public final Map<UUID, Rating> ratings = new LinkedHashMap<>();\n    public final Map<MissionReference, Counter> completedMissions = new LinkedHashMap<>();\n    public final Map<IslandFlag, Byte> islandFlags = new LinkedHashMap<>();\n    public final EnumerateMap<Dimension, KeyMap<IntValue>> cobbleGeneratorValues = new EnumerateMap<>(Dimension.values());\n    public final List<SIsland.UniqueVisitor> uniqueVisitors = new LinkedList<>();\n    public final KeyMap<IntValue> entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n    public final Map<PotionEffectType, IntValue> islandEffects = new LinkedHashMap<>();\n    public final List<ItemStack[]> islandChests = new ArrayList<>(plugin.getSettings().getIslandChests().getDefaultPages());\n    public final Int2ObjectMapView<IntValue> roleLimits = CollectionsFactory.createInt2ObjectArrayMap();\n    public final EnumerateMap<Dimension, WorldPosition> visitorHomes = new EnumerateMap<>(Dimension.values());\n    public IntValue islandSize = IntValue.syncedFixed(SYNCED_VALUE);\n    public IntValue warpsLimit = IntValue.syncedFixed(SYNCED_VALUE);\n    public IntValue teamLimit = IntValue.syncedFixed(SYNCED_VALUE);\n    public IntValue coopLimit = IntValue.syncedFixed(SYNCED_VALUE);\n    public DoubleValue cropGrowth = DoubleValue.syncedFixed(SYNCED_VALUE);\n    public DoubleValue spawnerRates = DoubleValue.syncedFixed(SYNCED_VALUE);\n    public DoubleValue mobDrops = DoubleValue.syncedFixed(SYNCED_VALUE);\n    public Value<BigDecimal> bankLimit = Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE);\n    public BigDecimal balance = BigDecimal.ZERO;\n    public long lastInterestTime = System.currentTimeMillis() / 1000;\n    public List<WarpRecord> warps = new LinkedList<>();\n    public List<WarpCategoryRecord> warpCategories = new LinkedList<>();\n    public List<BankTransaction> bankTransactions = new LinkedList<>();\n    public byte[] persistentData = new byte[0];\n\n    public IslandBuilderImpl() {\n\n    }\n\n    @Override\n    public Island.Builder setOwner(@Nullable SuperiorPlayer owner) {\n        this.owner = owner;\n        return this;\n    }\n\n    @Override\n    @Nullable\n    public SuperiorPlayer getOwner() {\n        return this.owner;\n    }\n\n    @Override\n    public Island.Builder setUniqueId(UUID uuid) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        Preconditions.checkState(plugin.getGrid().getIslandByUUID(uuid) == null, \"The provided uuid is not unique.\");\n        this.uuid = uuid;\n        return this;\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return this.uuid;\n    }\n\n    @Override\n    public Island.Builder setCenter(Location center) {\n        Preconditions.checkNotNull(center, \"center parameter cannot be null.\");\n        Preconditions.checkState(isValidCenter(center), \"The provided center is not centered. center: \" + center +\n                \", maxIslandSize: \" + plugin.getSettings().getMaxIslandSize());\n        this.center = SBlockPosition.of(center);\n        return this;\n    }\n\n    @Override\n    public Location getCenter() {\n        return this.center.toLocation((World) null);\n    }\n\n    @Override\n    public Island.Builder setName(String islandName) {\n        Preconditions.checkNotNull(islandName, \"islandName parameter cannot be null.\");\n        this.islandName = islandName;\n        return this;\n    }\n\n    @Override\n    public String getName() {\n        return this.islandName;\n    }\n\n    @Override\n    public Island.Builder setSchematicName(String islandType) {\n        Preconditions.checkNotNull(islandType, \"islandType parameter cannot be null.\");\n        this.islandType = islandType;\n        return this;\n    }\n\n    @Override\n    public String getScehmaticName() {\n        return this.islandType;\n    }\n\n    @Override\n    public Island.Builder setCreationTime(long creationTime) {\n        this.creationTime = creationTime;\n        return this;\n    }\n\n    @Override\n    public long getCreationTime() {\n        return this.creationTime;\n    }\n\n    @Override\n    public Island.Builder setDiscord(String discord) {\n        Preconditions.checkNotNull(discord, \"discord parameter cannot be null.\");\n        this.discord = discord;\n        return this;\n    }\n\n    @Override\n    public String getDiscord() {\n        return this.discord;\n    }\n\n    @Override\n    public Island.Builder setPaypal(String paypal) {\n        Preconditions.checkNotNull(paypal, \"paypal parameter cannot be null.\");\n        this.paypal = paypal;\n        return this;\n    }\n\n    @Override\n    public String getPaypal() {\n        return this.paypal;\n    }\n\n    @Override\n    public Island.Builder setBonusWorth(BigDecimal bonusWorth) {\n        Preconditions.checkNotNull(bonusWorth, \"bonusWorth parameter cannot be null.\");\n        this.bonusWorth = bonusWorth;\n        return this;\n    }\n\n    @Override\n    public BigDecimal getBonusWorth() {\n        return this.bonusWorth;\n    }\n\n    @Override\n    public Island.Builder setBonusLevel(BigDecimal bonusLevel) {\n        Preconditions.checkNotNull(bonusLevel, \"bonusLevel parameter cannot be null.\");\n        this.bonusLevel = bonusLevel;\n        return this;\n    }\n\n    @Override\n    public BigDecimal getBonusLevel() {\n        return this.bonusLevel;\n    }\n\n    @Override\n    public Island.Builder setLocked(boolean isLocked) {\n        this.isLocked = isLocked;\n        return this;\n    }\n\n    @Override\n    public boolean isLocked() {\n        return this.isLocked;\n    }\n\n    @Override\n    public Island.Builder setIgnored(boolean isIgnored) {\n        this.isIgnored = isIgnored;\n        return this;\n    }\n\n    @Override\n    public boolean isIgnored() {\n        return this.isIgnored;\n    }\n\n    @Override\n    public Island.Builder setDescription(String description) {\n        Preconditions.checkNotNull(description, \"description parameter cannot be null.\");\n        this.description = description;\n        return this;\n    }\n\n    @Override\n    public String getDescription() {\n        return this.description;\n    }\n\n    @Override\n    public Island.Builder setGeneratedSchematic(Dimension dimension) {\n        this.generatedSchematics.add(dimension);\n        return this;\n    }\n\n    @Override\n    public Set<Dimension> getGeneratedSchematics() {\n        return Collections.unmodifiableSet(this.generatedSchematics.collect(Dimension.values()));\n    }\n\n    @Override\n    public Island.Builder setUnlockedWorld(Dimension dimension) {\n        this.unlockedWorlds.add(dimension);\n        return this;\n    }\n\n    @Override\n    public Set<Dimension> getUnlockedWorlds() {\n        return Collections.unmodifiableSet(this.unlockedWorlds.collect(Dimension.values()));\n    }\n\n    @Override\n    public Island.Builder setLastTimeUpdated(long lastTimeUpdated) {\n        this.lastTimeUpdated = lastTimeUpdated;\n        return this;\n    }\n\n    @Override\n    public long getLastTimeUpdated() {\n        return this.lastTimeUpdated;\n    }\n\n    @Override\n    public Island.Builder setDirtyChunk(String worldName, int chunkX, int chunkZ) {\n        Preconditions.checkNotNull(worldName, \"worldName parameter cannot be null.\");\n        this.dirtyChunks.add(new DirtyChunk(worldName, chunkX, chunkZ));\n        return this;\n    }\n\n    @Override\n    public boolean isDirtyChunk(String worldName, int chunkX, int chunkZ) {\n        return this.dirtyChunks.contains(new DirtyChunk(worldName, chunkX, chunkZ));\n    }\n\n    @Override\n    public Island.Builder setBlockCount(Key block, BigInteger count) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        Preconditions.checkNotNull(count, \"count parameter cannot be null.\");\n        this.blockCounts.put(block, count);\n        return this;\n    }\n\n    @Override\n    public KeyMap<BigInteger> getBlockCounts() {\n        return KeyMaps.unmodifiableKeyMap(this.blockCounts);\n    }\n\n    @Override\n    public Island.Builder setEntityCount(Key entity, BigInteger count) {\n        Preconditions.checkNotNull(entity, \"entity parameter cannot be null.\");\n        Preconditions.checkNotNull(count, \"count parameter cannot be null.\");\n        this.entityCounts.put(entity, count);\n        return this;\n    }\n\n    @Override\n    public KeyMap<BigInteger> getEntityCounts() {\n        return KeyMaps.unmodifiableKeyMap(this.entityCounts);\n    }\n\n    @Override\n    public Island.Builder setIslandHome(Location location, Dimension dimension) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return setIslandHome(dimension, SWorldPosition.of(location));\n    }\n\n    @Override\n    public Island.Builder setIslandHome(Dimension dimension, WorldPosition worldPosition) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n        this.islandHomes.put(dimension, worldPosition);\n        return this;\n    }\n\n    @Override\n    public Map<Dimension, Location> getIslandHomesAsDimensions() {\n        Map<Dimension, Location> islandHomes = new LinkedHashMap<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            WorldPosition islandHome = this.islandHomes.get(dimension);\n            if (islandHome != null) {\n                islandHomes.put(dimension, islandHome.toLocation((World) null));\n            }\n        }\n\n        return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes);\n    }\n\n    @Override\n    public Island.Builder addIslandMember(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        this.members.add(superiorPlayer);\n        return this;\n    }\n\n    @Override\n    public List<SuperiorPlayer> getIslandMembers() {\n        return Collections.unmodifiableList(this.members);\n    }\n\n    @Override\n    public Island.Builder addBannedPlayer(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        this.bannedPlayers.add(superiorPlayer);\n        return this;\n    }\n\n    @Override\n    public List<SuperiorPlayer> getBannedPlayers() {\n        return Collections.unmodifiableList(this.bannedPlayers);\n    }\n\n    @Override\n    public Island.Builder setPlayerPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n        this.playerPermissions.computeIfAbsent(superiorPlayer, p -> new PlayerPrivilegeNode(superiorPlayer, null))\n                .loadPrivilege(islandPrivilege, (byte) (value ? 1 : 0));\n        return this;\n    }\n\n    @Override\n    public Map<SuperiorPlayer, PermissionNode> getPlayerPermissions() {\n        return Collections.unmodifiableMap(this.playerPermissions);\n    }\n\n    @Override\n    public Island.Builder setRolePermission(IslandPrivilege islandPrivilege, PlayerRole requiredRole) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n        Preconditions.checkNotNull(requiredRole, \"requiredRole parameter cannot be null.\");\n        this.rolePermissions.put(islandPrivilege, requiredRole.getId());\n        return this;\n    }\n\n    @Override\n    public Map<IslandPrivilege, PlayerRole> getRolePermissions() {\n        return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue())\n        )));\n    }\n\n    @Override\n    public Island.Builder setUpgrade(Upgrade upgrade, int level) {\n        Preconditions.checkNotNull(upgrade, \"upgrade parameter cannot be null.\");\n        this.upgrades.put(upgrade.getName(), level);\n        return this;\n    }\n\n    @Override\n    public Map<Upgrade, Integer> getUpgrades() {\n        return Collections.unmodifiableMap(this.upgrades.entrySet().stream().collect(Collectors.toMap(\n                entry -> plugin.getUpgrades().getUpgrade(entry.getKey()),\n                Map.Entry::getValue\n        )));\n    }\n\n    @Override\n    public Island.Builder setBlockLimit(Key block, int limit) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        this.blockLimits.put(block, limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit));\n        return this;\n    }\n\n    @Override\n    public KeyMap<Integer> getBlockLimits() {\n        return KeyMap.createKeyMap(IntValue.unboxMap(this.blockLimits));\n    }\n\n    @Override\n    public Island.Builder setRating(SuperiorPlayer superiorPlayer, Rating rating) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(rating, \"rating parameter cannot be null.\");\n        this.ratings.put(superiorPlayer.getUniqueId(), rating);\n        return this;\n    }\n\n    @Override\n    public Map<SuperiorPlayer, Rating> getRatings() {\n        return Collections.unmodifiableMap(this.ratings.entrySet().stream().collect(Collectors.toMap(\n                entry -> plugin.getPlayers().getSuperiorPlayer(entry.getKey()),\n                Map.Entry::getValue\n        )));\n    }\n\n    @Override\n    public Island.Builder setCompletedMission(Mission<?> mission, int finishCount) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        this.completedMissions.put(new MissionReference(mission), new Counter(finishCount));\n        return this;\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissions() {\n        Map<Mission<?>, Integer> completedMissions = new LinkedHashMap<>();\n\n        this.completedMissions.forEach((mission, finishCount) -> {\n            if (mission.isValid())\n                completedMissions.put(mission.getMission(), finishCount.get());\n        });\n\n        return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions);\n    }\n\n    @Override\n    public Island.Builder setIslandFlag(IslandFlag islandFlag, boolean value) {\n        Preconditions.checkNotNull(islandFlag, \"islandFlag parameter cannot be null.\");\n        this.islandFlags.put(islandFlag, (byte) (value ? 1 : 0));\n        return this;\n    }\n\n    @Override\n    public Map<IslandFlag, SyncStatus> getIslandFlags() {\n        return Collections.unmodifiableMap(this.islandFlags.entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> entry.getValue() == 1 ? SyncStatus.ENABLED : SyncStatus.DISABLED\n        )));\n    }\n\n    @Override\n    public Island.Builder setGeneratorRate(Key block, int rate, Dimension dimension) {\n        Preconditions.checkNotNull(block, \"block parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension dimension cannot be null.\");\n        this.cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL))\n                .put(block, rate < 0 ? IntValue.syncedFixed(rate) : IntValue.fixed(rate));\n        return this;\n    }\n\n    @Override\n    public Map<Dimension, KeyMap<Integer>> getGeneratorRatesAsDimensions() {\n        Map<Dimension, KeyMap<Integer>> result = new IdentityHashMap<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            KeyMap<IntValue> generatorRates = this.cobbleGeneratorValues.get(dimension);\n            if (generatorRates != null) {\n                if (generatorRates.isEmpty()) {\n                    result.put(dimension, KeyMaps.createEmptyMap());\n                } else {\n                    result.put(dimension, KeyMap.createKeyMap(IntValue.unboxMap(generatorRates)));\n                }\n            }\n        }\n\n        return Collections.unmodifiableMap(result);\n    }\n\n    @Override\n    public Island.Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        this.uniqueVisitors.add(new SIsland.UniqueVisitor(superiorPlayer, visitTime));\n        return this;\n    }\n\n    @Override\n    public Map<SuperiorPlayer, Long> getUniqueVisitors() {\n        LinkedHashMap<SuperiorPlayer, Long> result = new LinkedHashMap<>();\n        this.uniqueVisitors.forEach(uniqueVisitor ->\n                result.put(uniqueVisitor.getSuperiorPlayer(), uniqueVisitor.getLastVisitTime()));\n        return Collections.unmodifiableMap(result);\n    }\n\n    @Override\n    public Island.Builder setEntityLimit(Key entity, int limit) {\n        Preconditions.checkNotNull(entity, \"entity parameter cannot be null.\");\n        this.entityLimits.put(entity, limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit));\n        return this;\n    }\n\n    @Override\n    public KeyMap<Integer> getEntityLimits() {\n        return KeyMap.createKeyMap(IntValue.unboxMap(this.entityLimits));\n    }\n\n    @Override\n    public Island.Builder setIslandEffect(PotionEffectType potionEffectType, int level) {\n        Preconditions.checkNotNull(potionEffectType, \"potionEffectType parameter cannot be null.\");\n        this.islandEffects.put(potionEffectType, level < 0 ? IntValue.syncedFixed(level) : IntValue.fixed(level));\n        return this;\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getIslandEffects() {\n        return Collections.unmodifiableMap(IntValue.unboxMap(this.islandEffects));\n    }\n\n    @Override\n    public Island.Builder setIslandChest(int index, ItemStack[] contents) {\n        Preconditions.checkNotNull(contents, \"contents parameter cannot be null.\");\n\n        if (index >= this.islandChests.size()) {\n            while (index > this.islandChests.size()) {\n                this.islandChests.add(new ItemStack[plugin.getSettings().getIslandChests().getDefaultSize() * 9]);\n            }\n\n            this.islandChests.add(contents);\n        } else {\n            this.islandChests.set(index, contents);\n        }\n\n        return this;\n    }\n\n    @Override\n    public List<ItemStack[]> getIslandChests() {\n        return Collections.unmodifiableList(this.islandChests);\n    }\n\n    @Override\n    public Island.Builder setRoleLimit(PlayerRole playerRole, int limit) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        this.roleLimits.put(playerRole.getId(), limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit));\n        return this;\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getRoleLimits() {\n        if (this.roleLimits.isEmpty())\n            return Collections.emptyMap();\n\n        Map<PlayerRole, Integer> roleLimits = new HashMap<>();\n        Iterator<Int2ObjectMapView.Entry<IntValue>> iterator = this.roleLimits.entryIterator();\n        while (iterator.hasNext()) {\n            Int2ObjectMapView.Entry<IntValue> entry = iterator.next();\n            roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get());\n        }\n\n        return Collections.unmodifiableMap(roleLimits);\n    }\n\n    @Override\n    public Island.Builder setVisitorHome(Location location, Dimension dimension) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        return setVisitorHome(dimension, SWorldPosition.of(location));\n    }\n\n    @Override\n    public Island.Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n        this.visitorHomes.put(dimension, worldPosition);\n        return this;\n    }\n\n    @Override\n    public Map<Dimension, Location> getVisitorHomesAsDimensions() {\n        Map<Dimension, Location> visitorHomes = new LinkedHashMap<>();\n\n        for (Dimension dimension : Dimension.values()) {\n            WorldPosition visitorHome = this.visitorHomes.get(dimension);\n            if (visitorHome != null) {\n                visitorHomes.put(dimension, visitorHome.toLocation((World) null));\n            }\n        }\n\n        return visitorHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(visitorHomes);\n    }\n\n    @Override\n    public Island.Builder setIslandSize(int islandSize) {\n        this.islandSize = islandSize < 0 ? IntValue.syncedFixed(islandSize) : IntValue.fixed(islandSize);\n        return this;\n    }\n\n    @Override\n    public int getIslandSize() {\n        return this.islandSize.get();\n    }\n\n    @Override\n    public Island.Builder setTeamLimit(int teamLimit) {\n        this.teamLimit = teamLimit < 0 ? IntValue.syncedFixed(teamLimit) : IntValue.fixed(teamLimit);\n        return this;\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return this.teamLimit.get();\n    }\n\n    @Override\n    public Island.Builder setWarpsLimit(int warpsLimit) {\n        this.warpsLimit = warpsLimit < 0 ? IntValue.syncedFixed(warpsLimit) : IntValue.fixed(warpsLimit);\n        return this;\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return this.warpsLimit.get();\n    }\n\n    @Override\n    public Island.Builder setCropGrowth(double cropGrowth) {\n        this.cropGrowth = cropGrowth < 0 ? DoubleValue.syncedFixed(cropGrowth) : DoubleValue.fixed(cropGrowth);\n        return this;\n    }\n\n    @Override\n    public double getCropGrowth() {\n        return this.cropGrowth.get();\n    }\n\n    @Override\n    public Island.Builder setSpawnerRates(double spawnerRates) {\n        this.spawnerRates = spawnerRates < 0 ? DoubleValue.syncedFixed(spawnerRates) : DoubleValue.fixed(spawnerRates);\n        return this;\n    }\n\n    @Override\n    public double getSpawnerRates() {\n        return this.spawnerRates.get();\n    }\n\n    @Override\n    public Island.Builder setMobDrops(double mobDrops) {\n        this.mobDrops = mobDrops < 0 ? DoubleValue.syncedFixed(mobDrops) : DoubleValue.fixed(mobDrops);\n        return this;\n    }\n\n    @Override\n    public double getMobDrops() {\n        return this.mobDrops.get();\n    }\n\n    @Override\n    public Island.Builder setCoopLimit(int coopLimit) {\n        this.coopLimit = coopLimit < 0 ? IntValue.syncedFixed(coopLimit) : IntValue.fixed(coopLimit);\n        return this;\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return this.coopLimit.get();\n    }\n\n    @Override\n    public Island.Builder setBankLimit(BigDecimal bankLimit) {\n        Preconditions.checkNotNull(bankLimit, \"bankLimit parameter cannot be null.\");\n        this.bankLimit = bankLimit.compareTo(SYNCED_BANK_LIMIT_VALUE) <= 0 ? Value.syncedFixed(bankLimit) : Value.fixed(bankLimit);\n        return this;\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return this.bankLimit.get();\n    }\n\n    @Override\n    public Island.Builder setBalance(BigDecimal balance) {\n        Preconditions.checkNotNull(balance, \"balance parameter cannot be null.\");\n        this.balance = balance;\n        return this;\n    }\n\n    @Override\n    public BigDecimal getBalance() {\n        return this.balance;\n    }\n\n    @Override\n    public Island.Builder setLastInterestTime(long lastInterestTime) {\n        this.lastInterestTime = lastInterestTime;\n        return this;\n    }\n\n    @Override\n    public long getLastInterestTime() {\n        return this.lastInterestTime;\n    }\n\n    @Override\n    public Island.Builder addWarp(String name, String category, Location location, boolean isPrivate, @Nullable ItemStack icon) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkNotNull(category, \"category parameter cannot be null.\");\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n        this.warps.add(new WarpRecord(name, category, SWorldPosition.of(location), LazyWorldLocation.getWorldName(location), isPrivate, icon));\n        return this;\n    }\n\n    @Override\n    public Island.Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkNotNull(category, \"category parameter cannot be null.\");\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null.\");\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n        this.warps.add(new WarpRecord(name, category, worldPosition, worldInfo.getName(), isPrivate, icon));\n        return this;\n    }\n\n    @Override\n    public boolean hasWarp(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null\");\n\n        for (WarpRecord warpRecord : this.warps) {\n            if (warpRecord.name.equals(name))\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean hasWarp(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null\");\n\n        WorldPosition worldPosition = SWorldPosition.of(location);\n        String worldName = LazyWorldLocation.getWorldName(location);\n\n        for (WarpRecord warpRecord : this.warps) {\n            if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition))\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition) {\n        Preconditions.checkNotNull(worldInfo, \"worldInfo parameter cannot be null\");\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null\");\n\n        String worldName = worldInfo.getName();\n\n        for (WarpRecord warpRecord : this.warps) {\n            if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition))\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public Island.Builder addWarpCategory(String name, int slot, @Nullable ItemStack icon) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        Preconditions.checkArgument(slot >= 0, \"slot must be positive.\");\n        this.warpCategories.add(new WarpCategoryRecord(name, slot, icon));\n        return this;\n    }\n\n    @Override\n    public boolean hasWarpCategory(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null\");\n\n        for (WarpCategoryRecord warpCategoryRecord : this.warpCategories) {\n            if (warpCategoryRecord.name.equals(name))\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public Island.Builder addBankTransaction(BankTransaction bankTransaction) {\n        Preconditions.checkNotNull(bankTransaction, \"bankTransaction parameter cannot be null.\");\n        this.bankTransactions.add(bankTransaction);\n        return this;\n    }\n\n    @Override\n    public List<BankTransaction> getBankTransactions() {\n        return Collections.unmodifiableList(this.bankTransactions);\n    }\n\n    @Override\n    public Island.Builder setPersistentData(byte[] persistentData) {\n        Preconditions.checkNotNull(persistentData, \"persistentData parameter cannot be null.\");\n        this.persistentData = persistentData;\n        return this;\n    }\n\n    @Override\n    public byte[] getPersistentData() {\n        return this.persistentData;\n    }\n\n    @Override\n    public Island build() {\n        if (this.uuid == null)\n            throw new IllegalStateException(\"Cannot create an island with no valid uuid.\");\n        if (this.center == null)\n            throw new IllegalStateException(\"Cannot create an island with no valid location.\");\n\n        return plugin.getFactory().createIsland(this);\n    }\n\n    private static boolean isValidCenter(Location center) {\n        int maxIslandSize = plugin.getSettings().getMaxIslandSize() * 3;\n        return center.getBlockX() % maxIslandSize == 0 && center.getBlockZ() % maxIslandSize == 0 &&\n                plugin.getGrid().getIslandAt(center) == null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpCategoryRecord.java",
    "content": "package com.bgsoftware.superiorskyblock.island.builder;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport org.bukkit.inventory.ItemStack;\n\npublic class WarpCategoryRecord {\n\n    public final String name;\n    public final int slot;\n    @Nullable\n    public final ItemStack icon;\n\n    public WarpCategoryRecord(String name, int slot, @Nullable ItemStack icon) {\n        this.name = name;\n        this.slot = slot;\n        this.icon = icon;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java",
    "content": "package com.bgsoftware.superiorskyblock.island.builder;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport org.bukkit.inventory.ItemStack;\n\npublic class WarpRecord {\n\n    public final String name;\n    public final String category;\n    public final WorldPosition worldPosition;\n    public final String worldName;\n    public final boolean isPrivate;\n    @Nullable\n    public final ItemStack icon;\n\n    public WarpRecord(String name, String category, WorldPosition worldPosition, String worldName, boolean isPrivate, @Nullable ItemStack icon) {\n        this.name = name;\n        this.category = category;\n        this.worldPosition = worldPosition;\n        this.worldName = worldName;\n        this.isPrivate = isPrivate;\n        this.icon = icon;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.island.cache;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey;\nimport com.bgsoftware.superiorskyblock.core.BaseCacheImpl;\n\nimport java.util.function.Function;\n\npublic class IslandCacheImpl implements IslandCache {\n\n    private final BaseCacheImpl<IslandCacheKey<?>> cache = new BaseCacheImpl<>(IslandCacheKey.values());\n\n    private final Island island;\n\n    public IslandCacheImpl(Island island) {\n        this.island = island;\n    }\n\n    @Override\n    public Island getIsland() {\n        return this.island;\n    }\n\n    @Override\n    public <T> T store(IslandCacheKey<T> key, T value) {\n        return this.cache.store(key, value);\n    }\n\n    @Override\n    public <T> T remove(IslandCacheKey<T> key) {\n        return this.cache.remove(key);\n    }\n\n    @Override\n    public <T> T get(IslandCacheKey<T> key) {\n        return this.cache.get(key);\n    }\n\n    @Override\n    public <T> T getOrDefault(IslandCacheKey<T> key, T def) {\n        return this.cache.getOrDefault(key, def);\n    }\n\n    @Override\n    public <T> T computeIfAbsent(IslandCacheKey<T> key, Function<IslandCacheKey<T>, T> mappingFunction) {\n        return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java",
    "content": "package com.bgsoftware.superiorskyblock.island.cache;\n\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey;\nimport org.bukkit.Chunk;\n\nimport java.util.Set;\n\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic class IslandCacheKeys {\n\n    public static final IslandCacheKey<Set<Chunk>> PENDING_LOADED_CHUNKS =\n            (IslandCacheKey<Set<Chunk>>) (IslandCacheKey) register(\"PENDING_LOADED_CHUNKS\", Set.class);\n\n    private IslandCacheKeys() {\n\n    }\n\n    public static void registerCacheKeys() {\n        // Do nothing, only trigger all the register calls\n    }\n\n    public static <T> IslandCacheKey<T> register(String name, Class<T> valueType) {\n        IslandCacheKey.register(name, valueType);\n        return (IslandCacheKey<T>) IslandCacheKey.getByName(name);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.chunk;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.MutableChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\n\nimport java.util.BitSet;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\npublic class DirtyChunksContainer {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final EnumerateMap<Dimension, BitSet> dirtyChunks = new EnumerateMap<>(Dimension.values());\n\n    private final Island island;\n    private final int minChunkX;\n    private final int minChunkZ;\n    private final int chunksInXAxis;\n    private final int totalChunksCount;\n    private final boolean shouldSave;\n\n    public DirtyChunksContainer(Island island) {\n        this.island = island;\n\n        BlockPosition minimum = island.getMinimumPosition();\n        this.minChunkX = minimum.getX() >> 4;\n        this.minChunkZ = minimum.getZ() >> 4;\n\n        BlockPosition maximum = island.getMaximumPosition();\n        int maxChunkX = maximum.getX() >> 4;\n        int maxChunkZ = maximum.getZ() >> 4;\n        int chunksInZAxis = maxChunkZ - this.minChunkZ;\n\n        this.chunksInXAxis = maxChunkX - this.minChunkX;\n        this.totalChunksCount = this.chunksInXAxis * chunksInZAxis;\n\n        this.shouldSave = !island.isSpawn();\n    }\n\n    public Island getIsland() {\n        return island;\n    }\n\n    public boolean isMarkedDirty(ChunkPosition chunkPosition) {\n        int chunkIndex = getChunkIndex(chunkPosition);\n\n        if (chunkIndex < 0)\n            throw new IllegalStateException(\"Chunk is not inside island boundaries: \" + chunkPosition);\n\n        BitSet dirtyChunksBitset = this.dirtyChunks.get(chunkPosition.getWorldsInfo().getDimension());\n\n        return dirtyChunksBitset != null && !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex);\n    }\n\n    public void markEmpty(ChunkPosition chunkPosition, boolean save) {\n        int chunkIndex = getChunkIndex(chunkPosition);\n\n        if (chunkIndex < 0)\n            throw new IllegalStateException(\"Chunk is not inside island boundaries: \" + chunkPosition);\n\n        BitSet dirtyChunksBitset = this.dirtyChunks.get(chunkPosition.getWorldsInfo().getDimension());\n\n        boolean isMarkedDirty = dirtyChunksBitset != null && !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex);\n\n        if (isMarkedDirty) {\n            dirtyChunksBitset.clear(chunkIndex);\n            if (this.shouldSave && save)\n                IslandsDatabaseBridge.saveDirtyChunks(this);\n        }\n    }\n\n    public void markDirty(ChunkPosition chunkPosition, boolean save) {\n        int chunkIndex = getChunkIndex(chunkPosition);\n\n        if (chunkIndex < 0)\n            throw new IllegalStateException(\"Chunk is not inside island boundaries: \" + chunkPosition);\n\n        BitSet dirtyChunksBitset = this.dirtyChunks.computeIfAbsent(chunkPosition.getWorldsInfo().getDimension(),\n                e -> new BitSet(this.totalChunksCount));\n\n        boolean isMarkedDirty = !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex);\n\n        if (!isMarkedDirty) {\n            dirtyChunksBitset.set(chunkIndex);\n            if (this.shouldSave && save)\n                IslandsDatabaseBridge.saveDirtyChunks(this);\n        }\n    }\n\n    public void getDirtyChunks(Consumer<ChunkPosition> consumer) {\n        if (this.dirtyChunks.isEmpty())\n            return;\n\n        MutableChunkPosition mutableChunkPosition = new MutableChunkPosition();\n\n        for (Dimension dimension : Dimension.values()) {\n            BitSet dirtyChunks = this.dirtyChunks.get(dimension);\n            if (dirtyChunks != null && !dirtyChunks.isEmpty()) {\n                WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n                if (worldInfo != null) {\n                    for (int j = dirtyChunks.nextSetBit(0); j >= 0; j = dirtyChunks.nextSetBit(j + 1)) {\n                        int deltaX = j / this.chunksInXAxis;\n                        int deltaZ = j % this.chunksInXAxis;\n                        consumer.accept(mutableChunkPosition.reset(worldInfo, deltaX + this.minChunkX, deltaZ + this.minChunkZ));\n                    }\n                }\n            }\n        }\n\n    }\n\n    private int getChunkIndex(ChunkPosition chunkPosition) {\n        int deltaX = chunkPosition.getX() - this.minChunkX;\n        int deltaZ = chunkPosition.getZ() - this.minChunkZ;\n        return deltaX * this.chunksInXAxis + deltaZ;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.island.IslandNames;\nimport com.bgsoftware.superiorskyblock.island.container.grid.IslandsGrid;\nimport com.bgsoftware.superiorskyblock.island.container.grid.MultiWorldIslandsGrid;\nimport com.bgsoftware.superiorskyblock.island.container.grid.SingleWorldIslandsGrid;\nimport com.bgsoftware.superiorskyblock.island.top.SortingComparators;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata;\nimport com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortPlayerMetadata;\nimport com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortRatingMetadata;\nimport com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortValueMetadata;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class DefaultIslandsContainer implements IslandsContainer {\n\n    private final Map<UUID, Island> islandsByUUID = new ConcurrentHashMap<>();\n    private final Map<String, Island> islandsByNames = new ConcurrentHashMap<>();\n    private IslandsGrid islandsGrid;\n\n    private final Map<SortingType, Synchronized<List<Island>>> sortedIslands = new ConcurrentHashMap<>();\n\n    private final EnumerateSet<SortingType> notifiedValues = new EnumerateSet<>(SortingType.values());\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        this.islandsGrid = plugin.getProviders().hasCustomWorldsSupport() ?\n                new MultiWorldIslandsGrid() : new SingleWorldIslandsGrid();\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.WORLD_PROVIDER_UPDATE_EVENT, this::onWorldsProviderUpdate);\n    }\n\n    @Override\n    public void addIsland(Island island) {\n        addIslandToGrid(island);\n\n        this.islandsByUUID.put(island.getUniqueId(), island);\n        this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island);\n\n        sortedIslands.values().forEach(sortedIslands -> {\n            sortedIslands.write(_sortedIslands -> _sortedIslands.add(island));\n        });\n    }\n\n    private void addIslandToGrid(Island island) {\n        BlockPosition center = island.getCenterPosition();\n        long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ());\n\n        if (plugin.getProviders().hasCustomWorldsSupport()) {\n            // We don't know the logic of the custom worlds support, therefore we add a position\n            // for every possible world, so there won't be issues with detecting islands later.\n            for (Dimension dimension : Dimension.values()) {\n                if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) {\n                    WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n                    if (worldInfo != null)\n                        islandsGrid.addIsland(worldInfo.getName(), packedPos, island);\n                }\n            }\n        } else {\n            islandsGrid.addIsland(null, packedPos, island);\n        }\n    }\n\n    @Override\n    public void removeIsland(Island island) {\n        BlockPosition center = island.getCenterPosition();\n        long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ());\n\n        if (plugin.getProviders().hasCustomWorldsSupport()) {\n            for (Dimension dimension : Dimension.values()) {\n                if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) {\n                    WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension);\n                    if (worldInfo != null)\n                        islandsGrid.removeIslandAt(worldInfo.getName(), packedPos);\n                }\n            }\n        } else {\n            islandsGrid.removeIslandAt(null, packedPos);\n        }\n\n        this.islandsByUUID.remove(island.getUniqueId());\n        this.islandsByNames.remove(IslandNames.getNameForLookup(island.getStrippedName()));\n\n        sortedIslands.values().forEach(sortedIslands -> {\n            sortedIslands.write(_sortedIslands -> _sortedIslands.remove(island));\n        });\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandByUUID(UUID uuid) {\n        return this.islandsByUUID.get(uuid);\n    }\n\n    @Override\n    public Island getIslandByName(String name) {\n        return this.islandsByNames.get(IslandNames.getNameForLookup(name));\n    }\n\n    @Override\n    public void updateIslandName(Island island, String oldName) {\n        Island currentIsland = this.islandsByNames.remove(IslandNames.getNameForLookup(oldName));\n        if (currentIsland == island)\n            this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island);\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandAtPosition(int position, SortingType sortingType) {\n        ensureSortingType(sortingType);\n        return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> {\n            return position < 0 || position >= sortedIslands.size() ? null : sortedIslands.get(position);\n        });\n    }\n\n    @Override\n    public int getIslandPosition(Island island, SortingType sortingType) {\n        ensureSortingType(sortingType);\n        return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> {\n            return sortedIslands.indexOf(island);\n        });\n    }\n\n    @Override\n    public int getIslandsAmount() {\n        return this.islandsByUUID.size();\n    }\n\n    @Nullable\n    @Override\n    public Island getIslandAt(Location location) {\n        Island island = plugin.getProviders().hasCustomWorldsSupport() ?\n                customWorldsSupportIslandLookup(location) : nativeIslandLookup(location);\n        return island == null || !island.isInside(SWorldPosition.of(location)) ? null : island;\n    }\n\n    private Island customWorldsSupportIslandLookup(Location location) {\n        long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ());\n        String worldName = LazyWorldLocation.getWorldName(location);\n        return this.islandsGrid.getIslandAt(worldName, packedPos);\n    }\n\n    private Island nativeIslandLookup(Location location) {\n        // We first check that the world is an islands world.\n        World world = location.getWorld();\n        if (world == null || !plugin.getGrid().isIslandsWorld(world))\n            return null;\n\n        long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ());\n        return this.islandsGrid.getIslandAt(null, packedPos);\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType, Runnable onFinish) {\n        this.sortIslands(sortingType, false, onFinish);\n    }\n\n    @Override\n    public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish) {\n        ensureSortingType(sortingType);\n\n        Synchronized<List<Island>> sortedIslands = this.sortedIslands.get(sortingType);\n\n        if (!forceSort && (sortedIslands.readAndGet(List::size) <= 1 || !notifiedValues.remove(sortingType))) {\n            if (onFinish != null)\n                onFinish.run();\n            return;\n        }\n\n        BukkitExecutor.ensureAsync(() -> sortIslandsInternal(sortingType, onFinish));\n    }\n\n    @Override\n    public void notifyChange(SortingType sortingType, Island island) {\n        notifiedValues.add(sortingType);\n    }\n\n    @Override\n    public List<Island> getSortedIslands(SortingType sortingType) {\n        ensureSortingType(sortingType);\n        return this.sortedIslands.get(sortingType).readAndGet(sortedIslands ->\n                new SequentialListBuilder<Island>().build(sortedIslands));\n    }\n\n    @Override\n    public List<Island> getIslandsUnsorted() {\n        return new SequentialListBuilder<Island>().build(this.islandsByUUID.values());\n    }\n\n    @Override\n    public void addSortingType(SortingType sortingType, boolean sort) {\n        Preconditions.checkArgument(!sortedIslands.containsKey(sortingType), \"You cannot register an existing sorting type to the database.\");\n        sortIslandsInternal(sortingType, null);\n    }\n\n    private void ensureSortingType(SortingType sortingType) {\n        Preconditions.checkState(sortedIslands.containsKey(sortingType), \"The sorting-type \" + sortingType + \" doesn't exist in the database. Please contact author!\");\n    }\n\n    private void sortIslandsInternal(SortingType sortingType, @Nullable Runnable onFinish) {\n        List<Island> existingIslands = new LinkedList<>(islandsByUUID.values());\n        existingIslands.removeIf(Island::isIgnored);\n\n        List<Island> sortedIslands;\n\n        if (existingIslands.size() <= 1) {\n            sortedIslands = existingIslands;\n        } else try {\n            if (sortingType == SortingTypes.BY_LEVEL || sortingType == SortingTypes.BY_WORTH ||\n                    sortingType == SortingTypes.BY_PLAYERS || sortingType == SortingTypes.BY_RATING) {\n                sortedIslands = sortIslandsBuiltinSortingType(existingIslands, sortingType);\n            } else {\n                sortedIslands = existingIslands;\n                sortedIslands.sort(sortingType);\n            }\n        } catch (Throwable error) {\n            Log.warn(\"An error occurred while sorting islands for sorting-type \", sortingType.getName(), \":\");\n            throw error;\n        }\n\n        this.sortedIslands.put(sortingType, Synchronized.of(sortedIslands));\n\n        if (onFinish != null)\n            onFinish.run();\n    }\n\n    private List<Island> sortIslandsBuiltinSortingType(List<Island> existingIslands, SortingType sortingType) {\n        List<IslandSortMetadata<?>> islandMetadatas = new LinkedList<>();\n\n        if (sortingType == SortingTypes.BY_WORTH)\n            existingIslands.forEach(island -> islandMetadatas.add(new IslandSortValueMetadata(island, island.getWorth())));\n        else if (sortingType == SortingTypes.BY_LEVEL)\n            existingIslands.forEach(island -> islandMetadatas.add(new IslandSortValueMetadata(island, island.getIslandLevel())));\n        else if (sortingType == SortingTypes.BY_RATING)\n            existingIslands.forEach(island -> islandMetadatas.add(new IslandSortRatingMetadata(island)));\n        else /* BY_PLAYERS */\n            existingIslands.forEach(island -> islandMetadatas.add(new IslandSortPlayerMetadata(island)));\n\n        if (islandMetadatas.size() > 1) {\n            islandMetadatas.sort(SortingComparators.ISLAND_METADATA_COMPARATOR);\n        }\n\n        existingIslands.clear();\n        islandMetadatas.forEach(islandMetadata -> existingIslands.add(islandMetadata.getIsland()));\n\n        return existingIslands;\n    }\n\n    private void onWorldsProviderUpdate() {\n        if (plugin.getProviders().hasCustomWorldsSupport() && islandsGrid instanceof SingleWorldIslandsGrid) {\n            // We need to upgrade the grid to a MultiWorldIslandsGrid\n            this.islandsGrid = new MultiWorldIslandsGrid();\n            // Re-add all registered islands\n            for (Island island : this.islandsByUUID.values()) {\n                addIslandToGrid(island);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java",
    "content": "package com.bgsoftware.superiorskyblock.island.container.grid;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\npublic interface IslandsGrid {\n\n    void addIsland(String worldName, long packedPos, Island island);\n\n    @Nullable\n    Island removeIslandAt(String worldName, long packedPos);\n\n    @Nullable\n    Island getIslandAt(String worldName, long packedPos);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java",
    "content": "package com.bgsoftware.superiorskyblock.island.container.grid;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class MultiWorldIslandsGrid implements IslandsGrid {\n\n    private final Map<String, SingleWorldIslandsGrid> store = new ConcurrentHashMap<>();\n\n    @Override\n    public void addIsland(String worldName, long packedPos, Island island) {\n        this.store.computeIfAbsent(worldName, d -> new SingleWorldIslandsGrid())\n                .addIsland(null, packedPos, island);\n    }\n\n    @Override\n    public Island removeIslandAt(String worldName, long packedPos) {\n        SingleWorldIslandsGrid worldGrid = this.store.get(worldName);\n        return worldGrid == null ? null : worldGrid.removeIslandAt(null, packedPos);\n    }\n\n    @Override\n    public Island getIslandAt(String worldName, long packedPos) {\n        SingleWorldIslandsGrid worldGrid = this.store.get(worldName);\n        return worldGrid == null ? null : worldGrid.getIslandAt(null, packedPos);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java",
    "content": "package com.bgsoftware.superiorskyblock.island.container.grid;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView;\n\nimport java.util.concurrent.locks.StampedLock;\n\npublic class SingleWorldIslandsGrid implements IslandsGrid {\n\n    private final Long2ObjectMapView<Island> store = CollectionsFactory.createLong2ObjectLinkedHashMap();\n    private final StampedLock lock = new StampedLock();\n\n    @Override\n    public void addIsland(String unused, long packedPos, Island island) {\n        long stamp = this.lock.writeLock();\n        try {\n            this.store.put(packedPos, island);\n        } finally {\n            this.lock.unlockWrite(stamp);\n        }\n    }\n\n    @Override\n    public Island removeIslandAt(String unused, long packedPos) {\n        long stamp = this.lock.writeLock();\n        Island oldValue;\n        try {\n            oldValue = this.store.remove(packedPos);\n        } finally {\n            this.lock.unlockWrite(stamp);\n        }\n        return oldValue;\n    }\n\n    @Override\n    public Island getIslandAt(String unused, long packedPos) {\n        long stamp = this.lock.tryOptimisticRead();\n        Island island = this.store.get(packedPos);\n\n        // Validate that no write occurred while reading\n        if (!lock.validate(stamp)) {\n            // Fallback to a proper read lock\n            stamp = this.lock.readLock();\n            try {\n                island = this.store.get(packedPos);\n            } finally {\n                this.lock.unlockRead(stamp);\n            }\n        }\n        return island;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.island.flag;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\n\nimport java.util.Comparator;\nimport java.util.Locale;\n\npublic class IslandFlags {\n\n    public static final IslandFlag ALWAYS_DAY = register(\"ALWAYS_DAY\");\n    public static final IslandFlag ALWAYS_MIDDLE_DAY = register(\"ALWAYS_MIDDLE_DAY\");\n    public static final IslandFlag ALWAYS_NIGHT = register(\"ALWAYS_NIGHT\");\n    public static final IslandFlag ALWAYS_MIDDLE_NIGHT = register(\"ALWAYS_MIDDLE_NIGHT\");\n    public static final IslandFlag ALWAYS_RAIN = register(\"ALWAYS_RAIN\");\n    public static final IslandFlag ALWAYS_SHINY = register(\"ALWAYS_SHINY\");\n    public static final IslandFlag CREEPER_EXPLOSION = register(\"CREEPER_EXPLOSION\");\n    public static final IslandFlag CROPS_GROWTH = register(\"CROPS_GROWTH\");\n    public static final IslandFlag EGG_LAY = register(\"EGG_LAY\");\n    public static final IslandFlag ENDERMAN_GRIEF = register(\"ENDERMAN_GRIEF\");\n    public static final IslandFlag FIRE_SPREAD = register(\"FIRE_SPREAD\");\n    public static final IslandFlag GHAST_FIREBALL = register(\"GHAST_FIREBALL\");\n    public static final IslandFlag LAVA_FLOW = register(\"LAVA_FLOW\");\n    public static final IslandFlag PVP = register(\"PVP\");\n    public static final IslandFlag TNT_EXPLOSION = register(\"TNT_EXPLOSION\");\n    public static final IslandFlag TREE_GROWTH = register(\"TREE_GROWTH\");\n    public static final IslandFlag WATER_FLOW = register(\"WATER_FLOW\");\n    public static final IslandFlag WITHER_EXPLOSION = register(\"WITHER_EXPLOSION\");\n\n    private static String ALL_FLAG_NAMES;\n    private static int KNOWN_FLAGS_COUNT;\n\n    private IslandFlags() {\n\n    }\n\n    public static void registerFlags() {\n        // Do nothing, only trigger all the register calls\n    }\n\n    public static String getFlagsNames() {\n        if (ALL_FLAG_NAMES == null || KNOWN_FLAGS_COUNT != IslandFlag.values().size()) {\n            ALL_FLAG_NAMES = Formatters.COMMA_FORMATTER.format(IslandFlag.values().stream()\n                    .sorted(Comparator.comparing(IslandFlag::getName))\n                    .map(islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH)));\n            KNOWN_FLAGS_COUNT = IslandFlag.values().size();\n        }\n\n        return ALL_FLAG_NAMES;\n    }\n\n    private static IslandFlag register(String name) {\n        IslandFlag.register(name);\n        return IslandFlag.getByName(name);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java",
    "content": "package com.bgsoftware.superiorskyblock.island.notifications;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\n\nimport java.util.Collections;\n\npublic class IslandNotifications {\n\n    private IslandNotifications() {\n\n    }\n\n    public static void notifyPlayerQuit(SuperiorPlayer superiorPlayer) {\n        superiorPlayer.updateLastTimeStatus();\n\n        Island island = superiorPlayer.getIsland();\n\n        if (island == null)\n            return;\n\n        IslandUtils.sendMessage(island, Message.PLAYER_QUIT_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName());\n\n        boolean anyOnline = island.getIslandMembers(true).stream().anyMatch(islandMember ->\n                islandMember != superiorPlayer && islandMember.isOnline());\n\n        if (!anyOnline) {\n            island.setLastTimeUpdate(System.currentTimeMillis() / 1000);\n            island.setCurrentlyActive(false);\n        }\n    }\n\n    public static void notifyPlayerJoin(SuperiorPlayer superiorPlayer) {\n        superiorPlayer.updateLastTimeStatus();\n\n        Island island = superiorPlayer.getIsland();\n        if (island == null)\n            return;\n\n        IslandUtils.sendMessage(island, Message.PLAYER_JOIN_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName());\n        island.updateLastTime();\n        island.setCurrentlyActive(true);\n\n        // Give interest as soon as the owner joins the server\n        if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled() && superiorPlayer == island.getOwner()) {\n            int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval();\n            long currentTime = System.currentTimeMillis() / 1000;\n            long ticksToNextInterest = (bankInterestInterval - (currentTime - island.getLastInterestTime())) * 20;\n            if (ticksToNextInterest <= 0) {\n                island.giveInterest(false);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/preview/DefaultIslandPreviews.java",
    "content": "package com.bgsoftware.superiorskyblock.island.preview;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class DefaultIslandPreviews implements IslandPreviews {\n\n    private final Map<UUID, IslandPreview> islandPreviews = new ConcurrentHashMap<>();\n\n    @Override\n    public void startIslandPreview(IslandPreview islandPreview) {\n        this.islandPreviews.put(islandPreview.getPlayer().getUniqueId(), islandPreview);\n    }\n\n    @Override\n    public IslandPreview endIslandPreview(SuperiorPlayer superiorPlayer) {\n        return this.islandPreviews.remove(superiorPlayer.getUniqueId());\n    }\n\n    @Override\n    public IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer) {\n        return this.islandPreviews.get(superiorPlayer.getUniqueId());\n    }\n\n    @Override\n    public List<IslandPreview> getActivePreviews() {\n        return new SequentialListBuilder<IslandPreview>().build(this.islandPreviews.values());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/preview/IslandPreviews.java",
    "content": "package com.bgsoftware.superiorskyblock.island.preview;\n\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.util.List;\n\npublic interface IslandPreviews {\n\n    void startIslandPreview(IslandPreview islandPreview);\n\n    IslandPreview endIslandPreview(SuperiorPlayer superiorPlayer);\n\n    IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer);\n\n    List<IslandPreview> getActivePreviews();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java",
    "content": "package com.bgsoftware.superiorskyblock.island.preview;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\npublic class SIslandPreview implements IslandPreview {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final SuperiorPlayer superiorPlayer;\n    private final Location previewLocation;\n    private final Schematic schematic;\n    private final String islandName;\n    private final GameMode previousGameMode;\n\n    public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, Schematic schematic, String islandName, GameMode previousGameMode) {\n        this.superiorPlayer = superiorPlayer;\n        this.previewLocation = previewLocation;\n        this.schematic = schematic;\n        this.islandName = islandName;\n        this.previousGameMode = previousGameMode;\n\n        Player player = superiorPlayer.asPlayer();\n        Preconditions.checkNotNull(player, \"Cannot start island preview to an offline player.\");\n\n        PlayerChat.listen(player, message -> {\n            if (message.equalsIgnoreCase(Message.ISLAND_PREVIEW_CONFIRM_TEXT.getMessage(superiorPlayer.getUserLocale()))) {\n                handleConfirm();\n                return true;\n            } else if (message.equalsIgnoreCase(Message.ISLAND_PREVIEW_CANCEL_TEXT.getMessage(superiorPlayer.getUserLocale()))) {\n                handleCancel();\n                return true;\n            }\n\n            return false;\n        });\n    }\n\n    @Override\n    public SuperiorPlayer getPlayer() {\n        return superiorPlayer;\n    }\n\n    @Override\n    public Location getLocation() {\n        return previewLocation.clone();\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        if (location != null) {\n            location.setWorld(this.previewLocation.getWorld());\n            location.setX(this.previewLocation.getX());\n            location.setY(this.previewLocation.getY());\n            location.setZ(this.previewLocation.getZ());\n            location.setYaw(this.previewLocation.getYaw());\n            location.setPitch(this.previewLocation.getPitch());\n        }\n\n        return location;\n    }\n\n    @Override\n    public String getSchematic() {\n        return this.schematic.getName();\n    }\n\n    @Override\n    public String getIslandName() {\n        return this.islandName;\n    }\n\n    @Override\n    public GameMode getPreviousGameMode() {\n        return this.previousGameMode;\n    }\n\n    @Override\n    public void handleConfirm() {\n        MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(this.schematic);\n        MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView());\n        superiorPlayer.runIfOnline(PlayerChat::remove);\n    }\n\n    @Override\n    public void handleCancel() {\n        plugin.getGrid().cancelIslandPreview(superiorPlayer);\n        Message.ISLAND_PREVIEW_CANCEL.send(superiorPlayer);\n    }\n\n    @Override\n    public void handleEscape() {\n        plugin.getGrid().cancelIslandPreview(superiorPlayer);\n        Message.ISLAND_PREVIEW_CANCEL_DISTANCE.send(superiorPlayer);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java",
    "content": "package com.bgsoftware.superiorskyblock.island.privilege;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\n\nimport java.util.Comparator;\nimport java.util.Locale;\nimport java.util.Objects;\n\npublic class IslandPrivileges {\n\n    // Builtin privileges\n    public static final IslandPrivilege ALL = register(\"ALL\");\n    public static final IslandPrivilege ANIMAL_BREED = register(\"ANIMAL_BREED\");\n    public static final IslandPrivilege ANIMAL_SHEAR = register(\"ANIMAL_SHEAR\");\n    public static final IslandPrivilege BAN_MEMBER = register(\"BAN_MEMBER\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege BREAK = register(\"BREAK\");\n    public static final IslandPrivilege BRUSH = register(\"BRUSH\", ServerVersion.isAtLeast(ServerVersion.v1_20));\n    public static final IslandPrivilege BUILD = register(\"BUILD\");\n    public static final IslandPrivilege CHANGE_NAME = register(\"CHANGE_NAME\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege CHORUS_FRUIT = register(\"CHORUS_FRUIT\", ServerVersion.isAtLeast(ServerVersion.v1_9));\n    public static final IslandPrivilege CLOSE_BYPASS = register(\"CLOSE_BYPASS\");\n    public static final IslandPrivilege CLOSE_ISLAND = register(\"CLOSE_ISLAND\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege COOP_MEMBER = register(\"COOP_MEMBER\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege DELETE_WARP = register(\"DELETE_WARP\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege DEMOTE_MEMBERS = register(\"DEMOTE_MEMBERS\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege DEPOSIT_MONEY = register(\"DEPOSIT_MONEY\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege DISBAND_ISLAND = register(\"DISBAND_ISLAND\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege DISCORD_SHOW = register(\"DISCORD_SHOW\");\n    public static final IslandPrivilege DROP_ITEMS = register(\"DROP_ITEMS\");\n    public static final IslandPrivilege DYE_SHEEP = register(\"DYE_SHEEP\");\n    public static final IslandPrivilege ENDER_PEARL = register(\"ENDER_PEARL\");\n    public static final IslandPrivilege ENTITY_RIDE = register(\"ENTITY_RIDE\");\n    public static final IslandPrivilege EXPEL_BYPASS = register(\"EXPEL_BYPASS\");\n    public static final IslandPrivilege EXPEL_PLAYERS = register(\"EXPEL_PLAYERS\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege FERTILIZE = register(\"FERTILIZE\");\n    public static final IslandPrivilege FISH = register(\"FISH\");\n    public static final IslandPrivilege FLY = register(\"FLY\");\n    public static final IslandPrivilege IGNITE_CREEPER = register(\"IGNITE_CREEPER\");\n    public static final IslandPrivilege INVITE_MEMBER = register(\"INVITE_MEMBER\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege ISLAND_CHEST = register(\"ISLAND_CHEST\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege KICK_MEMBER = register(\"KICK_MEMBER\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege LEASH = register(\"LEASH\");\n    public static final IslandPrivilege MINECART_ENTER = register(\"MINECART_ENTER\");\n    public static final IslandPrivilege MINECART_OPEN = register(\"MINECART_OPEN\");\n    public static final IslandPrivilege NAME_ENTITY = register(\"NAME_ENTITY\");\n    public static final IslandPrivilege OPEN_ISLAND = register(\"OPEN_ISLAND\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege PAYPAL_SHOW = register(\"PAYPAL_SHOW\");\n    public static final IslandPrivilege PICKUP_DROPS = register(\"PICKUP_DROPS\");\n    @Nullable\n    public static final IslandPrivilege PROMOTE_MEMBERS = register(\"PROMOTE_MEMBERS\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege RANKUP = register(\"RANKUP\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege RATINGS_SHOW = register(\"RATINGS_SHOW\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SADDLE_ENTITY = register(\"SADDLE_ENTITY\");\n    @Nullable\n    public static final IslandPrivilege SCULK_SENSOR = register(\"SCULK_SENSOR\", ServerVersion.isAtLeast(ServerVersion.v1_17));\n    public static final IslandPrivilege SET_BIOME = register(\"SET_BIOME\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_DISCORD = register(\"SET_DISCORD\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_HOME = register(\"SET_HOME\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_PAYPAL = register(\"SET_PAYPAL\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_PERMISSION = register(\"SET_PERMISSION\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_ROLE = register(\"SET_ROLE\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_SETTINGS = register(\"SET_SETTINGS\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SET_WARP = register(\"SET_WARP\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege SPAWNER_BREAK = register(\"SPAWNER_BREAK\");\n    @Nullable\n    public static final IslandPrivilege UNCOOP_MEMBER = register(\"UNCOOP_MEMBER\", IslandPrivilege.Type.COMMAND);\n    public static final IslandPrivilege VALUABLE_BREAK = register(\"VALUABLE_BREAK\");\n    public static final IslandPrivilege VILLAGER_TRADING = register(\"VILLAGER_TRADING\");\n    public static final IslandPrivilege WIND_CHARGE = register(\"WIND_CHARGE\", ServerVersion.isAtLeast(ServerVersion.v1_21));\n    public static final IslandPrivilege WITHDRAW_MONEY = register(\"WITHDRAW_MONEY\", IslandPrivilege.Type.COMMAND);\n\n    // Privileges from configurations\n    @Nullable\n    public static IslandPrivilege CONFIG_VAULT_INTERACT;\n\n    private static String ALL_PRIVILEGE_NAMES;\n    private static int KNOWN_PRIVILEGES_COUNT;\n\n    private IslandPrivileges() {\n\n    }\n\n    public static void registerPrivileges() {\n        // Do nothing, only trigger all the register calls\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, IslandPrivileges::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        CONFIG_VAULT_INTERACT = null;\n\n        SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n        Key vaultKey = Keys.ofMaterialAndData(\"VAULT\");\n        CONFIG_VAULT_INTERACT = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(vaultKey);\n    }\n\n    public static String getPrivilegesNames() {\n        if (ALL_PRIVILEGE_NAMES == null || KNOWN_PRIVILEGES_COUNT != IslandPrivilege.values().size()) {\n            ALL_PRIVILEGE_NAMES = Formatters.COMMA_FORMATTER.format(IslandPrivilege.values().stream()\n                    .sorted(Comparator.comparing(IslandPrivilege::getName))\n                    .map(islandPrivilege -> islandPrivilege.getName().toLowerCase(Locale.ENGLISH)));\n            KNOWN_PRIVILEGES_COUNT = IslandPrivilege.values().size();\n        }\n\n        return ALL_PRIVILEGE_NAMES;\n    }\n\n    @NotNull\n    private static IslandPrivilege register(String name) {\n        return Objects.requireNonNull(register(name, true));\n    }\n\n    @NotNull\n    private static IslandPrivilege register(String name, IslandPrivilege.Type type) {\n        return Objects.requireNonNull(register(name, type, true));\n    }\n\n    @Nullable\n    private static IslandPrivilege register(String name, boolean registerCheck) {\n        return register(name, IslandPrivilege.Type.ACTION, registerCheck);\n    }\n\n    @Nullable\n    private static IslandPrivilege register(String name, IslandPrivilege.Type type, boolean registerCheck) {\n        if (!registerCheck)\n            return null;\n\n        IslandPrivilege.register(name, type);\n        return IslandPrivilege.getByName(name);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/privilege/PlayerPrivilegeNode.java",
    "content": "package com.bgsoftware.superiorskyblock.island.privilege;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.google.common.base.Preconditions;\n\npublic class PlayerPrivilegeNode extends PrivilegeNodeAbstract {\n\n    protected final SuperiorPlayer superiorPlayer;\n    protected Island island;\n\n    public PlayerPrivilegeNode(SuperiorPlayer superiorPlayer, Island island) {\n        this.superiorPlayer = superiorPlayer;\n        this.island = island;\n    }\n\n    public PlayerPrivilegeNode(SuperiorPlayer superiorPlayer, Island island, String permissions) {\n        this.superiorPlayer = superiorPlayer;\n        this.island = island;\n        setPermissions(permissions, false);\n    }\n\n    private PlayerPrivilegeNode(@Nullable EnumerateMap<IslandPrivilege, PrivilegeStatus> privileges,\n                                SuperiorPlayer superiorPlayer, Island island) {\n        super(privileges);\n        this.superiorPlayer = superiorPlayer;\n        this.island = island;\n    }\n\n    public void setIsland(Island island) {\n        this.island = island;\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n        return getStatus(IslandPrivileges.ALL) == PrivilegeStatus.ENABLED || getStatus(islandPrivilege) == PrivilegeStatus.ENABLED;\n    }\n\n    @Override\n    public PrivilegeNodeAbstract clone() {\n        return new PlayerPrivilegeNode(privileges, superiorPlayer, island);\n    }\n\n    public void loadPrivilege(IslandPrivilege islandPrivilege, byte status) {\n        privileges.put(islandPrivilege, PrivilegeStatus.of(status));\n    }\n\n    protected PrivilegeStatus getStatus(IslandPrivilege islandPrivilege) {\n        PrivilegeStatus cachedStatus = privileges.getOrDefault(islandPrivilege, PrivilegeStatus.DEFAULT);\n\n        if (cachedStatus != PrivilegeStatus.DEFAULT)\n            return cachedStatus;\n\n        PlayerRole playerRole = island.isMember(superiorPlayer) ? superiorPlayer.getPlayerRole() :\n                island.isCoop(superiorPlayer) ? SPlayerRole.coopRole() : SPlayerRole.guestRole();\n\n        return island.hasPermission(playerRole, islandPrivilege) ? PrivilegeStatus.ENABLED : PrivilegeStatus.DISABLED;\n    }\n\n    public static class EmptyPlayerPermissionNode extends PlayerPrivilegeNode {\n\n        public static final EmptyPlayerPermissionNode INSTANCE;\n\n        static {\n            INSTANCE = new EmptyPlayerPermissionNode();\n        }\n\n        EmptyPlayerPermissionNode() {\n            this(null, null);\n        }\n\n        EmptyPlayerPermissionNode(SuperiorPlayer superiorPlayer, Island island) {\n            super(null, superiorPlayer, island);\n        }\n\n        @Override\n        public boolean hasPermission(IslandPrivilege islandPrivilege) {\n            Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n            return superiorPlayer != null && island != null && super.hasPermission(islandPrivilege);\n        }\n\n        @Override\n        protected PrivilegeStatus getStatus(IslandPrivilege islandPrivilege) {\n            PlayerRole playerRole = island.isMember(superiorPlayer) ? superiorPlayer.getPlayerRole() : island.isCoop(superiorPlayer) ? SPlayerRole.coopRole() : SPlayerRole.guestRole();\n\n            if (island.hasPermission(playerRole, islandPrivilege))\n                return PrivilegeStatus.ENABLED;\n\n            return PrivilegeStatus.DISABLED;\n        }\n\n        @Override\n        public void setPermission(IslandPrivilege permission, boolean value) {\n            // Do nothing.\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/privilege/PrivilegeNodeAbstract.java",
    "content": "package com.bgsoftware.superiorskyblock.island.privilege;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PermissionNode;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Map;\n\npublic abstract class PrivilegeNodeAbstract implements PermissionNode {\n\n    protected final EnumerateMap<IslandPrivilege, PrivilegeStatus> privileges;\n\n    protected PrivilegeNodeAbstract() {\n        this.privileges = new EnumerateMap<>(IslandPrivilege.values());\n    }\n\n    protected PrivilegeNodeAbstract(EnumerateMap<IslandPrivilege, PrivilegeStatus> privileges) {\n        this.privileges = new EnumerateMap<>(privileges);\n    }\n\n    protected void setPermissions(@Nullable String permissions, boolean checkDefaults) {\n        if (Text.isBlank(permissions))\n            return;\n\n        String[] permission = permissions.split(\";\");\n        for (String perm : permission) {\n            String[] permissionSections = perm.split(\":\");\n            try {\n                IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permissionSections[0]);\n                if (permissionSections.length == 2) {\n                    privileges.put(islandPrivilege, PrivilegeStatus.of(permissionSections[1]));\n                } else {\n                    if (!checkDefaults || !isDefault(islandPrivilege))\n                        privileges.put(islandPrivilege, PrivilegeStatus.ENABLED);\n                }\n            } catch (NullPointerException ignored) {\n                // Ignored - invalid privilege.\n            } catch (Exception error) {\n                Log.error(error, \"An unexpected error while loading permissions for '\", perm, \"':\");\n            }\n        }\n    }\n\n    @Override\n    public abstract boolean hasPermission(IslandPrivilege permission);\n\n    @Override\n    public void setPermission(IslandPrivilege islandPrivilege, boolean value) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n        this.privileges.put(islandPrivilege, value ? PrivilegeStatus.ENABLED : PrivilegeStatus.DISABLED);\n    }\n\n    @Override\n    public Map<IslandPrivilege, Boolean> getCustomPermissions() {\n        return this.privileges.collect(IslandPrivilege.values(),\n                privilegeStatus -> privilegeStatus == PrivilegeStatus.ENABLED);\n    }\n\n    @Override\n    public abstract PrivilegeNodeAbstract clone();\n\n    protected boolean isDefault(IslandPrivilege islandPrivilege) {\n        return false;\n    }\n\n    protected enum PrivilegeStatus {\n\n        ENABLED,\n        DISABLED,\n        DEFAULT;\n\n        static PrivilegeStatus of(String value) throws IllegalArgumentException {\n            switch (value) {\n                case \"0\":\n                    return DISABLED;\n                case \"1\":\n                    return ENABLED;\n                default:\n                    return valueOf(value);\n            }\n        }\n\n        static PrivilegeStatus of(byte value) throws IllegalArgumentException {\n            switch (value) {\n                case 0:\n                    return DISABLED;\n                case 1:\n                    return ENABLED;\n                default:\n                    throw new IllegalArgumentException(\"Invalid privilege status: \" + value);\n            }\n        }\n\n        @Override\n        public String toString() {\n            switch (this) {\n                case ENABLED:\n                    return \"1\";\n                case DISABLED:\n                    return \"0\";\n                default:\n                    return name();\n            }\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/privilege/RolePrivilegeNode.java",
    "content": "package com.bgsoftware.superiorskyblock.island.privilege;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.core.Text;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.google.common.base.Preconditions;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class RolePrivilegeNode extends PrivilegeNodeAbstract {\n\n    @Nullable\n    private final SPlayerRole playerRole;\n    private final List<RolePrivilegeNode> linkedNodes = new LinkedList<>();\n\n    public RolePrivilegeNode(@Nullable SPlayerRole playerRole, @Nullable RolePrivilegeNode linkedNode) {\n        this(playerRole, linkedNode, null);\n    }\n\n    public RolePrivilegeNode(@Nullable SPlayerRole playerRole, @Nullable RolePrivilegeNode linkedNode, @Nullable String permissions) {\n        this.playerRole = playerRole;\n        if (linkedNode != null)\n            this.linkedNodes.add(linkedNode);\n        if (!Text.isBlank(permissions))\n            BukkitExecutor.sync(() -> setPermissions(permissions, playerRole != null), 1L);\n    }\n\n    private RolePrivilegeNode(EnumerateMap<IslandPrivilege, PrivilegeStatus> privileges,\n                              @Nullable SPlayerRole playerRole, List<RolePrivilegeNode> linkedNodes) {\n        super(privileges);\n        this.playerRole = playerRole;\n        for (RolePrivilegeNode linkedNode : linkedNodes)\n            this.linkedNodes.add(linkedNode.clone());\n    }\n\n    public void linkNode(RolePrivilegeNode otherNode) {\n        this.linkedNodes.add(otherNode);\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n\n        PrivilegeStatus status = getStatus(islandPrivilege);\n\n        if (status != PrivilegeStatus.DEFAULT) {\n            return status == PrivilegeStatus.ENABLED;\n        }\n\n        for (RolePrivilegeNode linkedNode : this.linkedNodes) {\n            status = linkedNode.getStatus(islandPrivilege);\n\n            if (status != PrivilegeStatus.DEFAULT) {\n                return status == PrivilegeStatus.ENABLED;\n            }\n        }\n\n        return playerRole != null && playerRole.getDefaultPermissions().hasPermission(islandPrivilege);\n    }\n\n    @Override\n    public void setPermission(IslandPrivilege islandPrivilege, boolean value) {\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege parameter cannot be null.\");\n        setPermission(islandPrivilege, value, true);\n    }\n\n    @Override\n    public RolePrivilegeNode clone() {\n        return new RolePrivilegeNode(privileges, playerRole, linkedNodes);\n    }\n\n    @Override\n    protected boolean isDefault(IslandPrivilege islandPrivilege) {\n        if (playerRole != null) {\n            return playerRole.getDefaultPermissions().isDefault(islandPrivilege);\n        }\n\n        for (RolePrivilegeNode linkedNode : this.linkedNodes) {\n            if (linkedNode.isDefault(islandPrivilege))\n                return true;\n        }\n\n        return privileges.containsKey(islandPrivilege);\n    }\n\n    public PrivilegeStatus getStatus(IslandPrivilege permission) {\n        return privileges.getOrDefault(permission, PrivilegeStatus.DEFAULT);\n    }\n\n    public void setPermission(IslandPrivilege permission, boolean value, boolean keepDisable) {\n        if (!value && !keepDisable) {\n            privileges.remove(permission);\n        } else {\n            super.setPermission(permission, value);\n        }\n\n        for (RolePrivilegeNode linkedNode : this.linkedNodes)\n            linkedNode.setPermission(permission, false, false);\n    }\n\n    @Override\n    public String toString() {\n        return \"RolePermissionNode\" + privileges;\n    }\n\n    public static class EmptyRolePermissionNode extends RolePrivilegeNode {\n\n        public static final EmptyRolePermissionNode INSTANCE;\n\n        static {\n            INSTANCE = new EmptyRolePermissionNode();\n        }\n\n        EmptyRolePermissionNode() {\n            super(null, null);\n        }\n\n        @Override\n        public boolean hasPermission(IslandPrivilege permission) {\n            return false;\n        }\n\n        @Override\n        public void setPermission(IslandPrivilege permission, boolean value) {\n            // Do nothing.\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/purge/DefaultIslandsPurger.java",
    "content": "package com.bgsoftware.superiorskyblock.island.purge;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class DefaultIslandsPurger implements IslandsPurger {\n\n    private final Set<Island> scheduledIslands = new HashSet<>();\n\n    @Override\n    public void scheduleIslandPurge(Island island) {\n        this.scheduledIslands.add(island);\n    }\n\n    @Override\n    public void unscheduleIslandPurge(Island island) {\n        this.scheduledIslands.remove(island);\n    }\n\n    @Override\n    public boolean isIslandPurgeScheduled(Island island) {\n        return this.scheduledIslands.contains(island);\n    }\n\n    @Override\n    public List<Island> getScheduledPurgedIslands() {\n        return new SequentialListBuilder<Island>().build(this.scheduledIslands);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/purge/IslandsPurger.java",
    "content": "package com.bgsoftware.superiorskyblock.island.purge;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.util.List;\n\npublic interface IslandsPurger {\n\n    void scheduleIslandPurge(Island island);\n\n    void unscheduleIslandPurge(Island island);\n\n    boolean isIslandPurgeScheduled(Island island);\n\n    List<Island> getScheduledPurgedIslands();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.island.role;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.RolesManager;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.island.role.container.RolesContainer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class RolesManagerImpl extends Manager implements RolesManager {\n\n    private static final int GUEST_ROLE_INDEX = -2;\n    private static final int COOP_ROLE_INDEX = -1;\n    private final RolesContainer rolesContainer;\n    private int lastRole = Integer.MIN_VALUE;\n\n    public RolesManagerImpl(SuperiorSkyblockPlugin plugin, RolesContainer rolesContainer) {\n        super(plugin);\n        this.rolesContainer = rolesContainer;\n    }\n\n    @Override\n    public void loadData() throws ManagerLoadException {\n        this.rolesContainer.clearRoles();\n\n        ConfigurationSection rolesSection = plugin.getSettings().getIslandRoles().getSection();\n\n        ConfigurationSection guestSection = rolesSection.getConfigurationSection(\"guest\");\n\n        if (guestSection == null)\n            throw new ManagerLoadException(\"Missing \\\"guest\\\" section for island roles\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        ConfigurationSection coopSection = rolesSection.getConfigurationSection(\"coop\");\n\n        if (coopSection == null)\n            throw new ManagerLoadException(\"Missing \\\"coop\\\" section for island roles\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        SPlayerRole guestsRole = loadRole(guestSection, GUEST_ROLE_INDEX, null);\n        SPlayerRole coopRole = loadRole(coopSection, COOP_ROLE_INDEX, guestsRole);\n\n        ConfigurationSection laddersSection = rolesSection.getConfigurationSection(\"ladder\");\n\n        if (laddersSection == null)\n            throw new ManagerLoadException(\"Missing \\\"ladder\\\" section for island roles\", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        List<ConfigurationSection> rolesByWeight = new LinkedList<>();\n        for (String roleSectionName : laddersSection.getKeys(false))\n            rolesByWeight.add(laddersSection.getConfigurationSection(roleSectionName));\n        rolesByWeight.sort(Comparator.comparingInt(o -> o.getInt(\"weight\", -1)));\n\n        SPlayerRole previousRole = coopRole;\n        for (ConfigurationSection roleSection : rolesByWeight)\n            previousRole = loadRole(roleSection, previousRole.getWeight() + 1, previousRole);\n\n        SPlayerRole.refreshRoles();\n    }\n\n    @Override\n    @Nullable\n    public PlayerRole getPlayerRole(int index) {\n        return this.rolesContainer.getPlayerRole(index);\n    }\n\n    @Override\n    @Nullable\n    public PlayerRole getPlayerRoleFromId(int id) {\n        return this.rolesContainer.getPlayerRoleFromId(id);\n    }\n\n    @Override\n    public PlayerRole getPlayerRole(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.rolesContainer.getPlayerRole(name);\n    }\n\n    @Override\n    public PlayerRole getDefaultRole() {\n        return getPlayerRole(0);\n    }\n\n    @Override\n    public PlayerRole getLastRole() {\n        return getPlayerRole(lastRole);\n    }\n\n    @Override\n    public PlayerRole getGuestRole() {\n        return getPlayerRole(GUEST_ROLE_INDEX);\n    }\n\n    @Override\n    public PlayerRole getCoopRole() {\n        return getPlayerRole(COOP_ROLE_INDEX);\n    }\n\n    @Override\n    public List<PlayerRole> getRoles() {\n        return this.rolesContainer.getRoles();\n    }\n\n    private SPlayerRole loadRole(ConfigurationSection section, int expectedWeight, SPlayerRole previousRole) throws ManagerLoadException {\n        int weight = section.getInt(\"weight\", expectedWeight);\n\n        if (weight != expectedWeight)\n            throw new ManagerLoadException(\"The role \\\"\" + section.getName() + \"\\\" has an unexpected weight: \" +\n                    weight + \", expected: \" + expectedWeight, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n\n        int id = section.getInt(\"id\", weight);\n        String name = section.getString(\"name\");\n        String displayName = section.getString(\"display-name\");\n\n        SPlayerRole playerRole = new SPlayerRole(name, displayName, id, weight, section.getStringList(\"permissions\"), previousRole);\n\n        this.rolesContainer.addPlayerRole(playerRole);\n\n        if (weight > lastRole)\n            lastRole = weight;\n\n        return playerRole;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java",
    "content": "package com.bgsoftware.superiorskyblock.island.role;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.RolePrivilegeNode;\nimport com.google.common.base.Preconditions;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\npublic class SPlayerRole implements PlayerRole {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static String ALL_ROLE_NAMES;\n    private static String LIMIT_ROLE_NAMES;\n    private static String LADDER_ROLE_NAMES;\n\n    private final String name;\n    private final String displayName;\n    private final int id;\n    private final int weight;\n    private final RolePrivilegeNode defaultPermissions;\n\n    public SPlayerRole(String name, @Nullable String displayName, int id, int weight, List<String> defaultPermissions,\n                       @Nullable SPlayerRole previousRole) {\n        this.name = name;\n        this.displayName = displayName == null ? name : displayName;\n        this.id = id;\n        this.weight = weight;\n\n        String permissions = defaultPermissions.isEmpty() ? null : String.join(\";\", defaultPermissions);\n\n        this.defaultPermissions = new RolePrivilegeNode(null,\n                previousRole == null ? RolePrivilegeNode.EmptyRolePermissionNode.INSTANCE : previousRole.defaultPermissions,\n                permissions);\n    }\n\n    public static PlayerRole defaultRole() {\n        return plugin.getRoles().getDefaultRole();\n    }\n\n    public static PlayerRole lastRole() {\n        return plugin.getRoles().getLastRole();\n    }\n\n    public static PlayerRole guestRole() {\n        return plugin.getRoles().getGuestRole();\n    }\n\n    public static PlayerRole coopRole() {\n        return plugin.getRoles().getCoopRole();\n    }\n\n    public static PlayerRole of(int weight) {\n        return plugin.getRoles().getPlayerRole(weight);\n    }\n\n    public static PlayerRole fromId(int id) {\n        return plugin.getRoles().getPlayerRoleFromId(id);\n    }\n\n    public static PlayerRole of(String name) {\n        return plugin.getRoles().getPlayerRole(name);\n    }\n\n    public static String getAllRoleNames() {\n        if (ALL_ROLE_NAMES == null) {\n            ALL_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream()\n                    .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH)));\n        }\n\n        return ALL_ROLE_NAMES;\n    }\n\n    public static String getRoleLimitsNames() {\n        if (LIMIT_ROLE_NAMES == null) {\n            LIMIT_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream()\n                    .filter(IslandUtils::isValidRoleForLimit)\n                    .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH)));\n        }\n\n        return LIMIT_ROLE_NAMES;\n    }\n\n    public static String getRolesLadderNames() {\n        if (LADDER_ROLE_NAMES == null) {\n            LADDER_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream()\n                    .filter(PlayerRole::isRoleLadder)\n                    .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH)));\n        }\n\n        return LADDER_ROLE_NAMES;\n    }\n\n    public static void refreshRoles() {\n        LIMIT_ROLE_NAMES = null;\n        LADDER_ROLE_NAMES = null;\n    }\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    @Override\n    public int getWeight() {\n        return weight;\n    }\n\n    @Override\n    public boolean isHigherThan(PlayerRole role) {\n        Preconditions.checkNotNull(role, \"playerRole parameter cannot be null.\");\n        return getWeight() > role.getWeight();\n    }\n\n    @Override\n    public boolean isLessThan(PlayerRole role) {\n        Preconditions.checkNotNull(role, \"playerRole parameter cannot be null.\");\n        return getWeight() < role.getWeight();\n    }\n\n    @Override\n    public boolean isFirstRole() {\n        return getWeight() == 0;\n    }\n\n    @Override\n    public boolean isLastRole() {\n        return getWeight() == lastRole().getWeight();\n    }\n\n    @Override\n    public boolean isRoleLadder() {\n        return getWeight() >= 0 && (getPreviousRole() != null || getNextRole() != null);\n    }\n\n    @Override\n    public PlayerRole getNextRole() {\n        return getWeight() < 0 ? null : plugin.getRoles().getPlayerRole(getWeight() + 1);\n    }\n\n    @Override\n    public PlayerRole getPreviousRole() {\n        return getWeight() <= 0 ? null : plugin.getRoles().getPlayerRole(getWeight() - 1);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(id);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SPlayerRole that = (SPlayerRole) o;\n        return id == that.id;\n    }\n\n    @Override\n    public String toString() {\n        return name;\n    }\n\n    public RolePrivilegeNode getDefaultPermissions() {\n        return defaultPermissions;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.role.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class DefaultRolesContainer implements RolesContainer {\n\n    private final Int2ObjectMapView<PlayerRole> rolesByWeight = CollectionsFactory.createInt2ObjectArrayMap();\n    private final Int2ObjectMapView<PlayerRole> rolesById = CollectionsFactory.createInt2ObjectArrayMap();\n    private final Map<String, PlayerRole> rolesByName = new HashMap<>();\n\n    @Nullable\n    @Override\n    public PlayerRole getPlayerRole(int index) {\n        return rolesByWeight.get(index);\n    }\n\n    @Nullable\n    @Override\n    public PlayerRole getPlayerRoleFromId(int id) {\n        return rolesById.get(id);\n    }\n\n    @Override\n    public PlayerRole getPlayerRole(String name) {\n        PlayerRole playerRole = rolesByName.get(name.toUpperCase(Locale.ENGLISH));\n\n        Preconditions.checkArgument(playerRole != null, \"Invalid role name: \" + name);\n\n        return playerRole;\n    }\n\n    @Override\n    public List<PlayerRole> getRoles() {\n        return new SequentialListBuilder<PlayerRole>()\n                .sorted(Comparator.comparingInt(PlayerRole::getId))\n                .build(rolesById.valueIterator());\n    }\n\n    @Override\n    public void addPlayerRole(PlayerRole playerRole) {\n        this.rolesByWeight.put(playerRole.getWeight(), playerRole);\n        this.rolesById.put(playerRole.getId(), playerRole);\n        this.rolesByName.put(playerRole.getName().toUpperCase(Locale.ENGLISH), playerRole);\n    }\n\n    @Override\n    public void clearRoles() {\n        this.rolesByWeight.clear();\n        this.rolesById.clear();\n        this.rolesByName.clear();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.role.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\n\nimport java.util.List;\n\npublic interface RolesContainer {\n\n    @Nullable\n    PlayerRole getPlayerRole(int index);\n\n    @Nullable\n    PlayerRole getPlayerRoleFromId(int id);\n\n    PlayerRole getPlayerRole(String name);\n\n    List<PlayerRole> getRoles();\n\n    void addPlayerRole(PlayerRole playerRole);\n\n    void clearRoles();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java",
    "content": "package com.bgsoftware.superiorskyblock.island.signs;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport org.bukkit.ChatColor;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.Sign;\n\nimport java.util.List;\n\npublic class IslandSigns {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private IslandSigns() {\n\n    }\n\n    public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location warpLocation, String[] warpLines,\n                                         boolean sendMessage) {\n        // Adjust to the middle of the block\n        warpLocation.add(0.5, 0, 0.5);\n\n        Island island = plugin.getGrid().getIslandAt(warpLocation);\n        if (island == null)\n            return new Result(Reason.NOT_IN_ISLAND, false);\n\n        superiorPlayer.runIfOnline(player -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                warpLocation.setYaw(player.getLocation(wrapper.getHandle()).getYaw());\n            }\n        });\n\n        if (isWarpSign(warpLines[0])) {\n            Reason reason = handleWarpSignPlace(superiorPlayer, island, warpLocation, warpLines, sendMessage);\n            return new Result(reason, true);\n        } else if (isVisitorsSign(warpLines[0])) {\n            return handleVisitorsSignPlace(superiorPlayer, island, warpLocation, warpLines, sendMessage);\n        }\n\n        return new Result(Reason.SUCCESS, false);\n    }\n\n    public static Result handleSignBreak(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, Sign sign) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location signLocation = sign.getLocation(wrapper.getHandle());\n\n            if (island == null) {\n                island = plugin.getGrid().getIslandAt(signLocation);\n                if (island == null)\n                    return new Result(Reason.NOT_IN_ISLAND, false);\n            }\n\n            IslandWarp islandWarp = island.getWarp(signLocation);\n\n            if (islandWarp != null) {\n                if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp))\n                    return new Result(Reason.EVENT_CANCELLED, true);\n\n                island.deleteWarp(superiorPlayer, signLocation);\n            } else {\n                if (sign.getLine(0).equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getActive())) {\n                    if (!PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer))\n                        return new Result(Reason.EVENT_CANCELLED, true);\n\n                    island.setVisitorsLocation(null);\n                }\n            }\n        }\n\n        return new Result(Reason.SUCCESS, false);\n    }\n\n    private static Reason handleWarpSignPlace(SuperiorPlayer superiorPlayer, Island island, Location warpLocation,\n                                              String[] signLines, boolean sendMessage) {\n        int warpsLimit = island.getWarpsLimit();\n        if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) {\n            if (sendMessage)\n                Message.NO_MORE_WARPS.send(superiorPlayer);\n\n            return Reason.LIMIT_REACHED;\n        }\n\n        String warpName = Formatters.STRIP_COLOR_FORMATTER.format(signLines[1].trim());\n        boolean privateFlag = signLines[2].equalsIgnoreCase(\"private\");\n\n        Reason result = Reason.SUCCESS;\n\n        if (warpName.isEmpty()) {\n            if (sendMessage)\n                Message.WARP_ILLEGAL_NAME.send(superiorPlayer);\n            result = Reason.ILLEGAL_NAME;\n        } else if (island.getWarp(warpName) != null) {\n            if (sendMessage)\n                Message.WARP_ALREADY_EXIST.send(superiorPlayer);\n            result = Reason.ALREADY_EXIST;\n        } else if (!IslandUtils.isWarpNameLengthValid(warpName)) {\n            if (sendMessage)\n                Message.WARP_NAME_TOO_LONG.send(superiorPlayer);\n            result = Reason.NAME_TOO_LONG;\n        }\n\n        if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, !privateFlag, null))\n            result = Reason.EVENT_CANCELLED;\n\n        if (result != Reason.SUCCESS)\n            return result;\n\n        List<String> signWarp = plugin.getSettings().getSignWarp();\n\n        for (int i = 0; i < signWarp.size(); i++)\n            signLines[i] = signWarp.get(i).replace(\"{0}\", warpName);\n\n        IslandWarp islandWarp = island.createWarp(warpName, warpLocation, null);\n        islandWarp.setPrivateFlag(privateFlag);\n        if (sendMessage)\n            Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation));\n\n        return Reason.SUCCESS;\n    }\n\n    private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Island island, Location visitorsLocation,\n                                                  String[] warpLines, boolean sendMessage) {\n        int warpsLimit = island.getWarpsLimit();\n        if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) {\n            if (sendMessage)\n                Message.NO_MORE_WARPS.send(superiorPlayer);\n\n            return new Result(Reason.LIMIT_REACHED, true);\n        }\n\n        PluginEvent<PluginEventArgs.IslandSetVisitorHome> setVisitorHomeEvent =\n                PluginEventsFactory.callIslandSetVisitorHomeEvent(island, superiorPlayer, visitorsLocation);\n\n        if (setVisitorHomeEvent.isCancelled())\n            return new Result(Reason.EVENT_CANCELLED, false);\n\n        StringBuilder descriptionBuilder = new StringBuilder();\n\n        for (int i = 1; i < 4; i++) {\n            String line = warpLines[i];\n            if (!line.isEmpty()) {\n                String formattedLine = plugin.getSettings().getVisitorsSign().getDescriptionLineFormat().replace(\"{0}\", line);\n                descriptionBuilder.append(\"\\n\").append(ChatColor.RESET).append(formattedLine);\n            }\n        }\n\n        String description = descriptionBuilder.length() < 1 ? \"\" : descriptionBuilder.substring(1);\n\n        warpLines[0] = plugin.getSettings().getVisitorsSign().getActive();\n\n        for (int i = 1; i <= 3; i++)\n            warpLines[i] = Formatters.COLOR_FORMATTER.format(warpLines[i]);\n\n        Location islandVisitorsLocation = island.getVisitorsLocation((Dimension) null /* unused */);\n        Block oldWelcomeSignBlock = islandVisitorsLocation == null ? null : islandVisitorsLocation.getBlock();\n\n        if (oldWelcomeSignBlock != null && Materials.isSign(oldWelcomeSignBlock.getType())) {\n            Sign oldWelcomeSign = (Sign) oldWelcomeSignBlock.getState();\n            oldWelcomeSign.setLine(0, plugin.getSettings().getVisitorsSign().getInactive());\n            oldWelcomeSign.update();\n        }\n\n        island.setVisitorsLocation(setVisitorHomeEvent.getArgs().islandVisitorHome);\n\n        PluginEvent<PluginEventArgs.IslandChangeDescription> changeDescriptionEvent =\n                PluginEventsFactory.callIslandChangeDescriptionEvent(island, superiorPlayer, description);\n\n        if (!changeDescriptionEvent.isCancelled())\n            island.setDescription(changeDescriptionEvent.getArgs().description);\n\n        if (sendMessage)\n            Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(visitorsLocation));\n\n        return new Result(Reason.SUCCESS, true);\n    }\n\n    private static boolean isWarpSign(String firstSignLine) {\n        return firstSignLine.equalsIgnoreCase(plugin.getSettings().getSignWarpLine());\n    }\n\n    private static boolean isVisitorsSign(String firstSignLine) {\n        return firstSignLine.equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getLine());\n    }\n\n    public enum Reason {\n\n        NOT_IN_ISLAND,\n        ILLEGAL_NAME,\n        ALREADY_EXIST,\n        NAME_TOO_LONG,\n        LIMIT_REACHED,\n        EVENT_CANCELLED,\n        SUCCESS\n\n    }\n\n    public static class Result {\n\n        private final Reason reason;\n        private final boolean cancelEvent;\n\n        public Result(Reason reason, boolean cancelEvent) {\n            this.reason = reason;\n            this.cancelEvent = cancelEvent;\n        }\n\n        public Reason getReason() {\n            return reason;\n        }\n\n        public boolean isCancelEvent() {\n            return cancelEvent;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top;\n\nimport com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.island.SIsland;\nimport com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata;\n\nimport java.util.Comparator;\n\npublic class SortingComparators {\n\n    public final static Comparator<SuperiorPlayer> PLAYER_NAMES_COMPARATOR = Comparator.comparing(SuperiorPlayer::getName);\n    public final static Comparator<SIsland.UniqueVisitor> PAIRED_PLAYERS_NAMES_COMPARATOR =\n            Comparator.comparing(o -> o.getSuperiorPlayer().getName());\n    public final static Comparator<BankTransaction> BANK_TRANSACTIONS_COMPARATOR =\n            Comparator.comparingInt(BankTransaction::getPosition);\n    private final static Comparator<Island> ISLAND_NAMES_COMPARATOR = (o1, o2) -> {\n        String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner().getName() : o1.getStrippedName();\n        String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner().getName() : o2.getStrippedName();\n        return firstName.compareTo(secondName);\n    };\n    public final static Comparator<Island> WORTH_COMPARATOR = (o1, o2) -> {\n        int compare = o2.getWorth().compareTo(o1.getWorth());\n        return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare;\n    };\n    public final static Comparator<Island> LEVEL_COMPARATOR = (o1, o2) -> {\n        int compare = o2.getIslandLevel().compareTo(o1.getIslandLevel());\n        return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare;\n    };\n    public final static Comparator<Island> RATING_COMPARATOR = (o1, o2) -> {\n        int totalRatingsCompare = Double.compare(o2.getTotalRating() * o2.getRatingAmount(), o1.getTotalRating() * o1.getRatingAmount());\n\n        if (totalRatingsCompare == 0) {\n            int ratingsAmountCompare = Integer.compare(o2.getRatingAmount(), o1.getRatingAmount());\n            return ratingsAmountCompare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : ratingsAmountCompare;\n        }\n\n        return totalRatingsCompare;\n    };\n    public final static Comparator<Island> PLAYERS_COMPARATOR = (o1, o2) -> {\n        int compare = Integer.compare(o2.getAllPlayersInside().size(), o1.getAllPlayersInside().size());\n        return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare;\n    };\n    public final static Comparator<SuperiorPlayer> ISLAND_ROLES_COMPARATOR = (o1, o2) -> {\n        // Comparison is between o2 and o1 as the lower the weight is, the higher the player is.\n        int compare = Integer.compare(o2.getPlayerRole().getWeight(), o1.getPlayerRole().getWeight());\n        return compare == 0 ? PLAYER_NAMES_COMPARATOR.compare(o1, o2) : compare;\n    };\n    public static final Comparator<IslandSortMetadata> ISLAND_METADATA_COMPARATOR =\n            (Comparator<IslandSortMetadata>) (o1, o2) -> o1.compareTo(o2);\n\n    private SortingComparators() {\n\n    }\n\n    public static void initializeTopIslandMembersSorting() throws IllegalArgumentException {\n        TopIslandMembersSorting.NAMES.setComparator(PLAYER_NAMES_COMPARATOR);\n        TopIslandMembersSorting.ROLES.setComparator(ISLAND_ROLES_COMPARATOR);\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\n\nimport java.util.Comparator;\n\npublic class SortingTypes {\n\n    public static final SortingType BY_WORTH = register(\"WORTH\", SortingComparators.WORTH_COMPARATOR, false);\n    public static final SortingType BY_LEVEL = register(\"LEVEL\", SortingComparators.LEVEL_COMPARATOR, false);\n    public static final SortingType BY_RATING = register(\"RATING\", SortingComparators.RATING_COMPARATOR, false);\n    public static final SortingType BY_PLAYERS = register(\"PLAYERS\", SortingComparators.PLAYERS_COMPARATOR, false);\n\n    private static volatile SortingType ISLAND_TOP_SORTING;\n    private static volatile SortingType GLOBAL_WARPS_SORTING;\n\n    private SortingTypes() {\n    }\n\n    public static void registerSortingTypes(SuperiorSkyblockPlugin plugin) {\n        // We actually register the settings update listener in here, as otherwise it causes errors\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2752\n        registerListeners(plugin.getPluginEventsDispatcher());\n    }\n\n    private static SortingType register(String name, Comparator<Island> comparator, boolean handleEqualsIslands) {\n        SortingType.register(name, comparator, handleEqualsIslands);\n        return SortingType.getByName(name);\n    }\n\n    public static SortingType getIslandTopSorting() {\n        return ISLAND_TOP_SORTING;\n    }\n\n    public static SortingType getGlobalWarpsSorting() {\n        return GLOBAL_WARPS_SORTING;\n    }\n\n    private static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SortingTypes::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        String topOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder();\n        String warpsOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getGlobalWarpsOrder();\n\n        ISLAND_TOP_SORTING = resolveByName(topOrder);\n        GLOBAL_WARPS_SORTING = resolveByName(warpsOrder);\n    }\n\n    private static SortingType resolveByName(String name) {\n        return SortingType.getByName(name);\n    }\n}\n\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top.metadata;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport org.jetbrains.annotations.NotNull;\n\npublic abstract class IslandSortMetadata<T extends IslandSortMetadata<T>> implements Comparable<T> {\n\n    private final Island island;\n    protected final String islandName;\n\n    protected IslandSortMetadata(Island island) {\n        this.island = island;\n        this.islandName = island.getStrippedName().isEmpty() ? island.getOwner().getName() : island.getStrippedName();\n    }\n\n    public Island getIsland() {\n        return island;\n    }\n\n    @Override\n    public int compareTo(@NotNull T o) {\n        return this.islandName.compareTo(o.islandName);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortPlayerMetadata.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top.metadata;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\npublic class IslandSortPlayerMetadata extends IslandSortMetadata<IslandSortPlayerMetadata> {\n\n    private final int allPlayersCount;\n\n    public IslandSortPlayerMetadata(Island island) {\n        super(island);\n        this.allPlayersCount = island.getAllPlayersInside().size();\n    }\n\n    @Override\n    public int compareTo(IslandSortPlayerMetadata o) {\n        int compare = Integer.compare(o.allPlayersCount, this.allPlayersCount);\n        return compare == 0 ? super.compareTo(o) : compare;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortRatingMetadata.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top.metadata;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\npublic class IslandSortRatingMetadata extends IslandSortMetadata<IslandSortRatingMetadata> {\n\n    private final int ratingAmount;\n    private final double compareValue;\n\n    public IslandSortRatingMetadata(Island island) {\n        super(island);\n        this.ratingAmount = island.getRatingAmount();\n        this.compareValue = island.getTotalRating() * ratingAmount;\n    }\n\n    @Override\n    public int compareTo(IslandSortRatingMetadata o) {\n        int compare = Double.compare(o.compareValue, this.compareValue);\n        if (compare == 0) {\n            compare = Integer.compare(o.ratingAmount, this.ratingAmount);\n            if (compare == 0)\n                compare = super.compareTo(o);\n        }\n        return compare;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortValueMetadata.java",
    "content": "package com.bgsoftware.superiorskyblock.island.top.metadata;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\n\nimport java.math.BigDecimal;\n\npublic class IslandSortValueMetadata extends IslandSortMetadata<IslandSortValueMetadata> {\n\n    private final BigDecimal value;\n\n    public IslandSortValueMetadata(Island island, BigDecimal value) {\n        super(island);\n        this.value = value;\n    }\n\n    @Override\n    public int compareTo(IslandSortValueMetadata o) {\n        int compare = o.value.compareTo(this.value);\n        return compare == 0 ? super.compareTo(o) : compare;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgrade.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\npublic class DefaultUpgrade extends SUpgrade {\n\n    private static final DefaultUpgrade INSTANCE = new DefaultUpgrade();\n\n    private DefaultUpgrade() {\n        super(\"DEFAULT\");\n    }\n\n    public static DefaultUpgrade getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public SUpgradeLevel getUpgradeLevel(int level) {\n        return DefaultUpgradeLevel.getInstance();\n    }\n\n    @Override\n    public int getMaxUpgradeLevel() {\n        return 1;\n    }\n\n    @Override\n    public void addUpgradeLevel(int level, SUpgradeLevel upgradeLevel) {\n        // Not supported for the default upgrade.\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost;\n\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.OptionalDouble;\nimport java.util.OptionalInt;\n\npublic class DefaultUpgradeLevel extends SUpgradeLevel {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final DefaultUpgradeLevel INSTANCE = new DefaultUpgradeLevel();\n\n    private DefaultUpgradeLevel() {\n        super(-1, EmptyUpgradeCost.getInstance(), Collections.emptyList(), \"\", Collections.emptySet(),\n                Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getCropGrowth())),\n                Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getSpawnerRates())),\n                Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getMobDrops())),\n                Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getTeamLimit())),\n                Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getWarpsLimit())),\n                Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getCoopLimit())),\n                Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getIslandSize())),\n                Value.syncedSupplied(() -> (KeyMap<Integer>) plugin.getSettings().getDefaultValues().getBlockLimits()),\n                Value.syncedSupplied(() -> (KeyMap<Integer>) plugin.getSettings().getDefaultValues().getEntityLimits()),\n                Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRealGeneratorsMap()),\n                Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandEffects()),\n                Value.syncedSupplied(() -> Optional.of(plugin.getSettings().getDefaultValues().getBankLimit())),\n                Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRoleLimitsAsView())\n        );\n    }\n\n    public static DefaultUpgradeLevel getInstance() {\n        return INSTANCE;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\nimport java.math.BigDecimal;\n\npublic class IslandUpgradeConstants {\n\n    public static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2);\n    public static final BigDecimal NO_BANK_LIMIT_VALUE = BigDecimal.valueOf(-1);\n\n    public static final int SYNCED_VALUE = -2;\n    public static final int NO_LIMIT_VALUE = -1;\n\n    private IslandUpgradeConstants() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.OptionalDouble;\nimport java.util.OptionalInt;\nimport java.util.Set;\n\npublic class SUpgrade implements Upgrade {\n\n    private static final SUpgradeLevel NULL_LEVEL = new SUpgradeLevel(0,\n            EmptyUpgradeCost.getInstance(),\n            Collections.emptyList(),\n            \"\",\n            Collections.emptySet(),\n            Value.syncedFixed(OptionalDouble.empty()),\n            Value.syncedFixed(OptionalDouble.empty()),\n            Value.syncedFixed(OptionalDouble.empty()),\n            Value.syncedFixed(OptionalInt.empty()),\n            Value.syncedFixed(OptionalInt.empty()),\n            Value.syncedFixed(OptionalInt.empty()),\n            Value.syncedFixed(OptionalInt.empty()),\n            Value.syncedFixed(KeyMaps.createEmptyMap()),\n            Value.syncedFixed(KeyMaps.createEmptyMap()),\n            Value.syncedFixed(new EnumerateMap<>(Collections.emptyList())),\n            Value.syncedFixed(Collections.emptyMap()),\n            Value.syncedFixed(Optional.empty()),\n            Value.syncedFixed(EmptyInt2IntMapView.INSTANCE));\n\n    private final String name;\n\n    private SUpgradeLevel[] upgradeLevels = new SUpgradeLevel[0];\n    private final Set<Integer> slots = new LinkedHashSet<>();\n\n    public SUpgrade(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public SUpgradeLevel getUpgradeLevel(int level) {\n        return level <= 0 || level > upgradeLevels.length ? NULL_LEVEL : upgradeLevels[level - 1];\n    }\n\n    @Override\n    public int getMaxUpgradeLevel() {\n        return upgradeLevels.length;\n    }\n\n    @Override\n    public int getSlot() {\n        return getSlots().get(0);\n    }\n\n    @Override\n    public List<Integer> getSlots() {\n        return Collections.unmodifiableList(new LinkedList<>(this.slots));\n    }\n\n    @Override\n    public boolean isSlot(int slot) {\n        return this.slots.contains(slot);\n    }\n\n    @Override\n    public void setSlot(int slot) {\n        this.slots.add(slot);\n    }\n\n    @Override\n    public void setSlots(@Nullable List<Integer> slots) {\n        if (slots == null) {\n            this.slots.clear();\n        } else {\n            this.slots.addAll(slots);\n        }\n    }\n\n    public void addUpgradeLevel(int level, SUpgradeLevel upgradeLevel) {\n        if (level > upgradeLevels.length)\n            upgradeLevels = Arrays.copyOf(upgradeLevels, level);\n\n        upgradeLevels[level - 1] = upgradeLevel;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SUpgrade upgrade = (SUpgrade) o;\n        return name.equals(upgrade.name);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport com.bgsoftware.superiorskyblock.core.value.DoubleValue;\nimport com.bgsoftware.superiorskyblock.core.value.IntValue;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.potion.PotionEffectType;\n\nimport javax.script.ScriptException;\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.OptionalDouble;\nimport java.util.OptionalInt;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\npublic class SUpgradeLevel implements UpgradeLevel {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private final int level;\n    private final UpgradeCost cost;\n    private final List<String> commands;\n    private final String permission;\n    private final Set<UpgradeRequirement> requirements;\n    private final Value<OptionalDouble> cropGrowth;\n    private final Value<OptionalDouble> spawnerRates;\n    private final Value<OptionalDouble> mobDrops;\n    private final Value<OptionalInt> teamLimit;\n    private final Value<OptionalInt> warpsLimit;\n    private final Value<OptionalInt> coopLimit;\n    private final Value<OptionalInt> borderSize;\n    private final Value<KeyMap<Integer>> blockLimits;\n    private final Value<KeyMap<Integer>> entityLimits;\n    private final Value<EnumerateMap<Dimension, Map<Key, Integer>>> generatorRates;\n    private final Value<Map<PotionEffectType, Integer>> islandEffects;\n    private final Value<Optional<BigDecimal>> bankLimit;\n    private final Value<Int2IntMapView> roleLimits;\n\n    @Nullable\n    private ItemData itemData;\n\n    public SUpgradeLevel(int level, UpgradeCost cost, List<String> commands, String permission, Set<UpgradeRequirement> requirements,\n                         Value<OptionalDouble> cropGrowth, Value<OptionalDouble> spawnerRates, Value<OptionalDouble> mobDrops,\n                         Value<OptionalInt> teamLimit, Value<OptionalInt> warpsLimit, Value<OptionalInt> coopLimit,\n                         Value<OptionalInt> borderSize, Value<KeyMap<Integer>> blockLimits,\n                         Value<KeyMap<Integer>> entityLimits, Value<EnumerateMap<Dimension, Map<Key, Integer>>> generatorRates,\n                         Value<Map<PotionEffectType, Integer>> islandEffects, Value<Optional<BigDecimal>> bankLimit,\n                         Value<Int2IntMapView> roleLimits) {\n        this.level = level;\n        this.cost = cost;\n        this.commands = commands;\n        this.permission = permission;\n        this.requirements = requirements;\n        this.cropGrowth = cropGrowth;\n        this.spawnerRates = spawnerRates;\n        this.mobDrops = mobDrops;\n        this.teamLimit = teamLimit;\n        this.warpsLimit = warpsLimit;\n        this.coopLimit = coopLimit;\n        this.borderSize = borderSize;\n        this.blockLimits = blockLimits;\n        this.entityLimits = entityLimits;\n        this.generatorRates = generatorRates;\n        this.islandEffects = islandEffects;\n        this.bankLimit = bankLimit;\n        this.roleLimits = roleLimits;\n    }\n\n    @Override\n    public int getLevel() {\n        return level;\n    }\n\n    @Override\n    public double getPrice() {\n        return cost.getCost().doubleValue();\n    }\n\n    public UpgradeCost getCost() {\n        return cost;\n    }\n\n    @Override\n    public List<String> getCommands() {\n        return Collections.unmodifiableList(commands);\n    }\n\n    @Override\n    public String getPermission() {\n        return permission;\n    }\n\n    @Override\n    public String checkRequirements(SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n\n        if (offlinePlayer != null) {\n            for (UpgradeRequirement requirement : requirements) {\n                String check = placeholdersService.get().parsePlaceholders(offlinePlayer, requirement.getPlaceholder());\n                try {\n                    if (!Boolean.parseBoolean(plugin.getScriptEngine().eval(check) + \"\"))\n                        return requirement.getErrorMessage();\n                } catch (ScriptException error) {\n                    Log.entering(\"ENTER\", level, superiorPlayer.getName(), requirement.getPlaceholder());\n                    Log.error(error, \"An unexpected error occurred while checking for upgrade requirement:\");\n                }\n            }\n        }\n\n        return \"\";\n    }\n\n    @Override\n    public boolean hasCropGrowth() {\n        return cropGrowth.get().isPresent();\n    }\n\n    @Override\n    public double getCropGrowth() {\n        return cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public boolean hasSpawnerRates() {\n        return spawnerRates.get().isPresent();\n    }\n\n    @Override\n    public double getSpawnerRates() {\n        return spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public boolean hasMobDrops() {\n        return mobDrops.get().isPresent();\n    }\n\n    @Override\n    public double getMobDrops() {\n        return mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public int getBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return blockLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public int getExactBlockLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return blockLimits.get().getRaw(key, IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public Map<Key, Integer> getBlockLimits() {\n        return Collections.unmodifiableMap(blockLimits.get());\n    }\n\n    @Override\n    public int getEntityLimit(EntityType entityType) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null.\");\n        return getEntityLimit(Keys.of(entityType));\n    }\n\n    @Override\n    public int getEntityLimit(Key key) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        return entityLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public Map<Key, Integer> getEntityLimitsAsKeys() {\n        return Collections.unmodifiableMap(entityLimits.get());\n    }\n\n    @Override\n    public boolean hasTeamLimit() {\n        return teamLimit.get().isPresent();\n    }\n\n    @Override\n    public int getTeamLimit() {\n        return teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public boolean hasWarpsLimit() {\n        return warpsLimit.get().isPresent();\n    }\n\n    @Override\n    public int getWarpsLimit() {\n        return warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public boolean hasCoopLimit() {\n        return coopLimit.get().isPresent();\n    }\n\n    @Override\n    public int getCoopLimit() {\n        return coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public boolean hasBorderSize() {\n        return borderSize.get().isPresent();\n    }\n\n    @Override\n    public int getBorderSize() {\n        return borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public int getGeneratorAmount(Key key, Dimension dimension) {\n        Preconditions.checkNotNull(key, \"key parameter cannot be null.\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Map<Key, Integer> generatorRates = this.generatorRates.get().get(dimension);\n        return (generatorRates == null ? 0 : generatorRates.getOrDefault(key, 0));\n    }\n\n    @Override\n    public Map<String, Integer> getGeneratorAmounts(Dimension dimension) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Map<Key, Integer> generatorRates = this.generatorRates.get().get(dimension);\n        return generatorRates == null ? Collections.emptyMap() : generatorRates.entrySet().stream().collect(Collectors.toMap(\n                entry -> entry.getKey().toString(),\n                Map.Entry::getValue));\n    }\n\n    @Override\n    public int getPotionEffect(PotionEffectType potionEffectType) {\n        Preconditions.checkNotNull(potionEffectType, \"potionEffectType parameter cannot be null.\");\n        return islandEffects.get().getOrDefault(potionEffectType, 0);\n    }\n\n    @Override\n    public Map<PotionEffectType, Integer> getPotionEffects() {\n        return Collections.unmodifiableMap(islandEffects.get());\n    }\n\n    @Override\n    public boolean hasBankLimit() {\n        return bankLimit.get().isPresent();\n    }\n\n    @Override\n    public BigDecimal getBankLimit() {\n        return bankLimit.get().orElse(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE);\n    }\n\n    @Override\n    public int getRoleLimit(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        return roleLimits.get().getOrDefault(playerRole.getId(), IslandUpgradeConstants.NO_LIMIT_VALUE);\n    }\n\n    @Override\n    public Map<PlayerRole, Integer> getRoleLimits() {\n        Int2IntMapView roleLimits = this.roleLimits.get();\n\n        if (roleLimits.isEmpty())\n            return Collections.emptyMap();\n\n        Map<PlayerRole, Integer> roleLimitsConverted = new LinkedHashMap<>();\n\n        Iterator<Int2IntMapView.Entry> iterator = roleLimits.entryIterator();\n        while (iterator.hasNext()) {\n            Int2IntMapView.Entry entry = iterator.next();\n            PlayerRole playerRole = SPlayerRole.fromId(entry.getKey());\n            if (playerRole != null)\n                roleLimitsConverted.put(playerRole, entry.getValue());\n        }\n\n        return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted);\n    }\n\n    public DoubleValue getCropGrowthUpgradeValue() {\n        return DoubleValue.syncedSupplied(() -> cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public DoubleValue getSpawnerRatesUpgradeValue() {\n        return DoubleValue.syncedSupplied(() -> spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public DoubleValue getMobDropsUpgradeValue() {\n        return DoubleValue.syncedSupplied(() -> mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public Map<Key, IntValue> getBlockLimitsUpgradeValue() {\n        return blockLimits.get().entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> IntValue.syncedFixed(entry.getValue()))\n        );\n    }\n\n    public Map<Key, IntValue> getEntityLimitsUpgradeValue() {\n        return entityLimits.get().entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> IntValue.syncedFixed(entry.getValue()))\n        );\n    }\n\n    public IntValue getTeamLimitUpgradeValue() {\n        return IntValue.syncedSupplied(() -> teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public IntValue getWarpsLimitUpgradeValue() {\n        return IntValue.syncedSupplied(() -> warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public IntValue getCoopLimitUpgradeValue() {\n        return IntValue.syncedSupplied(() -> coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public IntValue getBorderSizeUpgradeValue() {\n        return IntValue.syncedSupplied(() -> borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE));\n    }\n\n    public EnumerateMap<Dimension, Map<Key, IntValue>> getGeneratorUpgradeValue() {\n        EnumerateMap<Dimension, Map<Key, Integer>> generatorRates = this.generatorRates.get();\n\n        EnumerateMap<Dimension, Map<Key, IntValue>> generatorRatesConverted = new EnumerateMap<>(Dimension.values());\n\n        for (Dimension dimension : Dimension.values()) {\n            Map<Key, Integer> worldGeneratorRates = generatorRates.get(dimension);\n            if (worldGeneratorRates != null) {\n                Map<Key, IntValue> result = worldGeneratorRates.entrySet().stream().collect(Collectors.toMap(\n                        Map.Entry::getKey,\n                        entry -> IntValue.syncedFixed(entry.getValue())));\n                generatorRatesConverted.put(dimension, result);\n            }\n        }\n\n        return generatorRatesConverted;\n    }\n\n    public Map<PotionEffectType, IntValue> getPotionEffectsUpgradeValue() {\n        return islandEffects.get().entrySet().stream().collect(Collectors.toMap(\n                Map.Entry::getKey,\n                entry -> IntValue.syncedFixed(entry.getValue()))\n        );\n    }\n\n    public Value<BigDecimal> getBankLimitUpgradeValue() {\n        return Value.syncedSupplied(() -> bankLimit.get().orElseGet(() -> IslandUpgradeConstants.NO_BANK_LIMIT_VALUE));\n    }\n\n    public Map<PlayerRole, IntValue> getRoleLimitsUpgradeValue() {\n        Int2IntMapView roleLimits = this.roleLimits.get();\n\n        if (roleLimits.isEmpty())\n            return Collections.emptyMap();\n\n        Map<PlayerRole, IntValue> roleLimitsConverted = new LinkedHashMap<>();\n\n        Iterator<Int2IntMapView.Entry> iterator = roleLimits.entryIterator();\n        while (iterator.hasNext()) {\n            Int2IntMapView.Entry entry = iterator.next();\n            PlayerRole playerRole = SPlayerRole.fromId(entry.getKey());\n            if (playerRole != null)\n                roleLimitsConverted.put(playerRole, IntValue.syncedFixed(entry.getValue()));\n        }\n\n        return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted);\n    }\n\n    public void setItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel,\n                            GameSound hasNextLevelSound, GameSound noNextLevelSound,\n                            List<String> hasNextLevelCommands, List<String> noNextLevelCommands) {\n        this.itemData = new ItemData(hasNextLevel, noNextLevel, hasNextLevelSound, noNextLevelSound, hasNextLevelCommands, noNextLevelCommands);\n    }\n\n    @Nullable\n    public ItemData getItemData() {\n        return itemData;\n    }\n\n    public static class ItemData {\n\n        public TemplateItem hasNextLevel;\n        public TemplateItem noNextLevel;\n        public GameSound hasNextLevelSound;\n        public GameSound noNextLevelSound;\n        public List<String> hasNextLevelCommands;\n        public List<String> noNextLevelCommands;\n\n        public ItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel,\n                        GameSound hasNextLevelSound, GameSound noNextLevelSound,\n                        List<String> hasNextLevelCommands, List<String> noNextLevelCommands) {\n            this.hasNextLevel = hasNextLevel;\n            this.noNextLevel = noNextLevel;\n            this.hasNextLevelSound = hasNextLevelSound;\n            this.noNextLevelSound = noNextLevelSound;\n            this.hasNextLevelCommands = hasNextLevelCommands;\n            this.noNextLevelCommands = noNextLevelCommands;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradeRequirement.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\npublic class UpgradeRequirement {\n\n    private final String placeholder;\n    private final String errorMessage;\n\n    public UpgradeRequirement(String placeholder, String errorMessage) {\n        this.placeholder = placeholder;\n        this.errorMessage = errorMessage;\n    }\n\n    public String getPlaceholder() {\n        return placeholder;\n    }\n\n    public String getErrorMessage() {\n        return errorMessage;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.island.upgrade.container.UpgradesContainer;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collection;\nimport java.util.Locale;\n\npublic class UpgradesManagerImpl extends Manager implements UpgradesManager {\n\n    private final UpgradesContainer upgradesContainer;\n\n    private String ALL_UPGRADE_NAMES;\n\n    public UpgradesManagerImpl(SuperiorSkyblockPlugin plugin, UpgradesContainer upgradesContainer) {\n        super(plugin);\n        this.upgradesContainer = upgradesContainer;\n    }\n\n    @Override\n    public void loadData() {\n        // Data is loaded later.\n    }\n\n    @Override\n    public Upgrade getUpgrade(String upgradeName) {\n        Preconditions.checkNotNull(upgradeName, \"upgradeName parameter cannot be null.\");\n        return this.upgradesContainer.getUpgrade(upgradeName);\n    }\n\n    @Override\n    public Upgrade getUpgrade(int slot) {\n        return this.upgradesContainer.getUpgrade(slot);\n    }\n\n    @Override\n    public void addUpgrade(Upgrade upgrade) {\n        this.upgradesContainer.addUpgrade(upgrade);\n        ALL_UPGRADE_NAMES = null;\n    }\n\n    @Override\n    public Upgrade getDefaultUpgrade() {\n        return DefaultUpgrade.getInstance();\n    }\n\n    @Override\n    public boolean isUpgrade(String upgradeName) {\n        Preconditions.checkNotNull(upgradeName, \"upgradeName parameter cannot be null.\");\n        return getUpgrade(upgradeName) != null;\n    }\n\n    @Override\n    public Collection<Upgrade> getUpgrades() {\n        return this.upgradesContainer.getUpgrades();\n    }\n\n    @Override\n    public void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader) {\n        Preconditions.checkNotNull(id, \"id parameter cannot be null.\");\n        Preconditions.checkNotNull(costLoader, \"costLoader parameter cannot be null.\");\n        this.upgradesContainer.registerUpgradeCostLoader(id, costLoader);\n    }\n\n    @Override\n    public Collection<UpgradeCostLoader> getUpgradesCostLoaders() {\n        return this.upgradesContainer.getUpgradesCostLoaders();\n    }\n\n    @Nullable\n    @Override\n    public UpgradeCostLoader getUpgradeCostLoader(String id) {\n        Preconditions.checkNotNull(id, \"id parameter cannot be null.\");\n        return this.upgradesContainer.getUpgradeCostLoader(id);\n    }\n\n    public void clearUpgrades() {\n        this.upgradesContainer.clearUpgrades();\n    }\n\n    public String getUpgradesNames() {\n        if (ALL_UPGRADE_NAMES == null) {\n            ALL_UPGRADE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getUpgrades().getUpgrades().stream()\n                    .map(upgrade -> upgrade.getName().toLowerCase(Locale.ENGLISH)));\n        }\n\n        return ALL_UPGRADE_NAMES;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class DefaultUpgradesContainer implements UpgradesContainer {\n\n    private final Map<String, Upgrade> upgrades = new HashMap<>();\n    private final Map<String, UpgradeCostLoader> upgradeCostLoaders = new HashMap<>();\n\n    @Nullable\n    @Override\n    public Upgrade getUpgrade(String upgradeName) {\n        return this.upgrades.get(upgradeName.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Nullable\n    @Override\n    public Upgrade getUpgrade(int slot) {\n        return this.upgrades.values().stream()\n                .filter(upgrade -> upgrade.isSlot(slot))\n                .findFirst()\n                .orElse(null);\n    }\n\n    @Override\n    public Collection<Upgrade> getUpgrades() {\n        return new SequentialListBuilder<Upgrade>().build(this.upgrades.values());\n    }\n\n    @Override\n    public void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader) {\n        this.upgradeCostLoaders.put(id.toLowerCase(Locale.ENGLISH), costLoader);\n    }\n\n    @Override\n    public Collection<UpgradeCostLoader> getUpgradesCostLoaders() {\n        return new SequentialListBuilder<UpgradeCostLoader>().build(this.upgradeCostLoaders.values());\n    }\n\n    @Override\n    public UpgradeCostLoader getUpgradeCostLoader(String id) {\n        return this.upgradeCostLoaders.get(id.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public void addUpgrade(Upgrade upgrade) {\n        this.upgrades.put(upgrade.getName().toLowerCase(Locale.ENGLISH), upgrade);\n    }\n\n    @Override\n    public void clearUpgrades() {\n        this.upgrades.clear();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.container;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.google.common.collect.Sets;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class IslandUpgrades {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Set<IslandUpgrades> ALL_UPGRADE_CONTAINERS = Sets.newSetFromMap(new WeakHashMap<>());\n\n    static {\n\n    }\n\n    private final Map<String, Integer> enabledUpgrades = new ConcurrentHashMap<>();\n    private final Map<String, Integer> upgrades = new ConcurrentHashMap<>();\n\n    public IslandUpgrades() {\n        ALL_UPGRADE_CONTAINERS.add(this);\n    }\n\n    public void setUpgradeLevel(Upgrade upgrade, int level) {\n        setUpgradeLevelInternal(upgrade.getName(), Math.min(upgrade.getMaxUpgradeLevel(), level));\n    }\n\n    public void setUpgradeLevels(Map<String, Integer> upgrades) {\n        upgrades.forEach(this::setUpgradeLevelInternal);\n    }\n\n    public UpgradeLevel getUpgradeLevel(Upgrade upgrade) {\n        return upgrade.getUpgradeLevel(this.enabledUpgrades.getOrDefault(upgrade.getName(), 1));\n    }\n\n    public Map<String, Integer> getUpgrades() {\n        return Collections.unmodifiableMap(this.enabledUpgrades);\n    }\n\n    private void setUpgradeLevelInternal(String upgradeName, int level) {\n        this.enabledUpgrades.put(upgradeName, level);\n        this.upgrades.put(upgradeName, level);\n    }\n\n    public static void onUpgradesUpdate() {\n        for (IslandUpgrades islandUpgrades : ALL_UPGRADE_CONTAINERS) {\n            islandUpgrades.enabledUpgrades.clear();\n            islandUpgrades.upgrades.forEach((upgradeName, level) -> {\n                Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName);\n                if (upgrade != null)\n                    islandUpgrades.setUpgradeLevel(upgrade, level);\n            });\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\n\nimport java.util.Collection;\n\npublic interface UpgradesContainer {\n\n    @Nullable\n    Upgrade getUpgrade(String upgradeName);\n\n    @Nullable\n    Upgrade getUpgrade(int slot);\n\n    Collection<Upgrade> getUpgrades();\n\n    void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader);\n\n    Collection<UpgradeCostLoader> getUpgradesCostLoaders();\n\n    UpgradeCostLoader getUpgradeCostLoader(String id);\n\n    void addUpgrade(Upgrade upgrade);\n\n    void clearUpgrades();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/EmptyUpgradeCost.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.cost;\n\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\npublic class EmptyUpgradeCost extends UpgradeCostAbstract {\n\n    private static final EmptyUpgradeCost INSTANCE = new EmptyUpgradeCost();\n\n    private EmptyUpgradeCost() {\n        super(BigDecimal.ZERO, \"Null\");\n    }\n\n    public static EmptyUpgradeCost getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) {\n        return false;\n    }\n\n    @Override\n    public void withdrawCost(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public UpgradeCost clone(BigDecimal cost) {\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/PlaceholdersUpgradeCost.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.cost;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport org.bukkit.Bukkit;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class PlaceholdersUpgradeCost extends UpgradeCostAbstract {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private final String placeholder;\n    private final List<String> withdrawCommands;\n\n    public PlaceholdersUpgradeCost(BigDecimal cost, String placeholder, List<String> withdrawCommands) {\n        super(cost, \"placeholders\");\n        this.placeholder = placeholder;\n        this.withdrawCommands = Collections.unmodifiableList(withdrawCommands);\n    }\n\n    @Override\n    public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) {\n        BigDecimal currentBalance = BigDecimal.ZERO;\n\n        try {\n            currentBalance = new BigDecimal(placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), placeholder));\n        } catch (Exception ignored) {\n        }\n\n        return currentBalance.compareTo(cost) >= 0;\n    }\n\n    @Override\n    public void withdrawCost(SuperiorPlayer superiorPlayer) {\n        String cost = super.cost.toPlainString();\n        String playerName = superiorPlayer.getName();\n        withdrawCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                command.replace(\"%amount%\", cost).replace(\"%player%\", playerName)));\n    }\n\n    @Override\n    public UpgradeCost clone(BigDecimal cost) {\n        return new PlaceholdersUpgradeCost(cost, placeholder, withdrawCommands);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/UpgradeCostAbstract.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.cost;\n\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\n\nimport java.math.BigDecimal;\n\npublic abstract class UpgradeCostAbstract implements UpgradeCost {\n\n    protected final BigDecimal cost;\n    protected final String id;\n\n    protected UpgradeCostAbstract(BigDecimal cost, String id) {\n        this.cost = cost;\n        this.id = id;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public BigDecimal getCost() {\n        return cost;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/VaultUpgradeCost.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.cost;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\n\nimport java.math.BigDecimal;\n\npublic class VaultUpgradeCost extends UpgradeCostAbstract {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public VaultUpgradeCost(BigDecimal value) {\n        super(value, \"money\");\n    }\n\n    @Override\n    public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) {\n        return plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer).compareTo(cost) >= 0;\n    }\n\n    @Override\n    public void withdrawCost(SuperiorPlayer superiorPlayer) {\n        plugin.getProviders().withdrawMoney(superiorPlayer, cost);\n    }\n\n    @Override\n    public UpgradeCost clone(BigDecimal cost) {\n        return new VaultUpgradeCost(cost);\n    }\n\n}\n\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/loaders/PlaceholdersUpgradeCostLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.loaders;\n\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.island.upgrade.cost.PlaceholdersUpgradeCost;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.math.BigDecimal;\n\npublic class PlaceholdersUpgradeCostLoader implements UpgradeCostLoader {\n\n    @Override\n    public UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException {\n        if (!upgradeSection.contains(\"price\"))\n            throw new UpgradeCostLoadException(\"The field 'price' is missing from the section.\");\n        if (!upgradeSection.contains(\"placeholder\"))\n            throw new UpgradeCostLoadException(\"The field 'placeholder' is missing from the section.\");\n        if (!upgradeSection.contains(\"withdraw-commands\"))\n            throw new UpgradeCostLoadException(\"The field 'withdraw-commands' is missing from the section.\");\n\n        return new PlaceholdersUpgradeCost(\n                BigDecimal.valueOf(upgradeSection.getDouble(\"price\")),\n                upgradeSection.getString(\"placeholder\"),\n                upgradeSection.getStringList(\"withdraw-commands\")\n        );\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/loaders/VaultUpgradeCostLoader.java",
    "content": "package com.bgsoftware.superiorskyblock.island.upgrade.loaders;\n\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.island.upgrade.cost.VaultUpgradeCost;\nimport org.bukkit.configuration.ConfigurationSection;\n\nimport java.math.BigDecimal;\n\npublic class VaultUpgradeCostLoader implements UpgradeCostLoader {\n\n    @Override\n    public UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException {\n        if (!upgradeSection.contains(\"price\"))\n            throw new UpgradeCostLoadException(\"The field 'price' is missing from the section.\");\n        return new VaultUpgradeCost(BigDecimal.valueOf(upgradeSection.getDouble(\"price\")));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.island.warp;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.SWorldPosition;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Objects;\n\npublic class SIslandWarp implements IslandWarp {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final WarpCategory warpCategory;\n\n    private String name;\n    private WorldPosition worldPosition;\n    private WorldInfo worldInfo;\n    private boolean isPrivate;\n    private ItemStack icon;\n\n    public SIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) {\n        this.name = name;\n        this.worldPosition = worldPosition;\n        this.worldInfo = worldInfo;\n        this.warpCategory = warpCategory;\n        this.isPrivate = isPrivate;\n        this.icon = icon;\n    }\n\n    @Override\n    public Island getIsland() {\n        return warpCategory.getIsland();\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        Log.debug(Debug.SET_WARP_NAME, getOwnerName(), this.name, name);\n\n        String oldName = this.name;\n        this.name = name;\n\n        IslandsDatabaseBridge.updateWarpName(getIsland(), this, oldName);\n    }\n\n    @Override\n    public Location getLocation() {\n        return IslandWorlds.setWorldToLocation(this.worldInfo, this.worldPosition);\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        if (location != null) {\n            if (location instanceof LazyWorldLocation) {\n                ((LazyWorldLocation) location).setWorldName(this.worldInfo.getName());\n            } else {\n                IslandWorlds.ensureWorldLoaded(this.worldInfo);\n                World world = Bukkit.getWorld(this.worldInfo.getName());\n                location.setWorld(world);\n            }\n\n            location.setX(this.worldPosition.getX());\n            location.setY(this.worldPosition.getY());\n            location.setZ(this.worldPosition.getZ());\n            location.setYaw(this.worldPosition.getYaw());\n            location.setPitch(this.worldPosition.getPitch());\n        }\n\n        return location;\n    }\n\n    @Override\n    public void setLocation(Location location) {\n        Preconditions.checkNotNull(location, \"location parameter cannot be null.\");\n\n        Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, location);\n\n        this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), LazyWorldLocation.getWorldName(location));\n        this.worldPosition = SWorldPosition.of(location);\n\n        IslandsDatabaseBridge.updateWarpLocation(getIsland(), this);\n    }\n\n    @Override\n    public WorldPosition getPosition() {\n        return this.worldPosition;\n    }\n\n    @Override\n    public Dimension getPositionDimension() {\n        return this.worldInfo.getDimension();\n    }\n\n    @Override\n    public void setPosition(Dimension dimension, WorldPosition worldPosition) {\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null.\");\n        Preconditions.checkNotNull(worldPosition, \"worldPosition parameter cannot be null.\");\n\n        Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, dimension, worldPosition);\n\n        this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), dimension);\n        this.worldPosition = worldPosition;\n\n        IslandsDatabaseBridge.updateWarpLocation(getIsland(), this);\n    }\n\n    @Override\n    public boolean hasPrivateFlag() {\n        return isPrivate;\n    }\n\n    @Override\n    public void setPrivateFlag(boolean privateFlag) {\n        Log.debug(Debug.SET_WARP_PRIVATE, getOwnerName(), this.name, privateFlag);\n\n        this.isPrivate = privateFlag;\n\n        IslandsDatabaseBridge.updateWarpPrivateStatus(getIsland(), this);\n    }\n\n    @Override\n    public ItemStack getRawIcon() {\n        return icon == null ? null : icon.clone();\n    }\n\n    @Override\n    public ItemStack getIcon(SuperiorPlayer superiorPlayer) {\n        if (icon == null)\n            return null;\n\n        try {\n            ItemBuilder itemBuilder = new ItemBuilder(icon)\n                    .replaceAll(\"{0}\", name);\n            return superiorPlayer == null ? itemBuilder.build() : itemBuilder.build(superiorPlayer);\n        } catch (Exception error) {\n            setIcon(null);\n            return null;\n        }\n    }\n\n    @Override\n    public void setIcon(ItemStack icon) {\n        Log.debug(Debug.SET_WARP_ICON, getOwnerName(), this.name, icon);\n\n        this.icon = icon == null ? null : icon.clone();\n\n        IslandsDatabaseBridge.updateWarpIcon(getIsland(), this);\n    }\n\n    @Override\n    public WarpCategory getCategory() {\n        return warpCategory;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        SIslandWarp that = (SIslandWarp) o;\n        return name.equals(that.name);\n    }\n\n    private String getOwnerName() {\n        SuperiorPlayer superiorPlayer = getIsland().getOwner();\n        return superiorPlayer == null ? \"None\" : superiorPlayer.getName();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/warp/SWarpCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.island.warp;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.UUID;\n\npublic class SWarpCategory implements WarpCategory {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n\n    private final List<IslandWarp> islandWarps = new LinkedList<>();\n    private final UUID islandUUID;\n    private Island cachedIsland;\n\n    private String name;\n    private int slot;\n    private ItemStack icon;\n\n    public SWarpCategory(UUID islandUUID, String name, int slot, @Nullable ItemStack icon) {\n        this.islandUUID = islandUUID;\n        this.name = name;\n        this.slot = slot;\n        this.icon = icon == null ? WarpIcons.DEFAULT_WARP_CATEGORY_ICON.build() : icon;\n    }\n\n    @Override\n    public Island getIsland() {\n        return cachedIsland == null ? (cachedIsland = plugin.getGrid().getIslandByUUID(islandUUID)) : cachedIsland;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        Log.debug(Debug.SET_WARP_CATEGORY_NAME, getOwnerName(), this.name, name);\n\n        String oldName = this.name;\n        this.name = name;\n\n        for (IslandWarp islandWarp : islandWarps)\n            IslandsDatabaseBridge.updateWarpCategory(getIsland(), islandWarp, oldName);\n\n        IslandsDatabaseBridge.updateWarpCategoryName(getIsland(), this, oldName);\n    }\n\n    @Override\n    public List<IslandWarp> getWarps() {\n        return islandWarps;\n    }\n\n    @Override\n    public int getSlot() {\n        return slot;\n    }\n\n    @Override\n    public void setSlot(int slot) {\n        Log.debug(Debug.SET_WARP_CATEGORY_SLOT, getOwnerName(), this.name, slot);\n\n        this.slot = slot;\n\n        IslandsDatabaseBridge.updateWarpCategorySlot(getIsland(), this);\n    }\n\n    @Override\n    public ItemStack getRawIcon() {\n        return icon.clone();\n    }\n\n    @Override\n    public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) {\n        ItemBuilder itemBuilder = new ItemBuilder(icon)\n                .replaceAll(\"{0}\", name);\n        return superiorPlayer == null ? itemBuilder.build() : itemBuilder.build(superiorPlayer);\n    }\n\n    @Override\n    public void setIcon(@Nullable ItemStack icon) {\n        Log.debug(Debug.SET_WARP_CATEGORY_ICON, getOwnerName(), this.name, icon);\n\n        this.icon = icon == null ? WarpIcons.DEFAULT_WARP_CATEGORY_ICON.build() : icon.clone();\n\n        IslandsDatabaseBridge.updateWarpCategoryIcon(getIsland(), this);\n    }\n\n    private String getOwnerName() {\n        SuperiorPlayer superiorPlayer = getIsland().getOwner();\n        return superiorPlayer == null ? \"None\" : superiorPlayer.getName();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java",
    "content": "package com.bgsoftware.superiorskyblock.island.warp;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.Sign;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SignWarp {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private SignWarp() {\n\n    }\n\n    public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender commandSender) {\n        try (ObjectsPools.Wrapper<LazyWorldLocation> wrapper = ObjectsPools.LAZY_LOCATION.obtain()) {\n            Location warpLocation = islandWarp.getLocation(wrapper.getHandle());\n\n            if (warpLocation.getWorld() == null) {\n                IslandWorlds.accessIslandWorldAsync(islandWarp.getIsland(), warpLocation, true, islandWorldResult -> {\n                    islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(unused -> {\n                        trySignWarpBreakWorldLoaded(islandWarp, commandSender);\n                    });\n                });\n                return;\n            }\n        }\n\n        trySignWarpBreakWorldLoaded(islandWarp, commandSender);\n    }\n\n    private static void trySignWarpBreakWorldLoaded(IslandWarp islandWarp, CommandSender commandSender) {\n        ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> {\n            trySignWarpBreakChunkLoaded(islandWarp, commandSender);\n        });\n    }\n\n    private static void trySignWarpBreakChunkLoaded(IslandWarp islandWarp, CommandSender commandSender) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location warpLocation = islandWarp.getLocation(wrapper.getHandle());\n\n            Block signBlock = warpLocation.getBlock();\n            BlockState blockState = signBlock.getState();\n\n            // We check for a sign block at the warp's location.\n            if (!(blockState instanceof Sign))\n                return;\n\n            Sign sign = (Sign) blockState;\n\n            List<String> configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp());\n            configSignWarp.replaceAll(line -> line.replace(\"{0}\", islandWarp.getName()));\n            String[] signLines = sign.getLines();\n\n            for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) {\n                if (!signLines[i].equals(configSignWarp.get(i)))\n                    return;\n            }\n\n            // Detected warp sign\n            signBlock.setType(Material.AIR);\n            signBlock.getWorld().dropItemNaturally(warpLocation, new ItemStack(blockState.getType()));\n\n            Message.DELETE_WARP_SIGN_BROKE.send(commandSender);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/island/warp/WarpIcons.java",
    "content": "package com.bgsoftware.superiorskyblock.island.warp;\n\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport org.bukkit.Material;\n\npublic class WarpIcons {\n\n    public static final TemplateItem DEFAULT_WARP_CATEGORY_ICON = new TemplateItem(new ItemBuilder(Material.BOOK)\n            .withName(\"&6{0}\"));\n    public static TemplateItem DEFAULT_WARP_ICON;\n\n    private WarpIcons() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventCallback;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\n\npublic abstract class AbstractGameEventListener {\n\n\n    protected final SuperiorSkyblockPlugin plugin;\n\n    protected AbstractGameEventListener(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    protected <Args extends IEventArgs> void registerCallback(GameEventType<Args> type, GameEventPriority priority,\n                                                              GameEventCallback<Args> callback) {\n        registerCallback(type, priority, true, callback);\n    }\n\n    protected <Args extends IEventArgs> void registerCallback(GameEventType<Args> type, GameEventPriority priority,\n                                                              boolean ignoreCancelled,\n                                                              GameEventCallback<Args> callback) {\n        plugin.getGameEventsDispatcher().registerCallback(this, type, priority, ignoreCancelled, callback);\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Bukkit;\nimport org.bukkit.ChatColor;\nimport org.bukkit.entity.Player;\n\nimport java.util.UUID;\n\npublic class AdminPlayersListener extends AbstractGameEventListener {\n\n    private static final UUID DEVELOPER_UUID = UUID.fromString(\"45713654-41bf-45a1-aa6f-00fe6598703b\");\n\n    private final String buildName;\n\n    public AdminPlayersListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        String fileName = plugin.getFileName().split(\"\\\\.\")[0];\n        String buildName = fileName.contains(\"-\") ? fileName.substring(fileName.indexOf('-') + 1) : \"\";\n        this.buildName = buildName.isEmpty() ? \"\" : \" (Build: \" + buildName + \")\";\n\n        registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin);\n    }\n\n    private void onPlayerJoin(GameEvent<GameEventArgs.PlayerJoinEvent> e) {\n        Player player = e.getArgs().player;\n\n        // Notifies me when a server uses one of my plugins.\n        if (player.getUniqueId().equals(DEVELOPER_UUID)) {\n            Bukkit.getScheduler().runTaskLater(plugin, () -> Message.CUSTOM.send(player,\n                    \"&8[&fSuperiorSeries&8] &7This server is using SuperiorSkyblock2 v\" +\n                            plugin.getDescription().getVersion() + buildName, true), 5L);\n        }\n\n        // Notifies operators about new updates\n        if (player.isOp() && plugin.getUpdater().isOutdated()) {\n            Bukkit.getScheduler().runTaskLater(plugin, () ->\n                    player.sendMessage(ChatColor.BLUE + \"\" + ChatColor.BOLD + \"SuperiorSkyblock2\" + ChatColor.GRAY +\n                            \" A new version is available (v\" + plugin.getUpdater().getLatestVersion() + \")!\"), 20L);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Minecart;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.TNTPrimed;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\npublic class BlockChangesListener extends AbstractGameEventListener {\n\n    private static final Map<Material, Key> BUCKET_TO_KEY_CACHE = new ArrayMap<>();\n\n    @Nullable\n    private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, \"CHORUS_FLOWER\");\n\n    @Nullable\n    private static final Material CLOSED_EYEBLOSSOM = EnumHelper.getEnum(Material.class, \"CLOSED_EYEBLOSSOM\");\n\n    @Nullable\n    private static final Material OPEN_EYEBLOSSOM = EnumHelper.getEnum(Material.class, \"OPEN_EYEBLOSSOM\");\n    @Nullable\n    private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"BUILD_COPPERGOLEM\");\n\n    @WorldRecordFlags\n    private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n\n    static {\n        for (Material material : Material.values()) {\n            if (material.name().contains(\"_BUCKET\")) {\n                BUCKET_TO_KEY_CACHE.put(material, getBlockKeyFromBucketMaterial(material));\n            }\n        }\n    }\n\n    private final Collection<Location> alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS);\n    private final Collection<Location> alreadyChorusFlowerTracked = AutoRemovalCollection.newArrayList(1L * 50, TimeUnit.MILLISECONDS);\n\n    private final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    public BlockChangesListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        this.registerListeners();\n    }\n\n    /* BLOCK PLACES */\n\n    private void onBlockPlace(GameEvent<GameEventArgs.BlockPlaceEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        BlockState replacedState = e.getArgs().replacedState;\n\n        boolean shouldAvoidReplacedState = replacedState.equals(block.getState());\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            this.worldRecordService.get().recordBlockPlace(Keys.of(block),\n                    block.getLocation(wrapper.getHandle()),\n                    plugin.getNMSWorld().getDefaultAmount(block),\n                    shouldAvoidReplacedState ? null : replacedState,\n                    REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onBucketEmpty(GameEvent<GameEventArgs.PlayerEmptyBucketEvent> e) {\n        Material bucket = e.getArgs().bucket;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().clickedBlock.getWorld()))\n            return;\n\n        Key blockKey = BUCKET_TO_KEY_CACHE.computeIfAbsent(bucket, BlockChangesListener::getBlockKeyFromBucketMaterial);\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Block clickedBlock = e.getArgs().clickedBlock;\n            this.worldRecordService.get().recordBlockPlace(blockKey,\n                    clickedBlock.getLocation(wrapper.getHandle()), 1,\n                    null, REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onStructureGrow(GameEvent<GameEventArgs.StructureGrowEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().location.getWorld()))\n            return;\n\n        KeyMap<Integer> placedBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        KeyMap<Integer> brokenBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        e.getArgs().blocks.forEach(blockState -> {\n            Key placedBlockKey = Keys.of(blockState);\n            Key brokenBlockKey = Keys.of(blockState.getBlock());\n            if (!placedBlockKey.equals(brokenBlockKey)) {\n                if (!placedBlockKey.equals(ConstantKeys.AIR))\n                    placedBlockCounts.put(placedBlockKey, placedBlockCounts.getOrDefault(placedBlockKey, 0) + 1);\n                if (!brokenBlockKey.equals(ConstantKeys.AIR))\n                    brokenBlockCounts.put(brokenBlockKey, brokenBlockCounts.getOrDefault(brokenBlockKey, 0) + 1);\n            }\n        });\n        Location growLocation = e.getArgs().location;\n        this.worldRecordService.get().recordMultiBlocksPlace(placedBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS);\n        this.worldRecordService.get().recordMultiBlocksBreak(brokenBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS);\n    }\n\n    private void onBlockGrow(GameEvent<GameEventArgs.BlockGrowEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        BlockState newState = e.getArgs().newState;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            this.worldRecordService.get().recordBlockPlace(Keys.of(newState),\n                    block.getLocation(wrapper.getHandle()),\n                    1, block.getState(), REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onBlockForm(GameEvent<GameEventArgs.BlockFormEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        BlockState newState = e.getArgs().newState;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = block.getLocation(wrapper.getHandle());\n            this.worldRecordService.get().recordBlockPlace(Keys.of(newState), location, 1, block.getState(), REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onBlockSpread(GameEvent<GameEventArgs.BlockSpreadEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Block source = e.getArgs().source;\n        BlockState newState = e.getArgs().newState;\n\n        Material newStateType = newState.getType();\n        Material sourceType = source.getType();\n\n        Key spreadBlock = null;\n\n        if (newStateType == CHORUS_FLOWER && sourceType == CHORUS_FLOWER) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location spreadBlockLocation = source.getLocation(wrapper.getHandle());\n                // When a chorus flower grows, it is replaced with a flower plant and multiple new flowers can grow.\n                // Therefore, we want to track a plant one time instead of a new flower.\n                if (!alreadyChorusFlowerTracked.contains(spreadBlockLocation)) {\n                    spreadBlock = ConstantKeys.CHORUS_PLANT;\n                    alreadyChorusFlowerTracked.add(spreadBlockLocation.clone());\n                }\n            }\n        }\n\n        if (spreadBlock == null) {\n            spreadBlock = Keys.of(newState);\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            this.worldRecordService.get().recordBlockPlace(spreadBlock,\n                    block.getLocation(wrapper.getHandle()),\n                    1, block.getState(), REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onBlockShapeUpdate(GameEvent<GameEventArgs.BlockUpdateShapeEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Key newStateKey = Keys.of(block);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n\n            if (newStateKey.equals(ConstantKeys.AIR)) {\n                // New state is AIR, so this is a block break\n                Key oldStateKey = Keys.of(e.getArgs().oldState);\n                this.worldRecordService.get().recordBlockBreak(oldStateKey, blockLocation,\n                        1, REGULAR_RECORD_FLAGS);\n            } else {\n                this.worldRecordService.get().recordBlockPlace(newStateKey,\n                        block.getLocation(wrapper.getHandle()),\n                        1, e.getArgs().oldState, REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    private void onMinecartPlace(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        Entity vehicle = e.getArgs().entity;\n\n        if (!(vehicle instanceof Minecart))\n            return;\n\n        Key minecartBlockKey = getMinecartBlockKey(vehicle.getType());\n        if (minecartBlockKey != null) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                this.worldRecordService.get().recordBlockPlace(minecartBlockKey,\n                        vehicle.getLocation(wrapper.getHandle()),\n                        1, null, REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    private void onSpawnerChange(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        Block clickedBlock = e.getArgs().clickedBlock;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || clickedBlock.getType() != Materials.SPAWNER.toBukkitType())\n            return;\n\n        ItemStack handItem = e.getArgs().usedItem;\n\n        if (handItem == null)\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld()))\n            return;\n\n        Material handItemType = handItem.getType();\n        if (!Materials.isSpawnEgg(handItemType))\n            return;\n\n        Chunk chunk = clickedBlock.getChunk();\n        BlockState oldBlockState = clickedBlock.getState();\n        Key oldSpawnerKey = Keys.of(oldBlockState);\n\n        BukkitExecutor.sync(() -> {\n            if (!chunk.isLoaded())\n                return;\n\n            Key newSpawnerKey = Keys.of(clickedBlock);\n            if (!oldSpawnerKey.equals(newSpawnerKey)) {\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    Location location = clickedBlock.getLocation(wrapper.getHandle());\n                    int spawnerCount = plugin.getProviders().getSpawnersProvider().getSpawner(location).getKey();\n                    this.worldRecordService.get().recordBlockBreak(oldSpawnerKey, location, spawnerCount, REGULAR_RECORD_FLAGS);\n                    this.worldRecordService.get().recordBlockPlace(newSpawnerKey, location, spawnerCount, null, REGULAR_RECORD_FLAGS);\n                }\n            }\n        }, 1L);\n    }\n\n    private void onEntityChangeBlock(GameEvent<GameEventArgs.EntityChangeBlockEvent> e) {\n        if (e.getArgs().entity instanceof Player)\n            return;\n\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Key newBlockKey = e.getArgs().newType;\n        Key oldBlockKey = Keys.of(block);\n\n        if (newBlockKey.equals(oldBlockKey))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n\n            if (!oldBlockKey.equals(ConstantKeys.AIR)) {\n                this.worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation,\n                        plugin.getNMSWorld().getDefaultAmount(block),\n                        REGULAR_RECORD_FLAGS);\n            }\n\n            if (!newBlockKey.equals(ConstantKeys.AIR)) {\n                this.worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1,\n                        null, REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    /* BLOCK BREAKS */\n\n    private void onBlockBreak(GameEvent<GameEventArgs.BlockBreakEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS);\n    }\n\n    private void onBucketFill(GameEvent<GameEventArgs.PlayerFillBucketEvent> e) {\n        Block clickedBlock = e.getArgs().clickedBlock;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld()))\n            return;\n\n        boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(clickedBlock);\n        if (isWaterLogged || clickedBlock.isLiquid()) {\n            Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(clickedBlock);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                this.worldRecordService.get().recordBlockBreak(blockKey,\n                        clickedBlock.getLocation(wrapper.getHandle()),\n                        1, REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    private void onEntitySpawn(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        if (entity.isDead())\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        onMinecartPlace(e);\n        onDragonEggDrop(e);\n        onGolemStructure(e);\n    }\n\n    private void onDragonEggDrop(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        if (!(entity instanceof Item))\n            return;\n\n        Item item = (Item) entity;\n\n        if (item.getItemStack().getType() != Material.DRAGON_EGG)\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            for (Entity nearby : item.getNearbyEntities(2, 2, 2)) {\n                if (nearby instanceof FallingBlock) {\n                    Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby);\n                    this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()),\n                            1, WorldRecordFlags.SAVE_BLOCK_COUNT);\n                    return;\n                }\n            }\n        }\n    }\n\n    private void onGolemStructure(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle());\n\n            if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM) {\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.IRON_BLOCK, entityLocation, 4, 0);\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS);\n            } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN) {\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.SNOW_BLOCK, entityLocation, 2, 0);\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS);\n            } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_WITHER) {\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.SOUL_SAND, entityLocation, 4, 0);\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.WITHER_SKELETON_SKULL, entityLocation, 3, REGULAR_RECORD_FLAGS);\n            } else if (spawnReason == BUILD_COPPERGOLEM) {\n                Block copperOrChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN);\n                Key copperBlock = Keys.of(copperOrChestBlock);\n                this.worldRecordService.get().recordBlockBreak(copperBlock, entityLocation, 1, 0);\n                this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, 0);\n                BukkitExecutor.sync(() -> {\n                    Key chestBlock = Keys.of(copperOrChestBlock);\n                    this.worldRecordService.get().recordBlockPlace(chestBlock, entityLocation, 1, null, REGULAR_RECORD_FLAGS);\n                }, 1L);\n            }\n        }\n\n    }\n\n    private void onPistonExtend(GameEvent<GameEventArgs.PistonExtendEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        for (Block block : e.getArgs().blocks) {\n            if (plugin.getNMSWorld().getPistonReaction(block) == PistonPushReaction.DESTROY) {\n                this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    private void onLeavesDecay(GameEvent<GameEventArgs.LeavesDecayEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS);\n    }\n\n    private void onBlockFromTo(GameEvent<GameEventArgs.BlockFromToEvent> e) {\n        Block block = e.getArgs().block;\n\n        // Ignore dragon eggs, otherwise it will add +1 to the count of dragon eggs\n        // when right-clicking them\n        if (block.getType() == Material.DRAGON_EGG)\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Block toBlock = e.getArgs().toBlock;\n\n        if (toBlock.getType() != Material.AIR) {\n            // Do not save block counts\n            this.worldRecordService.get().recordBlockBreak(toBlock, 1, WorldRecordFlags.DIRTY_CHUNKS);\n        } else {\n            BukkitExecutor.sync(() -> {\n                // Ignore cobblestone blocks, otherwise it will add +1 to the count of cobblestone when generated\n                // from cobblestone generator\n                if (toBlock.getType() != Material.COBBLESTONE) {\n                    // Do not save block counts\n                    this.worldRecordService.get().recordBlockPlace(toBlock, 1, null, WorldRecordFlags.DIRTY_CHUNKS);\n                }\n            });\n        }\n    }\n\n    private void onBlockFade(GameEvent<GameEventArgs.BlockFadeEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        BlockState newState = e.getArgs().newState;\n        if (newState.getType() == Material.AIR) {\n            this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS);\n        } else {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                this.worldRecordService.get().recordBlockPlace(Keys.of(newState),\n                        newState.getLocation(wrapper.getHandle()),\n                        1,\n                        block.getState(),\n                        REGULAR_RECORD_FLAGS);\n            }\n        }\n    }\n\n    private void onEntityExplode(GameEvent<GameEventArgs.EntityExplodeEvent> e) {\n        if (e.getArgs().isSoftExplosion)\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        KeyMap<Integer> blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        e.getArgs().blocks.forEach(block -> {\n            Key blockKey = Keys.of(block);\n            blockCounts.put(blockKey, blockCounts.getOrDefault(blockKey, 0) + 1);\n        });\n\n        if (entity instanceof TNTPrimed)\n            blockCounts.put(ConstantKeys.TNT, blockCounts.getOrDefault(ConstantKeys.TNT, 0) + 1);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            this.worldRecordService.get().recordMultiBlocksBreak(blockCounts,\n                    entity.getLocation(wrapper.getHandle()), REGULAR_RECORD_FLAGS);\n        }\n    }\n\n    private void onSpongeAbsorb(GameEvent<GameEventArgs.SpongeAbsorbEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = block.getLocation(wrapper.getHandle());\n\n            if (alreadySpongeAbosrbCalled.contains(location))\n                return;\n\n            worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1,\n                    block.getState(), WorldRecordFlags.SAVE_BLOCK_COUNT);\n\n            alreadySpongeAbosrbCalled.add(location.clone());\n        }\n    }\n\n    private void onGenericGame(GameEvent<GameEventArgs.GenericGameEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().world))\n            return;\n\n        // We only care about block_change\n        if (!e.getArgs().gameEvent.equals(\"block_change\"))\n            return;\n\n        Location blockLocation = e.getArgs().location;\n        Block block = blockLocation.getBlock();\n        Material blockType = block.getType();\n\n        Key newBlockKey;\n        Key oldBlockKey;\n\n        if (blockType == OPEN_EYEBLOSSOM) {\n            // OPEN_EYEBLOSSOM was changed, we want to remove CLOSED_EYEBLOSSOM and replace it with OPEN_EYEBLOSSOM\n            newBlockKey = ConstantKeys.OPEN_EYEBLOSSOM;\n            oldBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM;\n        } else if (blockType == CLOSED_EYEBLOSSOM) {\n            // CLOSED_EYEBLOSSOM was changed, we want to remove OPEN_EYEBLOSSOM and replace it with CLOSED_EYEBLOSSOM\n            newBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM;\n            oldBlockKey = ConstantKeys.OPEN_EYEBLOSSOM;\n        } else {\n            return;\n        }\n\n        worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, null, 0);\n        worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, 1, REGULAR_RECORD_FLAGS);\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onBlockPlace);\n        registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketEmpty);\n        registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.MONITOR, this::onStructureGrow);\n        registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.MONITOR, this::onBlockGrow);\n        registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.MONITOR, this::onBlockForm);\n        registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.MONITOR, this::onBlockSpread);\n        registerCallback(GameEventType.BLOCK_UPDATE_SHAPE_EVENT, GameEventPriority.MONITOR, this::onBlockShapeUpdate);\n        registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange);\n        registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock);\n        registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak);\n        registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill);\n        registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn);\n        registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend);\n        registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay);\n        registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo);\n        registerCallback(GameEventType.BLOCK_FADE_EVENT, GameEventPriority.MONITOR, this::onBlockFade);\n        registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode);\n        registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb);\n\n        if (CLOSED_EYEBLOSSOM != null || OPEN_EYEBLOSSOM != null)\n            registerCallback(GameEventType.GENERIC_GAME_EVENT, GameEventPriority.MONITOR, this::onGenericGame);\n    }\n\n    @Nullable\n    private static Key getMinecartBlockKey(EntityType minecartType) {\n        switch (minecartType) {\n            case MINECART_HOPPER:\n                return ConstantKeys.HOPPER;\n            case MINECART_COMMAND:\n                return ConstantKeys.COMMAND_BLOCK;\n            case MINECART_TNT:\n                return ConstantKeys.TNT;\n            case MINECART_FURNACE:\n                return ConstantKeys.FURNACE;\n            case MINECART_CHEST:\n                return ConstantKeys.CHEST;\n            case MINECART_MOB_SPAWNER:\n                return ConstantKeys.MOB_SPAWNER;\n        }\n\n        return null;\n    }\n\n    private static Key getBlockKeyFromBucketMaterial(Material material) {\n        return Keys.ofMaterialAndData(material.name().replace(\"_BUCKET\", \"\"));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.events.EventCallback;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.Cancellable;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.block.BlockBreakEvent;\nimport org.bukkit.event.block.BlockBurnEvent;\nimport org.bukkit.event.block.BlockDispenseEvent;\nimport org.bukkit.event.block.BlockFadeEvent;\nimport org.bukkit.event.block.BlockFormEvent;\nimport org.bukkit.event.block.BlockFromToEvent;\nimport org.bukkit.event.block.BlockGrowEvent;\nimport org.bukkit.event.block.BlockIgniteEvent;\nimport org.bukkit.event.block.BlockPhysicsEvent;\nimport org.bukkit.event.block.BlockPistonExtendEvent;\nimport org.bukkit.event.block.BlockPistonRetractEvent;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.event.block.BlockRedstoneEvent;\nimport org.bukkit.event.block.BlockSpreadEvent;\nimport org.bukkit.event.block.EntityBlockFormEvent;\nimport org.bukkit.event.block.LeavesDecayEvent;\nimport org.bukkit.event.block.SignChangeEvent;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.event.entity.EntityChangeBlockEvent;\nimport org.bukkit.event.entity.EntityDamageByEntityEvent;\nimport org.bukkit.event.entity.EntityDamageEvent;\nimport org.bukkit.event.entity.EntityDeathEvent;\nimport org.bukkit.event.entity.EntityExplodeEvent;\nimport org.bukkit.event.entity.EntityInteractEvent;\nimport org.bukkit.event.entity.EntityPortalEnterEvent;\nimport org.bukkit.event.entity.EntityPortalEvent;\nimport org.bukkit.event.entity.EntityTargetEvent;\nimport org.bukkit.event.entity.EntityTeleportEvent;\nimport org.bukkit.event.entity.ItemSpawnEvent;\nimport org.bukkit.event.entity.PlayerLeashEntityEvent;\nimport org.bukkit.event.entity.ProjectileHitEvent;\nimport org.bukkit.event.entity.ProjectileLaunchEvent;\nimport org.bukkit.event.hanging.HangingBreakByEntityEvent;\nimport org.bukkit.event.hanging.HangingPlaceEvent;\nimport org.bukkit.event.inventory.InventoryClickEvent;\nimport org.bukkit.event.inventory.InventoryCloseEvent;\nimport org.bukkit.event.inventory.InventoryOpenEvent;\nimport org.bukkit.event.player.AsyncPlayerChatEvent;\nimport org.bukkit.event.player.PlayerBucketEmptyEvent;\nimport org.bukkit.event.player.PlayerBucketFillEvent;\nimport org.bukkit.event.player.PlayerChangedWorldEvent;\nimport org.bukkit.event.player.PlayerCommandPreprocessEvent;\nimport org.bukkit.event.player.PlayerDropItemEvent;\nimport org.bukkit.event.player.PlayerGameModeChangeEvent;\nimport org.bukkit.event.player.PlayerInteractAtEntityEvent;\nimport org.bukkit.event.player.PlayerInteractEntityEvent;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.event.player.PlayerItemConsumeEvent;\nimport org.bukkit.event.player.PlayerJoinEvent;\nimport org.bukkit.event.player.PlayerLoginEvent;\nimport org.bukkit.event.player.PlayerMoveEvent;\nimport org.bukkit.event.player.PlayerPickupItemEvent;\nimport org.bukkit.event.player.PlayerPortalEvent;\nimport org.bukkit.event.player.PlayerQuitEvent;\nimport org.bukkit.event.player.PlayerRespawnEvent;\nimport org.bukkit.event.player.PlayerShearEntityEvent;\nimport org.bukkit.event.player.PlayerTeleportEvent;\nimport org.bukkit.event.player.PlayerUnleashEntityEvent;\nimport org.bukkit.event.vehicle.VehicleCreateEvent;\nimport org.bukkit.event.vehicle.VehicleDamageEvent;\nimport org.bukkit.event.vehicle.VehicleEnterEvent;\nimport org.bukkit.event.vehicle.VehicleEntityCollisionEvent;\nimport org.bukkit.event.vehicle.VehicleMoveEvent;\nimport org.bukkit.event.world.ChunkLoadEvent;\nimport org.bukkit.event.world.ChunkUnloadEvent;\nimport org.bukkit.event.world.StructureGrowEvent;\nimport org.bukkit.event.world.WorldUnloadEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\npublic class BukkitEventsListener implements Listener {\n\n    private static final ReflectMethod<Entity> PROJECTILE_HIT_TARGET_ENTITY = new ReflectMethod<>(\n            ProjectileHitEvent.class, \"getHitEntity\");\n    private static final ReflectMethod<Block> PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>(\n            ProjectileHitEvent.class, \"getHitBlock\");\n    @Nullable\n    private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, \"WIND_CHARGE\");\n    @Nullable\n    private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, \"BREEZE_WIND_CHARGE\");\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public BukkitEventsListener(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n\n        // Block Events\n        createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_BURN_EVENT, BlockBurnEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_DISPENSE_EVENT, BlockDispenseEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_FADE_EVENT, BlockFadeEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_FORM_EVENT, BlockFormEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_GROW_EVENT, BlockGrowEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_IGNITE_EVENT, BlockIgniteEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_PLACE_EVENT, BlockPlaceEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.BLOCK_REDSTONE_EVENT, BlockRedstoneEvent.class, this::createGameEvent, this::cancelBlockRedstoneEvent);\n        createEventListener(GameEventType.BLOCK_SPREAD_EVENT, BlockSpreadEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PISTON_EXTEND_EVENT, BlockPistonExtendEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PISTON_RETRACT_EVENT, BlockPistonRetractEvent.class, this::createGameEvent);\n\n        // World Events\n        createEventListener(GameEventType.CHUNK_LOAD_EVENT, ChunkLoadEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.CHUNK_UNLOAD_EVENT, ChunkUnloadEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.STRUCTURE_GROW_EVENT, StructureGrowEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.WORLD_UNLOAD_EVENT, WorldUnloadEvent.class, this::createGameEvent);\n\n        // Entity Events\n        createEventListener(GameEventType.ENTITY_BLOCK_FORM_EVENT, EntityBlockFormEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageByEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_INTERACT_EVENT, EntityInteractEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_MOVE_EVENT, PlayerMoveEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_PORTAL_EVENT, PlayerPortalEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_RIDE_EVENT, VehicleEnterEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_SPAWN_EVENT, CreatureSpawnEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_SPAWN_EVENT, HangingPlaceEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_SPAWN_EVENT, VehicleCreateEvent.class, this::createGameEvent, this::cancelVehicleCreateEvent);\n        createEventListener(GameEventType.ENTITY_TARGET_EVENT, EntityTargetEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, EntityTeleportEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, PlayerTeleportEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.HANGING_BREAK_EVENT, HangingBreakByEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.HANGING_PLACE_EVENT, HangingPlaceEvent.class, this::createGameEvent2);\n        createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent);\n\n        // Inventory Events\n        createEventListener(GameEventType.INVENTORY_CLICK_EVENT, InventoryClickEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.INVENTORY_CLOSE_EVENT, InventoryCloseEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.INVENTORY_OPEN_EVENT, InventoryOpenEvent.class, this::createGameEvent);\n\n        // Player Events\n        createEventListener(GameEventType.PLAYER_CHANGED_WORLD_EVENT, PlayerChangedWorldEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_COMMAND_EVENT, PlayerCommandPreprocessEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_DROP_ITEM_EVENT, PlayerDropItemEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, PlayerBucketEmptyEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_FILL_BUCKET_EVENT, PlayerBucketFillEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractAtEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_ITEM_CONSUME_EVENT, PlayerItemConsumeEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_JOIN_EVENT, PlayerJoinEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_LEASH_ENTITY_EVENT, PlayerLeashEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_LOGIN_EVENT, PlayerLoginEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, PlayerPickupItemEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_QUIT_EVENT, PlayerQuitEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, PlayerShearEntityEvent.class, this::createGameEvent);\n        createEventListener(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, PlayerUnleashEntityEvent.class, this::createGameEvent);\n\n        // Special Events (per version)\n        try {\n            Class.forName(\"org.bukkit.event.block.SpongeAbsorbEvent\");\n            createEventListener(GameEventType.SPONGE_ABSORB_EVENT, org.bukkit.event.block.SpongeAbsorbEvent.class, new SpongeAbsorbEventFunction());\n        } catch (ClassNotFoundException ignored) {\n        }\n\n        try {\n            Class.forName(\"com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent\");\n            createEventListener(GameEventType.ENTITY_DEATH_EVENT, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent.class, new EntityRemoveFromWorldEventFunction());\n        } catch (ClassNotFoundException ignored) {\n            createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent);\n        }\n\n        boolean registeredChatListener = false;\n        if (plugin.getSettings().getChatSigningSupport()) {\n            try {\n                Class.forName(\"io.papermc.paper.event.player.AsyncChatEvent\");\n                createEventListener(GameEventType.PLAYER_CHAT_EVENT, io.papermc.paper.event.player.AsyncChatEvent.class, new AsyncChatEventFunctions(), new AsyncChatEventFunctions());\n                registeredChatListener = true;\n            } catch (Exception ignored) {\n            }\n        }\n\n        if (!registeredChatListener)\n            createEventListener(GameEventType.PLAYER_CHAT_EVENT, AsyncPlayerChatEvent.class, this::createGameEvent);\n\n        try {\n            Class.forName(\"org.bukkit.event.player.PlayerPickupArrowEvent\");\n            createEventListener(GameEventType.PLAYER_PICKUP_ARROW_EVENT, org.bukkit.event.player.PlayerPickupArrowEvent.class, new PlayerPickupArrowEventFunctions());\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Class.forName(\"org.bukkit.event.player.PlayerAttemptPickupItemEvent\");\n            createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, org.bukkit.event.player.PlayerAttemptPickupItemEvent.class, new PlayerPickupItemEventFunctions());\n        } catch (Exception ignored) {\n        }\n\n        try {\n            Class.forName(\"org.bukkit.event.raid.RaidTriggerEvent\");\n            createEventListener(GameEventType.RAID_TRIGGER_EVENT, org.bukkit.event.raid.RaidTriggerEvent.class, new RaidTriggerEventFunctions());\n        } catch (Exception ignored) {\n        }\n\n\n        try {\n            Class genericGameEventClass = Class.forName(\"org.bukkit.event.world.GenericGameEvent\");\n            createEventListener(GameEventType.GENERIC_GAME_EVENT, genericGameEventClass, plugin.getNMSAlgorithms().getGenericGameCreator());\n        } catch (Exception ignored) {\n        }\n    }\n\n    /*\n     * BLOCK EVENTS\n     */\n\n    private GameEvent<GameEventArgs.BlockBreakEvent> createGameEvent(GameEventType<GameEventArgs.BlockBreakEvent> eventType, GameEventPriority priority, BlockBreakEvent e) {\n        GameEventArgs.BlockBreakEvent blockBreakEvent = new GameEventArgs.BlockBreakEvent();\n        blockBreakEvent.block = e.getBlock();\n        blockBreakEvent.player = e.getPlayer();\n        return eventType.createEvent(blockBreakEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockBurnEvent> createGameEvent(GameEventType<GameEventArgs.BlockBurnEvent> eventType, GameEventPriority priority, BlockBurnEvent e) {\n        GameEventArgs.BlockBurnEvent blockBurnEvent = new GameEventArgs.BlockBurnEvent();\n        blockBurnEvent.block = e.getBlock();\n        return eventType.createEvent(blockBurnEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockDispenseEvent> createGameEvent(GameEventType<GameEventArgs.BlockDispenseEvent> eventType, GameEventPriority priority, BlockDispenseEvent e) {\n        GameEventArgs.BlockDispenseEvent blockDispenseEvent = new GameEventArgs.BlockDispenseEvent();\n        blockDispenseEvent.block = e.getBlock();\n        blockDispenseEvent.dispensedItem = e.getItem();\n        blockDispenseEvent.velocity = e.getVelocity();\n        return eventType.createEvent(blockDispenseEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockFadeEvent> createGameEvent(GameEventType<GameEventArgs.BlockFadeEvent> eventType, GameEventPriority priority, BlockFadeEvent e) {\n        GameEventArgs.BlockFadeEvent blockFadeEvent = new GameEventArgs.BlockFadeEvent();\n        blockFadeEvent.block = e.getBlock();\n        blockFadeEvent.newState = e.getNewState();\n        return eventType.createEvent(blockFadeEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockFormEvent> createGameEvent(GameEventType<GameEventArgs.BlockFormEvent> eventType, GameEventPriority priority, BlockFormEvent e) {\n        GameEventArgs.BlockFormEvent blockFormEvent = new GameEventArgs.BlockFormEvent();\n        blockFormEvent.block = e.getBlock();\n        blockFormEvent.newState = e.getNewState();\n        return eventType.createEvent(blockFormEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockFromToEvent> createGameEvent(GameEventType<GameEventArgs.BlockFromToEvent> eventType, GameEventPriority priority, BlockFromToEvent e) {\n        GameEventArgs.BlockFromToEvent blockFromToEvent = new GameEventArgs.BlockFromToEvent();\n        blockFromToEvent.block = e.getBlock();\n        blockFromToEvent.toBlock = e.getToBlock();\n        return eventType.createEvent(blockFromToEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockGrowEvent> createGameEvent(GameEventType<GameEventArgs.BlockGrowEvent> eventType, GameEventPriority priority, BlockGrowEvent e) {\n        GameEventArgs.BlockGrowEvent blockGrowEvent = new GameEventArgs.BlockGrowEvent();\n        blockGrowEvent.block = e.getBlock();\n        blockGrowEvent.newState = e.getNewState();\n        return eventType.createEvent(blockGrowEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockIgniteEvent> createGameEvent(GameEventType<GameEventArgs.BlockIgniteEvent> eventType, GameEventPriority priority, BlockIgniteEvent e) {\n        GameEventArgs.BlockIgniteEvent blockIgniteEvent = new GameEventArgs.BlockIgniteEvent();\n        blockIgniteEvent.block = e.getBlock();\n        blockIgniteEvent.igniteCause = e.getCause();\n        return eventType.createEvent(blockIgniteEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockPhysicsEvent> createGameEvent(GameEventType<GameEventArgs.BlockPhysicsEvent> eventType, GameEventPriority priority, BlockPhysicsEvent e) {\n        GameEventArgs.BlockPhysicsEvent blockPhysicsEvent = new GameEventArgs.BlockPhysicsEvent();\n        blockPhysicsEvent.block = e.getBlock();\n        return eventType.createEvent(blockPhysicsEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockPlaceEvent> createGameEvent(GameEventType<GameEventArgs.BlockPlaceEvent> eventType, GameEventPriority priority, BlockPlaceEvent e) {\n        GameEventArgs.BlockPlaceEvent blockPlaceEvent = new GameEventArgs.BlockPlaceEvent();\n        blockPlaceEvent.block = e.getBlock();\n        blockPlaceEvent.player = e.getPlayer();\n        blockPlaceEvent.againstBlock = e.getBlockAgainst();\n        blockPlaceEvent.replacedState = e.getBlockReplacedState();\n        blockPlaceEvent.usedHand = BukkitItems.getHand(e);\n        blockPlaceEvent.usedItem = getHandItem(e.getPlayer(), blockPlaceEvent.usedHand, true, () -> e.getItemInHand());\n        return eventType.createEvent(blockPlaceEvent);\n    }\n\n    private GameEvent<GameEventArgs.BlockRedstoneEvent> createGameEvent(GameEventType<GameEventArgs.BlockRedstoneEvent> eventType, GameEventPriority priority, BlockRedstoneEvent e) {\n        GameEventArgs.BlockRedstoneEvent blockRedstoneEvent = new GameEventArgs.BlockRedstoneEvent();\n        blockRedstoneEvent.block = e.getBlock();\n        return eventType.createEvent(blockRedstoneEvent);\n    }\n\n    private void cancelBlockRedstoneEvent(BlockRedstoneEvent bukkitEvent, GameEvent<GameEventArgs.BlockRedstoneEvent> gameEvent) {\n        if (gameEvent.isCancelled())\n            bukkitEvent.setNewCurrent(0);\n    }\n\n    private GameEvent<GameEventArgs.BlockSpreadEvent> createGameEvent(GameEventType<GameEventArgs.BlockSpreadEvent> eventType, GameEventPriority priority, BlockSpreadEvent e) {\n        GameEventArgs.BlockSpreadEvent blockSpreadEvent = new GameEventArgs.BlockSpreadEvent();\n        blockSpreadEvent.block = e.getBlock();\n        blockSpreadEvent.newState = e.getNewState();\n        blockSpreadEvent.source = e.getSource();\n        return eventType.createEvent(blockSpreadEvent);\n    }\n\n    private GameEvent<GameEventArgs.LeavesDecayEvent> createGameEvent(GameEventType<GameEventArgs.LeavesDecayEvent> eventType, GameEventPriority priority, LeavesDecayEvent e) {\n        GameEventArgs.LeavesDecayEvent leavesDecayEvent = new GameEventArgs.LeavesDecayEvent();\n        leavesDecayEvent.block = e.getBlock();\n        return eventType.createEvent(leavesDecayEvent);\n    }\n\n    private GameEvent<GameEventArgs.PistonExtendEvent> createGameEvent(GameEventType<GameEventArgs.PistonExtendEvent> eventType, GameEventPriority priority, BlockPistonExtendEvent e) {\n        GameEventArgs.PistonExtendEvent pistonExtendEvent = new GameEventArgs.PistonExtendEvent();\n        pistonExtendEvent.block = e.getBlock();\n        pistonExtendEvent.blocks = e.getBlocks();\n        pistonExtendEvent.direction = e.getDirection();\n        return eventType.createEvent(pistonExtendEvent);\n    }\n\n    private GameEvent<GameEventArgs.PistonRetractEvent> createGameEvent(GameEventType<GameEventArgs.PistonRetractEvent> eventType, GameEventPriority priority, BlockPistonRetractEvent e) {\n        GameEventArgs.PistonRetractEvent pistonRetractEvent = new GameEventArgs.PistonRetractEvent();\n        pistonRetractEvent.block = e.getBlock();\n        pistonRetractEvent.blocks = e.getBlocks();\n        pistonRetractEvent.direction = e.getDirection();\n        return eventType.createEvent(pistonRetractEvent);\n    }\n\n    /*\n     * WORLD EVENTS\n     */\n\n    private GameEvent<GameEventArgs.ChunkLoadEvent> createGameEvent(GameEventType<GameEventArgs.ChunkLoadEvent> eventType, GameEventPriority priority, ChunkLoadEvent e) {\n        GameEventArgs.ChunkLoadEvent chunkLoadEvent = new GameEventArgs.ChunkLoadEvent();\n        chunkLoadEvent.chunk = e.getChunk();\n        chunkLoadEvent.isNewChunk = e.isNewChunk();\n        return eventType.createEvent(chunkLoadEvent);\n    }\n\n    private GameEvent<GameEventArgs.ChunkUnloadEvent> createGameEvent(GameEventType<GameEventArgs.ChunkUnloadEvent> eventType, GameEventPriority priority, ChunkUnloadEvent e) {\n        GameEventArgs.ChunkUnloadEvent chunkUnloadEvent = new GameEventArgs.ChunkUnloadEvent();\n        chunkUnloadEvent.chunk = e.getChunk();\n        return eventType.createEvent(chunkUnloadEvent);\n    }\n\n    private GameEvent<GameEventArgs.SignChangeEvent> createGameEvent(GameEventType<GameEventArgs.SignChangeEvent> eventType, GameEventPriority priority, SignChangeEvent e) {\n        GameEventArgs.SignChangeEvent signChangeEvent = new GameEventArgs.SignChangeEvent();\n        signChangeEvent.block = e.getBlock();\n        signChangeEvent.player = e.getPlayer();\n        signChangeEvent.lines = e.getLines();\n        return eventType.createEvent(signChangeEvent);\n    }\n\n    private GameEvent<GameEventArgs.StructureGrowEvent> createGameEvent(GameEventType<GameEventArgs.StructureGrowEvent> eventType, GameEventPriority priority, StructureGrowEvent e) {\n        GameEventArgs.StructureGrowEvent structureGrowEvent = new GameEventArgs.StructureGrowEvent();\n        structureGrowEvent.world = e.getWorld();\n        structureGrowEvent.location = e.getLocation();\n        structureGrowEvent.blocks = e.getBlocks();\n        return eventType.createEvent(structureGrowEvent);\n    }\n\n    private GameEvent<GameEventArgs.WorldUnloadEvent> createGameEvent(GameEventType<GameEventArgs.WorldUnloadEvent> eventType, GameEventPriority priority, WorldUnloadEvent e) {\n        GameEventArgs.WorldUnloadEvent worldUnloadEvent = new GameEventArgs.WorldUnloadEvent();\n        worldUnloadEvent.world = e.getWorld();\n        return eventType.createEvent(worldUnloadEvent);\n    }\n\n    /*\n     * ENTITY EVENTS\n     */\n\n    private GameEvent<GameEventArgs.EntityBlockFormEvent> createGameEvent(GameEventType<GameEventArgs.EntityBlockFormEvent> eventType, GameEventPriority priority, EntityBlockFormEvent e) {\n        GameEventArgs.EntityBlockFormEvent entityBlockFormEvent = new GameEventArgs.EntityBlockFormEvent();\n        entityBlockFormEvent.block = e.getBlock();\n        entityBlockFormEvent.newState = e.getNewState();\n        entityBlockFormEvent.entity = e.getEntity();\n        return eventType.createEvent(entityBlockFormEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityChangeBlockEvent> createGameEvent(GameEventType<GameEventArgs.EntityChangeBlockEvent> eventType, GameEventPriority priority, EntityChangeBlockEvent e) {\n        GameEventArgs.EntityChangeBlockEvent entityChangeBlockEvent = new GameEventArgs.EntityChangeBlockEvent();\n\n        entityChangeBlockEvent.entity = e.getEntity();\n        entityChangeBlockEvent.block = e.getBlock();\n        if (ServerVersion.isLegacy()) {\n            // noinspection deprecated\n            entityChangeBlockEvent.newType = Keys.of(e.getTo(), e.getData());\n        } else {\n            entityChangeBlockEvent.newType = Keys.of(e.getTo(), (byte) 0);\n        }\n\n        return eventType.createEvent(entityChangeBlockEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityCollisionEvent> createGameEvent(GameEventType<GameEventArgs.EntityCollisionEvent> eventType, GameEventPriority priority, VehicleEntityCollisionEvent e) {\n        GameEventArgs.EntityCollisionEvent entityCollisionEvent = new GameEventArgs.EntityCollisionEvent();\n        entityCollisionEvent.entity = e.getEntity();\n        entityCollisionEvent.target = e.getVehicle();\n        return eventType.createEvent(entityCollisionEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityDamageEvent> createGameEvent(GameEventType<GameEventArgs.EntityDamageEvent> eventType, GameEventPriority priority, EntityDamageByEntityEvent e) {\n        GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent();\n        entityDamageEvent.entity = e.getEntity();\n        entityDamageEvent.damageCause = e.getCause();\n        entityDamageEvent.damager = e.getDamager();\n        return eventType.createEvent(entityDamageEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityDamageEvent> createGameEvent(GameEventType<GameEventArgs.EntityDamageEvent> eventType, GameEventPriority priority, EntityDamageEvent e) {\n        GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent();\n        entityDamageEvent.entity = e.getEntity();\n        entityDamageEvent.damageCause = e.getCause();\n        entityDamageEvent.damager = null;\n        return eventType.createEvent(entityDamageEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityDamageEvent> createGameEvent(GameEventType<GameEventArgs.EntityDamageEvent> eventType, GameEventPriority priority, VehicleDamageEvent e) {\n        GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent();\n        entityDamageEvent.entity = e.getVehicle();\n        entityDamageEvent.damager = e.getAttacker();\n        entityDamageEvent.damageCause = EntityDamageEvent.DamageCause.ENTITY_ATTACK;\n        return eventType.createEvent(entityDamageEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityEnterPortalEvent> createGameEvent(GameEventType<GameEventArgs.EntityEnterPortalEvent> eventType, GameEventPriority priority, EntityPortalEnterEvent e) {\n        GameEventArgs.EntityEnterPortalEvent entityEnterPortalEvent = new GameEventArgs.EntityEnterPortalEvent();\n        entityEnterPortalEvent.entity = e.getEntity();\n        entityEnterPortalEvent.portalLocation = e.getLocation();\n        return eventType.createEvent(entityEnterPortalEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityExplodeEvent> createGameEvent(GameEventType<GameEventArgs.EntityExplodeEvent> eventType, GameEventPriority priority, EntityExplodeEvent e) {\n        GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent();\n        entityExplodeEvent.entity = e.getEntity();\n        entityExplodeEvent.blocks = e.blockList();\n        entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE;\n        return eventType.createEvent(entityExplodeEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityInteractEvent> createGameEvent(GameEventType<GameEventArgs.EntityInteractEvent> eventType, GameEventPriority priority, EntityInteractEvent e) {\n        GameEventArgs.EntityInteractEvent entityExplodeEvent = new GameEventArgs.EntityInteractEvent();\n        entityExplodeEvent.entity = e.getEntity();\n        entityExplodeEvent.block = e.getBlock();\n        return eventType.createEvent(entityExplodeEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityMoveEvent> createGameEvent(GameEventType<GameEventArgs.EntityMoveEvent> eventType, GameEventPriority priority, PlayerMoveEvent e) {\n        Location from = e.getFrom();\n        Location to = e.getTo();\n\n        if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY())\n            return null;\n\n        GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent();\n        entityMoveEvent.entity = e.getPlayer();\n        entityMoveEvent.from = e.getFrom();\n        entityMoveEvent.to = e.getTo();\n        return eventType.createEvent(entityMoveEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityMoveEvent> createGameEvent(GameEventType<GameEventArgs.EntityMoveEvent> eventType, GameEventPriority priority, VehicleMoveEvent e) {\n        Location from = e.getFrom();\n        Location to = e.getTo();\n\n        if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY())\n            return null;\n\n        GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent();\n        entityMoveEvent.entity = e.getVehicle();\n        entityMoveEvent.from = e.getFrom();\n        entityMoveEvent.to = e.getTo();\n        return eventType.createEvent(entityMoveEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityPortalEvent> createGameEvent(GameEventType<GameEventArgs.EntityPortalEvent> eventType, GameEventPriority priority, EntityPortalEvent e) {\n        GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent();\n        entityPortalEvent.entity = e.getEntity();\n        entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END ||\n                e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ?\n                PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL;\n        entityPortalEvent.from = e.getFrom();\n        entityPortalEvent.to = e.getTo();\n        return eventType.createEvent(entityPortalEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityPortalEvent> createGameEvent(GameEventType<GameEventArgs.EntityPortalEvent> eventType, GameEventPriority priority, PlayerPortalEvent e) {\n        GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent();\n        entityPortalEvent.entity = e.getPlayer();\n        entityPortalEvent.cause = e.getTo() == null ? e.getCause() :\n                e.getTo().getWorld().getEnvironment() == World.Environment.THE_END ||\n                        e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ?\n                        PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL;\n        entityPortalEvent.from = e.getFrom();\n        entityPortalEvent.to = e.getTo();\n        return eventType.createEvent(entityPortalEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityRideEvent> createGameEvent(GameEventType<GameEventArgs.EntityRideEvent> eventType, GameEventPriority priority, VehicleEnterEvent e) {\n        GameEventArgs.EntityRideEvent entityRideEvent = new GameEventArgs.EntityRideEvent();\n        entityRideEvent.entity = e.getEntered();\n        entityRideEvent.vehicle = e.getVehicle();\n        return eventType.createEvent(entityRideEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntitySpawnEvent> createGameEvent(GameEventType<GameEventArgs.EntitySpawnEvent> eventType, GameEventPriority priority, CreatureSpawnEvent e) {\n        GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent();\n        entitySpawnEvent.entity = e.getEntity();\n        entitySpawnEvent.spawnReason = e.getSpawnReason();\n        return eventType.createEvent(entitySpawnEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntitySpawnEvent> createGameEvent(GameEventType<GameEventArgs.EntitySpawnEvent> eventType, GameEventPriority priority, HangingPlaceEvent e) {\n        GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent();\n        entitySpawnEvent.entity = e.getEntity();\n        entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT;\n        return eventType.createEvent(entitySpawnEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntitySpawnEvent> createGameEvent(GameEventType<GameEventArgs.EntitySpawnEvent> eventType, GameEventPriority priority, ItemSpawnEvent e) {\n        GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent();\n        entitySpawnEvent.entity = e.getEntity();\n        entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT;\n        return eventType.createEvent(entitySpawnEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntitySpawnEvent> createGameEvent(GameEventType<GameEventArgs.EntitySpawnEvent> eventType, GameEventPriority priority, VehicleCreateEvent e) {\n        GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent();\n        entitySpawnEvent.entity = e.getVehicle();\n        entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT;\n        return eventType.createEvent(entitySpawnEvent);\n    }\n\n    private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent<GameEventArgs.EntitySpawnEvent> gameEvent) {\n        if (gameEvent.isCancelled())\n            bukkitEvent.getVehicle().remove();\n    }\n\n    private GameEvent<GameEventArgs.EntityTargetEvent> createGameEvent(GameEventType<GameEventArgs.EntityTargetEvent> eventType, GameEventPriority priority, EntityTargetEvent e) {\n        GameEventArgs.EntityTargetEvent entityTargetEvent = new GameEventArgs.EntityTargetEvent();\n        entityTargetEvent.entity = e.getEntity();\n        entityTargetEvent.target = e.getTarget();\n        return eventType.createEvent(entityTargetEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityTeleportEvent> createGameEvent(GameEventType<GameEventArgs.EntityTeleportEvent> eventType, GameEventPriority priority, EntityTeleportEvent e) {\n        GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent();\n        entityTeleportEvent.entity = e.getEntity();\n        entityTeleportEvent.from = e.getFrom();\n        entityTeleportEvent.to = e.getTo();\n        entityTeleportEvent.cause = PlayerTeleportEvent.TeleportCause.UNKNOWN;\n        return eventType.createEvent(entityTeleportEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityTeleportEvent> createGameEvent(GameEventType<GameEventArgs.EntityTeleportEvent> eventType, GameEventPriority priority, PlayerTeleportEvent e) {\n        GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent();\n        entityTeleportEvent.entity = e.getPlayer();\n        entityTeleportEvent.from = e.getFrom();\n        entityTeleportEvent.to = e.getTo();\n        entityTeleportEvent.cause = e.getCause();\n        return eventType.createEvent(entityTeleportEvent);\n    }\n\n    private GameEvent<GameEventArgs.HangingBreakEvent> createGameEvent(GameEventType<GameEventArgs.HangingBreakEvent> eventType, GameEventPriority priority, HangingBreakByEntityEvent e) {\n        GameEventArgs.HangingBreakEvent hangingBreakEvent = new GameEventArgs.HangingBreakEvent();\n        hangingBreakEvent.entity = e.getEntity();\n        hangingBreakEvent.remover = e.getRemover();\n        hangingBreakEvent.removeCause = e.getCause();\n        return eventType.createEvent(hangingBreakEvent);\n    }\n\n    private GameEvent<GameEventArgs.HangingPlaceEvent> createGameEvent2(GameEventType<GameEventArgs.HangingPlaceEvent> eventType, GameEventPriority priority, HangingPlaceEvent e) {\n        GameEventArgs.HangingPlaceEvent hangingPlaceEvent = new GameEventArgs.HangingPlaceEvent();\n        hangingPlaceEvent.entity = e.getEntity();\n        hangingPlaceEvent.player = e.getPlayer();\n        return eventType.createEvent(hangingPlaceEvent);\n    }\n\n    private GameEvent<GameEventArgs.ProjectileHitEvent> createGameEvent(GameEventType<GameEventArgs.ProjectileHitEvent> eventType, GameEventPriority priority, ProjectileHitEvent e) {\n        GameEventArgs.ProjectileHitEvent projectileHitEvent = new GameEventArgs.ProjectileHitEvent();\n        projectileHitEvent.entity = e.getEntity();\n        if (PROJECTILE_HIT_TARGET_ENTITY.isValid())\n            projectileHitEvent.hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e);\n        if (PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid())\n            projectileHitEvent.hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e);\n        return eventType.createEvent(projectileHitEvent);\n    }\n\n    private GameEvent<GameEventArgs.ProjectileLaunchEvent> createGameEvent(GameEventType<GameEventArgs.ProjectileLaunchEvent> eventType, GameEventPriority priority, ProjectileLaunchEvent e) {\n        GameEventArgs.ProjectileLaunchEvent projectileLaunchEvent = new GameEventArgs.ProjectileLaunchEvent();\n        projectileLaunchEvent.entity = e.getEntity();\n        return eventType.createEvent(projectileLaunchEvent);\n    }\n\n    private GameEvent<GameEventArgs.EntityDeathEvent> createGameEvent(GameEventType<GameEventArgs.EntityDeathEvent> eventType, GameEventPriority priority, EntityDeathEvent e) {\n        GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent();\n        entityDeathEvent.entity = e.getEntity();\n        return eventType.createEvent(entityDeathEvent);\n    }\n\n    /*\n     * INVENTORY EVENTS\n     */\n\n    private GameEvent<GameEventArgs.InventoryClickEvent> createGameEvent(GameEventType<GameEventArgs.InventoryClickEvent> eventType, GameEventPriority priority, InventoryClickEvent e) {\n        GameEventArgs.InventoryClickEvent inventoryClickEvent = new GameEventArgs.InventoryClickEvent();\n        inventoryClickEvent.bukkitEvent = e;\n        return eventType.createEvent(inventoryClickEvent);\n    }\n\n    private GameEvent<GameEventArgs.InventoryCloseEvent> createGameEvent(GameEventType<GameEventArgs.InventoryCloseEvent> eventType, GameEventPriority priority, InventoryCloseEvent e) {\n        GameEventArgs.InventoryCloseEvent inventoryCloseEvent = new GameEventArgs.InventoryCloseEvent();\n        inventoryCloseEvent.bukkitEvent = e;\n        return eventType.createEvent(inventoryCloseEvent);\n    }\n\n    private GameEvent<GameEventArgs.InventoryOpenEvent> createGameEvent(GameEventType<GameEventArgs.InventoryOpenEvent> eventType, GameEventPriority priority, InventoryOpenEvent e) {\n        GameEventArgs.InventoryOpenEvent inventoryOpenEvent = new GameEventArgs.InventoryOpenEvent();\n        inventoryOpenEvent.bukkitEvent = e;\n        return eventType.createEvent(inventoryOpenEvent);\n    }\n\n    /*\n     * PLAYER EVENTS\n     */\n\n    private GameEvent<GameEventArgs.PlayerChangedWorldEvent> createGameEvent(GameEventType<GameEventArgs.PlayerChangedWorldEvent> eventType, GameEventPriority priority, PlayerChangedWorldEvent e) {\n        GameEventArgs.PlayerChangedWorldEvent playerChangedWorldEvent = new GameEventArgs.PlayerChangedWorldEvent();\n        playerChangedWorldEvent.player = e.getPlayer();\n        playerChangedWorldEvent.from = e.getFrom();\n        return eventType.createEvent(playerChangedWorldEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerCommandEvent> createGameEvent(GameEventType<GameEventArgs.PlayerCommandEvent> eventType, GameEventPriority priority, PlayerCommandPreprocessEvent e) {\n        GameEventArgs.PlayerCommandEvent playerCommandEvent = new GameEventArgs.PlayerCommandEvent();\n        playerCommandEvent.player = e.getPlayer();\n        playerCommandEvent.command = e.getMessage();\n        return eventType.createEvent(playerCommandEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerDropItemEvent> createGameEvent(GameEventType<GameEventArgs.PlayerDropItemEvent> eventType, GameEventPriority priority, PlayerDropItemEvent e) {\n        GameEventArgs.PlayerDropItemEvent playerDropItemEvent = new GameEventArgs.PlayerDropItemEvent();\n        playerDropItemEvent.player = e.getPlayer();\n        playerDropItemEvent.droppedItem = e.getItemDrop();\n        return eventType.createEvent(playerDropItemEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerEmptyBucketEvent> createGameEvent(GameEventType<GameEventArgs.PlayerEmptyBucketEvent> eventType, GameEventPriority priority, PlayerBucketEmptyEvent e) {\n        GameEventArgs.PlayerEmptyBucketEvent playerEmptyBucketEvent = new GameEventArgs.PlayerEmptyBucketEvent();\n        playerEmptyBucketEvent.player = e.getPlayer();\n        playerEmptyBucketEvent.bucket = e.getBucket();\n        playerEmptyBucketEvent.clickedBlock = e.getBlockClicked();\n        return eventType.createEvent(playerEmptyBucketEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerFillBucketEvent> createGameEvent(GameEventType<GameEventArgs.PlayerFillBucketEvent> eventType, GameEventPriority priority, PlayerBucketFillEvent e) {\n        GameEventArgs.PlayerFillBucketEvent playerFillBucketEvent = new GameEventArgs.PlayerFillBucketEvent();\n        playerFillBucketEvent.player = e.getPlayer();\n        playerFillBucketEvent.bucket = e.getBucket();\n        playerFillBucketEvent.clickedBlock = e.getBlockClicked();\n        return eventType.createEvent(playerFillBucketEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerGamemodeChangeEvent> createGameEvent(GameEventType<GameEventArgs.PlayerGamemodeChangeEvent> eventType, GameEventPriority priority, PlayerGameModeChangeEvent e) {\n        GameEventArgs.PlayerGamemodeChangeEvent playerGamemodeChangeEvent = new GameEventArgs.PlayerGamemodeChangeEvent();\n        playerGamemodeChangeEvent.player = e.getPlayer();\n        playerGamemodeChangeEvent.newGamemode = e.getNewGameMode();\n        return eventType.createEvent(playerGamemodeChangeEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerInteractEvent> createGameEvent(GameEventType<GameEventArgs.PlayerInteractEvent> eventType, GameEventPriority priority, PlayerInteractAtEntityEvent e) {\n        GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent();\n        playerInteractEvent.player = e.getPlayer();\n        playerInteractEvent.action = Action.RIGHT_CLICK_AIR;\n        playerInteractEvent.usedHand = BukkitItems.getHand(e);\n        playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null);\n        playerInteractEvent.clickedEntity = e.getRightClicked();\n        return eventType.createEvent(playerInteractEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerInteractEvent> createGameEvent(GameEventType<GameEventArgs.PlayerInteractEvent> eventType, GameEventPriority priority, PlayerInteractEntityEvent e) {\n        GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent();\n        playerInteractEvent.player = e.getPlayer();\n        playerInteractEvent.action = Action.RIGHT_CLICK_AIR;\n        playerInteractEvent.usedHand = BukkitItems.getHand(e);\n        playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null);\n        playerInteractEvent.clickedEntity = e.getRightClicked();\n        return eventType.createEvent(playerInteractEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerInteractEvent> createGameEvent(GameEventType<GameEventArgs.PlayerInteractEvent> eventType, GameEventPriority priority, PlayerInteractEvent e) {\n        GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent();\n        playerInteractEvent.player = e.getPlayer();\n        playerInteractEvent.action = e.getAction();\n        playerInteractEvent.usedHand = BukkitItems.getHand(e);\n        playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, () -> e.getItem());\n        playerInteractEvent.clickedBlock = e.getClickedBlock();\n        return eventType.createEvent(playerInteractEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerItemConsumeEvent> createGameEvent(GameEventType<GameEventArgs.PlayerItemConsumeEvent> eventType, GameEventPriority priority, PlayerItemConsumeEvent e) {\n        GameEventArgs.PlayerItemConsumeEvent playerItemConsumeEvent = new GameEventArgs.PlayerItemConsumeEvent();\n        playerItemConsumeEvent.player = e.getPlayer();\n        playerItemConsumeEvent.consumedItem = e.getItem();\n        return eventType.createEvent(playerItemConsumeEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerJoinEvent> createGameEvent(GameEventType<GameEventArgs.PlayerJoinEvent> eventType, GameEventPriority priority, PlayerJoinEvent e) {\n        GameEventArgs.PlayerJoinEvent playerJoinEvent = new GameEventArgs.PlayerJoinEvent();\n        playerJoinEvent.player = e.getPlayer();\n        return eventType.createEvent(playerJoinEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerLeashEntityEvent> createGameEvent(GameEventType<GameEventArgs.PlayerLeashEntityEvent> eventType, GameEventPriority priority, PlayerLeashEntityEvent e) {\n        GameEventArgs.PlayerLeashEntityEvent playerLeashEntityEvent = new GameEventArgs.PlayerLeashEntityEvent();\n        playerLeashEntityEvent.player = e.getPlayer();\n        playerLeashEntityEvent.entity = e.getEntity();\n        return eventType.createEvent(playerLeashEntityEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerLoginEvent> createGameEvent(GameEventType<GameEventArgs.PlayerLoginEvent> eventType, GameEventPriority priority, PlayerLoginEvent e) {\n        GameEventArgs.PlayerLoginEvent playerLoginEvent = new GameEventArgs.PlayerLoginEvent();\n        playerLoginEvent.player = e.getPlayer();\n        return eventType.createEvent(playerLoginEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerPickupItemEvent> createGameEvent(GameEventType<GameEventArgs.PlayerPickupItemEvent> eventType, GameEventPriority priority, PlayerPickupItemEvent e) {\n        GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent();\n        playerPickupItemEvent.player = e.getPlayer();\n        playerPickupItemEvent.pickedUpItem = e.getItem();\n        return eventType.createEvent(playerPickupItemEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerQuitEvent> createGameEvent(GameEventType<GameEventArgs.PlayerQuitEvent> eventType, GameEventPriority priority, PlayerQuitEvent e) {\n        GameEventArgs.PlayerQuitEvent playerQuitEvent = new GameEventArgs.PlayerQuitEvent();\n        playerQuitEvent.player = e.getPlayer();\n        return eventType.createEvent(playerQuitEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerRespawnEvent> createGameEvent(GameEventType<GameEventArgs.PlayerRespawnEvent> eventType, GameEventPriority priority, PlayerRespawnEvent e) {\n        GameEventArgs.PlayerRespawnEvent playerRespawnEvent = new GameEventArgs.PlayerRespawnEvent();\n        playerRespawnEvent.player = e.getPlayer();\n        playerRespawnEvent.bukkitEvent = e;\n        return eventType.createEvent(playerRespawnEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerShearEntityEvent> createGameEvent(GameEventType<GameEventArgs.PlayerShearEntityEvent> eventType, GameEventPriority priority, PlayerShearEntityEvent e) {\n        GameEventArgs.PlayerShearEntityEvent playerShearEntityEvent = new GameEventArgs.PlayerShearEntityEvent();\n        playerShearEntityEvent.player = e.getPlayer();\n        playerShearEntityEvent.entity = e.getEntity();\n        return eventType.createEvent(playerShearEntityEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerUnleashEntityEvent> createGameEvent(GameEventType<GameEventArgs.PlayerUnleashEntityEvent> eventType, GameEventPriority priority, PlayerUnleashEntityEvent e) {\n        GameEventArgs.PlayerUnleashEntityEvent playerUnleashEntityEvent = new GameEventArgs.PlayerUnleashEntityEvent();\n        playerUnleashEntityEvent.player = e.getPlayer();\n        playerUnleashEntityEvent.entity = e.getEntity();\n        return eventType.createEvent(playerUnleashEntityEvent);\n    }\n\n    private GameEvent<GameEventArgs.PlayerChatEvent> createGameEvent(GameEventType<GameEventArgs.PlayerChatEvent> eventType, GameEventPriority priority, AsyncPlayerChatEvent e) {\n        GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent();\n        playerChatEvent.player = e.getPlayer();\n        playerChatEvent.message = e.getMessage();\n        playerChatEvent.format = e.getFormat();\n        return eventType.createEvent(playerChatEvent);\n    }\n\n    /*\n     * INTERNALS\n     */\n\n    private <E extends Event, Args extends IEventArgs> void createEventListener(GameEventType<Args> eventType,\n                                                                                Class<E> bukkitEventClass,\n                                                                                GameEventCreator<Args, E> function) {\n        createEventListener(eventType, bukkitEventClass, function, null);\n    }\n\n    private <E extends Event, Args extends IEventArgs> void createEventListener(GameEventType<Args> eventType,\n                                                                                Class<E> bukkitEventClass,\n                                                                                GameEventCreator<Args, E> function,\n                                                                                @Nullable ApplyBukkitEventFunction<E, Args> applyBukkitEventFunction) {\n        Map<GameEventPriority, List<EventCallback>> callbacks = plugin.getGameEventsDispatcher().getCallbacks(eventType);\n        if (!callbacks.isEmpty()) {\n            callbacks.keySet().forEach(priority ->\n                    createEventListenerForPriority(eventType, bukkitEventClass, priority, function, applyBukkitEventFunction));\n        }\n    }\n\n    private <E extends Event, Args extends IEventArgs> void createEventListenerForPriority(GameEventType<Args> eventType,\n                                                                                           Class<E> bukkitEventClass,\n                                                                                           GameEventPriority gameEventPriority,\n                                                                                           GameEventCreator<Args, E> function,\n                                                                                           @Nullable ApplyBukkitEventFunction<E, Args> applyBukkitEventFunction) {\n        EventPriority bukkitEventPriority = EventPriority.valueOf(gameEventPriority.name());\n        plugin.getServer().getPluginManager().registerEvent(bukkitEventClass, this, bukkitEventPriority, (listener, event) -> {\n            if (!bukkitEventClass.isAssignableFrom(event.getClass()))\n                return;\n\n            IEventsDispatcher customEventsDispatcher = plugin.getEventsDispatcher();\n            if (customEventsDispatcher != null) {\n                if (customEventsDispatcher.notifyEvent(event, bukkitEventPriority))\n                    return;\n                if (!customEventsDispatcher.shouldFallbackToDefaultExecutorOnFailure())\n                    return;\n            }\n\n            GameEvent<Args> gameEvent = function.execute(eventType, gameEventPriority, (E) event);\n            if (gameEvent == null)\n                return;\n\n            boolean cancelledBeforeDispatch = false;\n\n            if (event instanceof Cancellable && ((Cancellable) event).isCancelled()) {\n                gameEvent.setCancelled();\n                cancelledBeforeDispatch = true;\n            }\n\n            plugin.getGameEventsDispatcher().onGameEvent(gameEvent, gameEventPriority);\n            if (!cancelledBeforeDispatch && gameEvent.isCancelled()) {\n                if (event instanceof Cancellable)\n                    ((Cancellable) event).setCancelled(true);\n            }\n            if (applyBukkitEventFunction != null)\n                applyBukkitEventFunction.apply((E) event, gameEvent);\n        }, plugin, false);\n    }\n\n    private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean clone, @Nullable Supplier<ItemStack> defItem) {\n        ItemStack itemStack = BukkitItems.getHandItem(player, usedHand);\n        if (clone && itemStack != null) {\n            itemStack = itemStack.clone();\n        }\n        if (defItem != null && (itemStack == null || itemStack.getType() == Material.AIR))\n            itemStack = defItem.get();\n        return itemStack;\n    }\n\n    public interface GameEventCreator<Args extends IEventArgs, E extends Event> {\n\n        @Nullable\n        GameEvent<Args> execute(GameEventType<Args> eventType, GameEventPriority priority, E e);\n\n    }\n\n    private interface ApplyBukkitEventFunction<E, Args extends IEventArgs> {\n\n        void apply(E bukkitEvent, GameEvent<Args> event);\n\n    }\n\n    /*\n     * SPECIAL EVENTS\n     */\n\n    private static class SpongeAbsorbEventFunction implements GameEventCreator<GameEventArgs.SpongeAbsorbEvent, org.bukkit.event.block.SpongeAbsorbEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.SpongeAbsorbEvent> execute(GameEventType<GameEventArgs.SpongeAbsorbEvent> eventType, GameEventPriority priority, org.bukkit.event.block.SpongeAbsorbEvent e) {\n            GameEventArgs.SpongeAbsorbEvent spongeAbsorbEvent = new GameEventArgs.SpongeAbsorbEvent();\n            spongeAbsorbEvent.block = e.getBlock();\n            spongeAbsorbEvent.blocks = e.getBlocks();\n            return eventType.createEvent(spongeAbsorbEvent);\n        }\n    }\n\n    private class EntityRemoveFromWorldEventFunction implements GameEventCreator<GameEventArgs.EntityDeathEvent, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.EntityDeathEvent> execute(GameEventType<GameEventArgs.EntityDeathEvent> eventType, GameEventPriority priority, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent e) {\n            Location entityLocation = e.getEntity().getLocation();\n\n            BukkitExecutor.sync(() -> {\n                if (e.getEntity().isValid() && !e.getEntity().isDead())\n                    return;\n\n                World world = entityLocation.getWorld();\n                int chunkX = entityLocation.getBlockX() >> 4;\n                int chunkZ = entityLocation.getBlockZ() >> 4;\n                // We don't want call this event if\n                if (world.isChunkLoaded(chunkX, chunkZ)) {\n                    GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent();\n                    entityDeathEvent.entity = e.getEntity();\n                    GameEvent<GameEventArgs.EntityDeathEvent> gameEvent = eventType.createEvent(entityDeathEvent);\n                    plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority);\n                }\n            }, 1L);\n\n            return null;\n        }\n    }\n\n    private class AsyncChatEventFunctions implements\n            GameEventCreator<GameEventArgs.PlayerChatEvent, io.papermc.paper.event.player.AsyncChatEvent>,\n            ApplyBukkitEventFunction<io.papermc.paper.event.player.AsyncChatEvent, GameEventArgs.PlayerChatEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.PlayerChatEvent> execute(GameEventType<GameEventArgs.PlayerChatEvent> eventType, GameEventPriority priority, io.papermc.paper.event.player.AsyncChatEvent e) {\n            GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent();\n            playerChatEvent.player = e.getPlayer();\n            playerChatEvent.message = LegacyComponentSerializer.legacyAmpersand().serialize(e.message());\n            return eventType.createEvent(playerChatEvent);\n        }\n\n        @Override\n        public void apply(io.papermc.paper.event.player.AsyncChatEvent bukkitEvent, GameEvent<GameEventArgs.PlayerChatEvent> event) {\n            plugin.getNMSAlgorithms().handlePaperChatRenderer(bukkitEvent);\n        }\n\n    }\n\n    private static class PlayerPickupArrowEventFunctions implements GameEventCreator<GameEventArgs.PlayerPickupArrowEvent, org.bukkit.event.player.PlayerPickupArrowEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.PlayerPickupArrowEvent> execute(GameEventType<GameEventArgs.PlayerPickupArrowEvent> eventType, GameEventPriority priority, org.bukkit.event.player.PlayerPickupArrowEvent e) {\n            GameEventArgs.PlayerPickupArrowEvent playerPickupArrowEvent = new GameEventArgs.PlayerPickupArrowEvent();\n            playerPickupArrowEvent.player = e.getPlayer();\n            playerPickupArrowEvent.pickedUpItem = e.getItem();\n            return eventType.createEvent(playerPickupArrowEvent);\n        }\n\n    }\n\n    private static class PlayerPickupItemEventFunctions implements GameEventCreator<GameEventArgs.PlayerPickupItemEvent, org.bukkit.event.player.PlayerAttemptPickupItemEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.PlayerPickupItemEvent> execute(GameEventType<GameEventArgs.PlayerPickupItemEvent> eventType, GameEventPriority priority, org.bukkit.event.player.PlayerAttemptPickupItemEvent e) {\n            GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent();\n            playerPickupItemEvent.player = e.getPlayer();\n            playerPickupItemEvent.pickedUpItem = e.getItem();\n            return eventType.createEvent(playerPickupItemEvent);\n        }\n\n    }\n\n    private static class RaidTriggerEventFunctions implements GameEventCreator<GameEventArgs.RaidTriggerEvent, org.bukkit.event.raid.RaidTriggerEvent> {\n\n        @Override\n        public GameEvent<GameEventArgs.RaidTriggerEvent> execute(GameEventType<GameEventArgs.RaidTriggerEvent> eventType, GameEventPriority priority, org.bukkit.event.raid.RaidTriggerEvent e) {\n            GameEventArgs.RaidTriggerEvent raidTriggerEvent = new GameEventArgs.RaidTriggerEvent();\n            raidTriggerEvent.world = e.getWorld();\n            raidTriggerEvent.player = e.getPlayer();\n            raidTriggerEvent.raidLocation = e.getRaid().getLocation();\n            return eventType.createEvent(raidTriggerEvent);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.Listener;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class BukkitListeners {\n\n    private static final Pattern LISTENER_REGISTER_FAILURE =\n            Pattern.compile(\"Plugin SuperiorSkyblock2 v(.*) has failed to register events for (.*) because (.*) does not exist\\\\.\");\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    private String listenerRegisterFailure = \"\";\n\n    public BukkitListeners(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public void registerListeners() {\n        new AdminPlayersListener(this.plugin);\n        new ChunksListener(this.plugin);\n        new EntityTrackingListener(this.plugin);\n        new FeaturesListener(this.plugin);\n        new IslandFlagsListener(this.plugin);\n        new IslandWorldEventsListener(this.plugin);\n        new MenusListener(this.plugin);\n        new PlayersListener(this.plugin);\n        new PortalsListener(this.plugin);\n        new ProtectionListener(this.plugin);\n        new SignsListener(this.plugin);\n        new StackedBlocksListener(this.plugin);\n        new WorldDestructionListener(this.plugin);\n\n        if (plugin.getSettings().isStopLeaving())\n            new IslandOutsideListener(this.plugin);\n\n        if (plugin.getSettings().isAutoBlocksTracking())\n            new BlockChangesListener(this.plugin);\n\n        if (!plugin.getSettings().getIslandPreviews().getLocations().isEmpty())\n            new IslandPreviewListener(this.plugin);\n\n        safeEventsRegister(new BukkitEventsListener(this.plugin));\n    }\n\n    public void unregisterListeners() {\n        plugin.getGameEventsDispatcher().clearCallbacks();\n        HandlerList.unregisterAll(this.plugin);\n    }\n\n    public void registerListenerFailureFilter() {\n        plugin.getLogger().setFilter(record -> {\n            Matcher matcher = LISTENER_REGISTER_FAILURE.matcher(record.getMessage());\n            if (matcher.find())\n                listenerRegisterFailure = matcher.group(3);\n\n            return true;\n        });\n    }\n\n    private void safeEventsRegister(Listener listener) {\n        listenerRegisterFailure = \"\";\n        plugin.getServer().getPluginManager().registerEvents(listener, plugin);\n        if (!listenerRegisterFailure.isEmpty())\n            throw new RuntimeException(listenerRegisterFailure);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.cache.IslandCache;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCalculationAlgorithm;\nimport com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ChunksListener extends AbstractGameEventListener {\n\n    private final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    public ChunksListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n\n        registerCallback(GameEventType.CHUNK_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onChunkUnload);\n        registerCallback(GameEventType.WORLD_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onWorldUnload);\n        registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad);\n    }\n\n    private void onChunkUnload(GameEvent<GameEventArgs.ChunkUnloadEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().chunk.getWorld()))\n            return;\n\n        handleChunkUnload(e.getArgs().chunk);\n    }\n\n    private void onWorldUnload(GameEvent<GameEventArgs.WorldUnloadEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().world))\n            return;\n\n        for (Chunk loadedChunk : e.getArgs().world.getLoadedChunks())\n            handleChunkUnload(loadedChunk);\n    }\n\n    private void onChunkLoad(GameEvent<GameEventArgs.ChunkLoadEvent> e) {\n        handleChunkLoad(e.getArgs().chunk, e.getArgs().isNewChunk);\n    }\n\n    /* INTERNAL */\n\n    private void handleChunkUnload(Chunk chunk) {\n        plugin.getStackedBlocks().removeStackedBlockHolograms(chunk);\n\n        List<Island> chunkIslands = plugin.getGrid().getIslandsAt(chunk);\n        chunkIslands.forEach(island -> {\n            if (!island.isSpawn())\n                handleIslandChunkUnload(island, chunk);\n        });\n    }\n\n    private void handleIslandChunkUnload(Island island, Chunk chunk) {\n        if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class))\n            plugin.getNMSChunks().startTickingChunk(island, chunk, true);\n\n        if (!plugin.getNMSChunks().isChunkEmpty(chunk))\n            island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true);\n\n        Arrays.stream(chunk.getEntities()).forEach(this.worldRecordService.get()::recordEntityDespawn);\n    }\n\n    private void handleChunkLoad(Chunk chunk, boolean isNewChunk) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(chunk.getWorld()))\n            return;\n\n        List<Island> chunkIslands = plugin.getGrid().getIslandsAt(chunk);\n        chunkIslands.forEach(island -> {\n            if (!island.isSpawn()) {\n                try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) {\n                    handleIslandChunkLoad(island, chunk, chunkPosition, isNewChunk);\n                }\n            }\n        });\n    }\n\n    private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chunkPosition, boolean isNewChunk) {\n        World world = chunk.getWorld();\n        Dimension dimension = plugin.getGrid().getIslandsWorldDimension(world);\n\n        if (isNewChunk && dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n            Biome defaultWorldBiome = IslandUtils.getDefaultWorldBiome(dimension);\n            // We want to update the biome for new island chunks.\n            if (island.getBiome() != defaultWorldBiome) {\n                List<Player> playersToUpdate;\n                try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) {\n                    playersToUpdate = strategy.getPlayers(WorldInfo.of(world));\n                }\n                plugin.getNMSChunks().setBiome(Collections.singletonList(chunkPosition), island.getBiome(), playersToUpdate);\n            }\n        }\n\n        plugin.getNMSChunks().injectChunkSections(chunk);\n\n        IslandCache islandCache = island.getCache();\n\n        Set<Chunk> pendingLoadedChunksForIsland = islandCache.computeIfAbsent(IslandCacheKeys.PENDING_LOADED_CHUNKS,\n                k -> new LinkedHashSet<>());\n        pendingLoadedChunksForIsland.add(chunk);\n\n        boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class);\n        if (cropGrowthEnabled && island.isInsideRange(chunk))\n            plugin.getNMSChunks().startTickingChunk(island, chunk, false);\n\n        if (!plugin.getNMSChunks().isChunkEmpty(chunk))\n            island.markChunkDirty(world, chunk.getX(), chunk.getZ(), true);\n\n        BlockPosition islandCenter = island.getCenterPosition();\n\n        boolean entityLimitsEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class);\n        MutableBoolean recalculateEntities = new MutableBoolean(false);\n\n        if (chunk.getX() == (islandCenter.getX() >> 4) && chunk.getZ() == (islandCenter.getZ() >> 4)) {\n            if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) {\n                Block chunkBlock = chunk.getBlock(0, 100, 0);\n                island.setBiome(world.getBiome(chunkBlock.getX(), chunkBlock.getZ()), false);\n            }\n\n            if (entityLimitsEnabled)\n                recalculateEntities.set(true);\n        }\n\n        BukkitExecutor.sync(() -> {\n            if (chunk.isLoaded())\n                // Update holograms of stacked blocks in delay so the chunk is entirely loaded.\n                plugin.getStackedBlocks().updateStackedBlockHolograms(chunk);\n        }, 10L);\n\n        BukkitExecutor.sync(() -> {\n            if (!pendingLoadedChunksForIsland.remove(chunk) || !chunk.isLoaded())\n                return;\n\n            // If we cannot recalculate entities at this moment, we want to track entities normally.\n            if (!island.getEntitiesTracker().canRecalculateEntityCounts())\n                recalculateEntities.set(false);\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                for (Entity entity : chunk.getEntities()) {\n                    // We want to delete old holograms of stacked blocks + count entities for the chunk\n                    if (entity instanceof ArmorStand && isOldHologram((ArmorStand) entity) &&\n                            plugin.getStackedBlocks().getStackedBlockAmount(entity.getLocation(wrapper.getHandle()).subtract(0, 1, 0)) > 1) {\n                        entity.remove();\n                    }\n                }\n            }\n\n            if (recalculateEntities.get()) {\n                island.getEntitiesTracker().recalculateEntityCounts();\n                pendingLoadedChunksForIsland.clear();\n                islandCache.remove(IslandCacheKeys.PENDING_LOADED_CHUNKS);\n            }\n        }, 2L);\n\n        DefaultIslandCalculationAlgorithm.CACHED_CALCULATED_CHUNKS.write(cache -> cache.remove(chunkPosition));\n    }\n\n    private static boolean isOldHologram(ArmorStand armorStand) {\n        return !armorStand.hasGravity() && armorStand.isSmall() && !armorStand.isVisible() &&\n                armorStand.isCustomNameVisible() && armorStand.isMarker() && armorStand.getCustomName() != null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.entity.Entity;\n\npublic class EntityTrackingListener extends AbstractGameEventListener {\n\n    private final LazyReference<WorldRecordService> worldRecordService = new LazyReference<WorldRecordService>() {\n        @Override\n        protected WorldRecordService create() {\n            return plugin.getServices().getService(WorldRecordService.class);\n        }\n    };\n\n    public EntityTrackingListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        this.registerListeners();\n    }\n\n    private void onEntitySpawn(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        this.worldRecordService.get().recordEntitySpawn(entity);\n    }\n\n    private void onEntityDeath(GameEvent<GameEventArgs.EntityDeathEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        worldRecordService.get().recordEntityDespawn(entity);\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn);\n        registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onEntityDeath);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectField;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class FeaturesListener extends AbstractGameEventListener {\n\n    private static final EnumerateMap<PluginEventType<?>, PlaceholdersPopulator<?>> POPULATORS = new EnumerateMap<>(PluginEventType.values());\n\n    @Nullable\n    private static final Material VAULT = EnumHelper.getEnum(Material.class, \"VAULT\");\n    @Nullable\n    private static final Material TRIAL_SPAWNER = EnumHelper.getEnum(Material.class, \"TRIAL_SPAWNER\");\n    @Nullable\n    private static final Material SCULK_SENSOR = EnumHelper.getEnum(Material.class, \"SCULK_SENSOR\");\n    @Nullable\n    private static final Material SCULK_SHRIEKER = EnumHelper.getEnum(Material.class, \"SCULK_SHRIEKER\");\n\n    private final LazyReference<RegionManagerService> protectionManager = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public FeaturesListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    /* EVENT COMMANDS */\n\n    private void onGeneralPluginEvent(PluginEvent<?> event) {\n        List<String> commands = plugin.getSettings().getEventCommands().get(event.getType().getBukkitEventName());\n\n        if (commands == null)\n            return;\n\n        Map<String, String> placeholdersReplaces = new HashMap<>();\n\n        PlaceholdersPopulator placeholdersPopulator = POPULATORS.computeIfAbsent(event.getType(),\n                type -> createPlaceholdersPopulator(event.getArgs().getClass()));\n        if (placeholdersPopulator != null)\n            placeholdersPopulator.populate(event.getArgs(), placeholdersReplaces);\n\n        BukkitExecutor.ensureMain(() -> {\n            for (String command : commands) {\n                for (Map.Entry<String, String> replaceEntry : placeholdersReplaces.entrySet())\n                    command = command.replace(replaceEntry.getKey(), replaceEntry.getValue());\n                Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);\n            }\n        });\n    }\n\n    /* OBSIDIAN TO LAVA */\n\n    private void onObsidianClick(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Player player = e.getArgs().player;\n        ItemStack handItem = e.getArgs().usedItem;\n        Block clickedBlock = e.getArgs().clickedBlock;\n\n        if (handItem == null || clickedBlock == null || handItem.getType() != Material.BUCKET ||\n                clickedBlock.getType() != Material.OBSIDIAN)\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld()))\n            return;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) != 1)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(clickedBlock.getLocation(wrapper.getHandle()));\n        }\n        if (island == null)\n            return;\n\n        e.setCancelled();\n\n\n        ItemStack inHandItem = handItem.clone();\n        inHandItem.setAmount(inHandItem.getAmount() - 1);\n\n        PlayerHand usedHand = e.getArgs().usedHand;\n        BukkitItems.setHandItem(player, usedHand, inHandItem.getAmount() == 0 ? null : inHandItem);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), player.getInventory(),\n                    player.getLocation(wrapper.getHandle()));\n        }\n\n        island.handleBlockBreak(ConstantKeys.OBSIDIAN, 1);\n\n        clickedBlock.setType(Material.AIR);\n    }\n\n    /* VISITORS BLOCKED COMMANDS */\n\n    private void onPlayerCommandAsVisitor(GameEvent<GameEventArgs.PlayerCommandEvent> e) {\n        Player player = e.getArgs().player;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(player.getWorld()))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer.hasBypassModeEnabled())\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null || island.isSpawn() || !island.isVisitor(superiorPlayer, true))\n            return;\n\n        String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(\" \");\n\n        String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0];\n\n        if (plugin.getSettings().getBlockedVisitorsCommands().stream().anyMatch(commandLabel::contains)) {\n            e.setCancelled();\n            Message.VISITOR_BLOCK_COMMAND.send(superiorPlayer);\n        }\n    }\n\n    /* PREVIEW BLOCKED COMMANDS */\n\n    private void onPlayerCommandWhilePreview(GameEvent<GameEventArgs.PlayerCommandEvent> e) {\n        Player player = e.getArgs().player;\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer.hasBypassModeEnabled())\n            return;\n\n        IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer);\n        if (islandPreview == null)\n            return;\n\n        String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(\" \");\n\n        String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0];\n\n        if (plugin.getSettings().getIslandPreviews().getBlockedCommands().stream().anyMatch(commandLabel::contains)) {\n            e.setCancelled();\n            Message.ISLAND_PREVIEW_BLOCK_COMMAND.send(superiorPlayer);\n        }\n    }\n\n    /* BLOCKS TRACKING */\n\n    private void onChunkLoad(GameEvent<GameEventArgs.ChunkLoadEvent> e) {\n        Chunk chunk = e.getArgs().chunk;\n        List<Island> chunkIslands = plugin.getGrid().getIslandsAt(chunk);\n        chunkIslands.forEach(island -> handleIslandChunkLoad(island, chunk));\n    }\n\n    private void handleIslandChunkLoad(Island island, Chunk chunk) {\n        List<Location> blockEntities = plugin.getNMSChunks().getBlockEntities(chunk);\n\n        if (blockEntities.isEmpty())\n            return;\n\n        blockEntities.forEach(blockEntity -> {\n            plugin.getNMSWorld().replaceSculkSensorListener(island, blockEntity);\n            plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockEntity);\n        });\n    }\n\n    /* VAULTS & TRIAL SPAWNERS */\n\n    private void onTrialBlockPlace(GameEvent<GameEventArgs.BlockPlaceEvent> e) {\n        Block block = e.getArgs().block;\n        Material blockType = block.getType();\n\n        if (blockType != VAULT && blockType != TRIAL_SPAWNER)\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n            if (island == null)\n                return;\n\n            plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockLocation);\n        }\n    }\n\n    /* SCULK SENSORS */\n\n    private void onSculkSensorPlace(GameEvent<GameEventArgs.BlockPlaceEvent> e) {\n        Block block = e.getArgs().block;\n        Material blockType = block.getType();\n\n        if (blockType != SCULK_SENSOR)\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n            if (island == null)\n                return;\n\n            plugin.getNMSWorld().replaceSculkSensorListener(island, blockLocation);\n        }\n    }\n\n    private void onSculkShriekerInteract(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        Block clickedBlock = e.getArgs().clickedBlock;\n\n        if (action != Action.PHYSICAL || clickedBlock.getType() != SCULK_SHRIEKER)\n            return;\n\n        InteractionResult interactionResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n            Location blockLocation = clickedBlock.getLocation(wrapper.getHandle());\n            interactionResult = protectionManager.get().handleCustomInteraction(superiorPlayer,\n                    blockLocation, IslandPrivileges.SCULK_SENSOR);\n        }\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false))\n            e.setCancelled();\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        for (PluginEventType<?> eventType : PluginEventType.values()) {\n            String bukkitEventName = eventType.getBukkitEventName();\n            if (bukkitEventName != null && plugin.getSettings().getEventCommands().containsKey(bukkitEventName))\n                plugin.getPluginEventsDispatcher().registerCallback(eventType, this::onGeneralPluginEvent);\n        }\n\n        if (plugin.getSettings().isObsidianToLava())\n            registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick);\n        if (!plugin.getSettings().getBlockedVisitorsCommands().isEmpty())\n            registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandAsVisitor);\n        if (!plugin.getSettings().getIslandPreviews().getBlockedCommands().isEmpty())\n            registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandWhilePreview);\n\n        registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad);\n\n        if (VAULT != null && TRIAL_SPAWNER != null) {\n            registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onTrialBlockPlace);\n        }\n\n        if (SCULK_SENSOR != null && SCULK_SHRIEKER != null) {\n            registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onSculkSensorPlace);\n            registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSculkShriekerInteract);\n        }\n    }\n\n    private static <Args extends PluginEventArgs> PlaceholdersPopulator<Args> createPlaceholdersPopulator(Class<?> argsClass) {\n        List<FieldData<?>> fieldsData = new LinkedList<>();\n\n        collectAllFields(argsClass, field -> {\n            ReflectField<?> reflectField = new ReflectField<>(field.getDeclaringClass(), field.getType(), field.getName());\n            if (reflectField.isValid()) {\n                String placeholder = \"%\" + field.getName() + \"%\";\n                FieldData<?> fieldData = createFieldData(reflectField, field, placeholder);\n                fieldsData.add(fieldData);\n                if (field.getName().equals(\"superiorPlayer\"))\n                    fieldsData.add(new FieldData(fieldData.reflectField, \"%player%\", fieldData.toStringMethod));\n                else if (field.getName().equals(\"targetPlayer\"))\n                    fieldsData.add(new FieldData(fieldData.reflectField, \"%target%\", fieldData.toStringMethod));\n            }\n        });\n\n        return (args, placeholders) -> {\n            for (FieldData fieldData : fieldsData) {\n                Optional.ofNullable(fieldData.reflectField.get(args)).ifPresent(value ->\n                        placeholders.put(fieldData.placeholder, (String) fieldData.toStringMethod.apply(value)));\n            }\n        };\n\n    }\n\n    private static FieldData<?> createFieldData(ReflectField<?> reflectField, Field field, String placeholder) {\n        if (field.getType() == SuperiorPlayer.class)\n            return new FieldData<>((ReflectField<SuperiorPlayer>) reflectField, placeholder, SuperiorPlayer::getName);\n        else if (field.getType() == Island.class)\n            return new FieldData<>((ReflectField<Island>) reflectField, placeholder, Island::getName);\n        else if (field.getType() == Mission.class)\n            return new FieldData<>((ReflectField<Mission>) reflectField, placeholder, Mission::getName);\n        else if (field.getType() == String.class)\n            return new FieldData<>((ReflectField<String>) reflectField, placeholder, s -> s);\n        else\n            return new FieldData<>(reflectField, placeholder, String::valueOf);\n    }\n\n    private static void collectAllFields(Class<?> clazz, Consumer<Field> consumer) {\n        while (clazz != null && clazz != Object.class) {\n            for (Field field : clazz.getFields())\n                consumer.accept(field);\n            clazz = clazz.getSuperclass();\n        }\n    }\n\n    private interface PlaceholdersPopulator<T> {\n\n        void populate(T args, Map<String, String> placeholders);\n\n    }\n\n    private static class FieldData<T> {\n\n        private final ReflectField<T> reflectField;\n        private final Function<T, String> toStringMethod;\n        private final String placeholder;\n\n        FieldData(ReflectField<T> reflectField, String placeholder, Function<T, String> toStringMethod) {\n            this.reflectField = reflectField;\n            this.toStringMethod = toStringMethod;\n            this.placeholder = placeholder;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Chicken;\nimport org.bukkit.entity.Enderman;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Fireball;\nimport org.bukkit.entity.Ghast;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.LivingEntity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.block.BlockIgniteEvent;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.event.hanging.HangingBreakEvent;\nimport org.bukkit.potion.PotionEffectType;\nimport org.bukkit.projectiles.ProjectileSource;\n\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Optional;\n\npublic class IslandFlagsListener extends AbstractGameEventListener {\n\n    private static final EnumSet<CreatureSpawnEvent.SpawnReason> NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons();\n\n    private final Int2ObjectMapView<ProjectileSource> originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap();\n\n    private World spawnIslandWorld;\n\n    public IslandFlagsListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        this.registerListeners();\n    }\n\n    /* INTERNAL EVENTS */\n\n    private void onSpawnUpdate() {\n        // We want to optimize island checks only for island worlds\n        // However, if the spawn world is not an islands world, we want to check it as well.\n        Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(\n                plugin.getSettings().getWorlds().getDefaultWorldDimension());\n        this.spawnIslandWorld = spawnLocation.getWorld();\n    }\n\n    /* ENTITY SPAWNING */\n\n    private void onEntitySpawn(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(e.getArgs().entity.getWorld()))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = e.getArgs().entity.getLocation(wrapper.getHandle());\n\n            if (checkPreventEntitySpawn(e, location) || checkPreventEggLay(e, location))\n                e.setCancelled();\n        }\n    }\n\n    private boolean checkPreventEntitySpawn(GameEvent<GameEventArgs.EntitySpawnEvent> e, Location entityLocation) {\n        CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason;\n\n        if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER ||\n                spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) {\n            List<EntityCategory> entityCategories = BukkitEntities.getCategories(e.getArgs().entity);\n            IslandFlag islandFlag;\n            for (EntityCategory entityCategory : entityCategories) {\n                islandFlag = entityCategory.getSpawnerSpawningIslandFlag();\n                if (islandFlag != null && preventAction(entityLocation, islandFlag)) {\n                    return true;\n                }\n            }\n        } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) {\n            List<EntityCategory> entityCategories = BukkitEntities.getCategories(e.getArgs().entity);\n            IslandFlag islandFlag;\n            for (EntityCategory entityCategory : entityCategories) {\n                islandFlag = entityCategory.getNaturalSpawningIslandFlag();\n                if (islandFlag != null && preventAction(entityLocation, islandFlag)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    private boolean checkPreventEggLay(GameEvent<GameEventArgs.EntitySpawnEvent> e, Location entityLocation) {\n        if (!(e.getArgs().entity instanceof Item))\n            return false;\n\n        Item item = (Item) e.getArgs().entity;\n\n        if (item.getItemStack().getType() != Material.EGG)\n            return false;\n\n        if (preventAction(entityLocation, IslandFlags.EGG_LAY)) {\n            for (Entity entity : item.getNearbyEntities(1, 1, 1)) {\n                if (entity instanceof Chicken) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /* ENTITY EXPLOSIONS */\n\n    private void onHangingBreakByEntity(GameEvent<GameEventArgs.HangingBreakEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(entity.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = entity.getLocation(wrapper.getHandle());\n\n            HangingBreakEvent.RemoveCause removeCause = e.getArgs().removeCause;\n            Entity remover = e.getArgs().remover;\n\n            if (removeCause == HangingBreakEvent.RemoveCause.EXPLOSION) {\n                if (remover instanceof Player) {\n                    // Explosion was set by TNT.\n                    if (preventAction(entityLocation, IslandFlags.TNT_EXPLOSION)) {\n                        e.setCancelled();\n                        return;\n                    }\n                } else if (remover instanceof Ghast) {\n                    // Explosion was set by TNT.\n                    if (preventAction(entityLocation, IslandFlags.GHAST_FIREBALL)) {\n                        e.setCancelled();\n                        return;\n                    }\n                }\n            }\n\n            if (preventEntityExplosion(remover, entityLocation)) {\n                e.setCancelled();\n            }\n        }\n    }\n\n    private void onEntityExplode(GameEvent<GameEventArgs.EntityExplodeEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(entity.getWorld()))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventEntityExplosion(entity, entity.getLocation(wrapper.getHandle())))\n                e.getArgs().blocks.clear();\n        }\n    }\n\n    private void onEntityChangeBlock(GameEvent<GameEventArgs.EntityChangeBlockEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(block.getWorld()))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventEntityExplosion(e.getArgs().entity, block.getLocation(wrapper.getHandle())))\n                e.setCancelled();\n        }\n    }\n\n    private void onFireballDamage(GameEvent<GameEventArgs.EntityDamageEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(entity.getWorld())) {\n            return;\n        }\n\n        if (entity instanceof Fireball) {\n            originalFireballsDamager.put(entity.getEntityId(), ((Fireball) entity).getShooter());\n            BukkitExecutor.sync(() -> originalFireballsDamager.remove(entity.getEntityId()), 40L);\n        }\n    }\n\n    public boolean preventEntityExplosion(Entity source, Location explodeLocation) {\n        IslandFlag islandFlag;\n\n        switch (source.getType()) {\n            case CREEPER:\n                islandFlag = IslandFlags.CREEPER_EXPLOSION;\n                break;\n            case PRIMED_TNT:\n            case MINECART_TNT:\n                islandFlag = IslandFlags.TNT_EXPLOSION;\n                break;\n            case WITHER:\n            case WITHER_SKULL:\n                islandFlag = IslandFlags.WITHER_EXPLOSION;\n                break;\n            case FIREBALL: {\n                ProjectileSource projectileSource = originalFireballsDamager.remove(source.getEntityId());\n                if (projectileSource == null)\n                    projectileSource = ((Fireball) source).getShooter();\n                if (projectileSource instanceof Ghast) {\n                    islandFlag = IslandFlags.GHAST_FIREBALL;\n                    break;\n                }\n            }\n            default:\n                return false;\n        }\n\n        return preventAction(explodeLocation, islandFlag);\n    }\n\n    /* GENERAL EVENTS */\n\n    private void onBlockFlow(GameEvent<GameEventArgs.BlockFromToEvent> e) {\n        Block block = e.getArgs().block;\n        Block toBlock = e.getArgs().toBlock;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(toBlock.getWorld())) {\n            return;\n        }\n\n        IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(block) ?\n                IslandFlags.WATER_FLOW : IslandFlags.LAVA_FLOW;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventAction(toBlock.getLocation(wrapper.getHandle()), islandFlag))\n                e.setCancelled();\n        }\n    }\n\n    private void onCropsGrowth(GameEvent<GameEventArgs.BlockGrowEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH))\n                e.setCancelled();\n        }\n    }\n\n    private void onTreeGrowth(GameEvent<GameEventArgs.StructureGrowEvent> e) {\n        Location location = e.getArgs().location;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(location.getWorld())) {\n            return;\n        }\n\n        if (preventAction(location, IslandFlags.TREE_GROWTH))\n            e.setCancelled();\n    }\n\n    private void onFireSpread(GameEvent<GameEventArgs.BlockBurnEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD))\n                e.setCancelled();\n        }\n    }\n\n    private void onBlockIgnite(GameEvent<GameEventArgs.BlockIgniteEvent> e) {\n        if (e.getArgs().igniteCause != BlockIgniteEvent.IgniteCause.SPREAD)\n            return;\n\n        Block block = e.getArgs().block;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD))\n                e.setCancelled();\n        }\n    }\n\n    private void onEndermanGrief(GameEvent<GameEventArgs.EntityChangeBlockEvent> e) {\n        if (!(e.getArgs().entity instanceof Enderman))\n            return;\n\n        Block block = e.getArgs().block;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF))\n                e.setCancelled();\n        }\n    }\n\n    private void onPoisonAttack(GameEvent<GameEventArgs.ProjectileHitEvent> e) {\n        Entity entity = e.getArgs().entity;\n        EntityType entityType = entity.getType();\n\n        if (entityType != EntityType.SPLASH_POTION)\n            return;\n\n        // We only check island flags in relevant worlds\n        if (shouldIgnoreWorldEvents(entity.getWorld())) {\n            return;\n        }\n\n        BukkitEntities.getPlayerSource(entity).ifPresent(shooterPlayer -> {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (!preventAction(entity.getLocation(wrapper.getHandle()), IslandFlags.PVP))\n                    return;\n            }\n\n            List<Entity> nearbyEntities = entity.getNearbyEntities(2, 2, 2);\n\n            BukkitExecutor.sync(() -> nearbyEntities.forEach(nearbyEntity -> {\n                if (nearbyEntity instanceof LivingEntity && !nearbyEntity.getUniqueId().equals(shooterPlayer.getUniqueId()))\n                    ((LivingEntity) nearbyEntity).removePotionEffect(PotionEffectType.POISON);\n            }), 1L);\n        });\n    }\n\n    /* INTERNAL */\n\n    private boolean preventAction(Location location, IslandFlag islandFlag) {\n        Island island = plugin.getGrid().getIslandAt(location);\n        if (island == null)\n            return false;\n\n        if (!plugin.getSettings().getSpawn().isProtected() && island.isSpawn())\n            return false;\n\n        return !island.hasSettingsEnabled(islandFlag);\n    }\n\n    private void registerListeners() {\n        registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.LOWEST, this::onEntityExplode);\n        registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEntityChangeBlock);\n        registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEntitySpawn);\n        registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.LOWEST, this::onHangingBreakByEntity);\n        registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.MONITOR, this::onFireballDamage);\n        registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.LOWEST, this::onBlockFlow);\n        registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.LOWEST, this::onCropsGrowth);\n        registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.LOWEST, this::onTreeGrowth);\n        registerCallback(GameEventType.BLOCK_BURN_EVENT, GameEventPriority.LOWEST, this::onFireSpread);\n        registerCallback(GameEventType.BLOCK_IGNITE_EVENT, GameEventPriority.LOWEST, this::onBlockIgnite);\n        registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief);\n        registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack);\n        plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SPAWN_UPDATE_EVENT, this::onSpawnUpdate);\n    }\n\n    private boolean shouldIgnoreWorldEvents(@Nullable World world) {\n        return world == null || (world != this.spawnIslandWorld && !plugin.getGrid().isIslandsWorld(world));\n    }\n\n    private static EnumSet<CreatureSpawnEvent.SpawnReason> initializeNaturalSpawnReasons() {\n        EnumSet<CreatureSpawnEvent.SpawnReason> naturalSpawnReasons = EnumSet.noneOf(CreatureSpawnEvent.SpawnReason.class);\n\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"JOCKEY\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"CHUNK_GEN\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"NATURAL\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"TRAP\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"MOUNT\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"VILLAGE_INVASION\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"VILLAGE_DEFENSE\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"PATROL\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"BEEHIVE\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"LIGHTNING\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"DEFAULT\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"JOCKEY\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"JOCKEY\")).ifPresent(naturalSpawnReasons::add);\n        Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"JOCKEY\")).ifPresent(naturalSpawnReasons::add);\n\n        return naturalSpawnReasons;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\n\npublic class IslandOutsideListener extends AbstractGameEventListener {\n\n    public IslandOutsideListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n\n        registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onMinecartRightClick);\n        registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onEntityRide);\n        registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onEntityMove);\n    }\n\n    private void onMinecartRightClick(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Entity rightClicked = e.getArgs().clickedEntity;\n        if (rightClicked == null)\n            return;\n\n        if (!plugin.getGrid().isIslandsWorld(rightClicked.getWorld()))\n            return;\n\n        Player player = e.getArgs().player;\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n        if (superiorPlayer.hasBypassModeEnabled())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = rightClicked.getLocation(wrapper.getHandle());\n            Island entityIsland = plugin.getGrid().getIslandAt(entityLocation);\n\n            if (entityIsland != null && entityIsland.isInsideRange(entityLocation, 1D))\n                return;\n        }\n\n        e.setCancelled();\n    }\n\n    private void onEntityRide(GameEvent<GameEventArgs.EntityRideEvent> e) {\n        if (!plugin.getSettings().isStopLeaving())\n            return;\n\n        Entity vehicle = e.getArgs().vehicle;\n\n        if (!plugin.getGrid().isIslandsWorld(vehicle.getWorld()))\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        if (entity instanceof Player && plugin.getPlayers().getSuperiorPlayer(entity).hasBypassModeEnabled())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location vehicleLocation = vehicle.getLocation(wrapper.getHandle());\n            Island entityIsland = plugin.getGrid().getIslandAt(vehicleLocation);\n\n            if (entityIsland != null && entityIsland.isInsideRange(vehicleLocation, 1D))\n                return;\n        }\n\n        e.setCancelled();\n    }\n\n    private void onEntityMove(GameEvent<GameEventArgs.EntityMoveEvent> e) {\n        if (!plugin.getSettings().isStopLeaving())\n            return;\n\n        Location to = e.getArgs().to;\n        World destinationWorld = to.getWorld();\n\n        if (!plugin.getGrid().isIslandsWorld(destinationWorld))\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        if (!entity.getWorld().equals(destinationWorld))\n            return;\n\n        Location from = e.getArgs().from;\n\n        if (entity instanceof Player) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity);\n            if (handlePlayerMove(superiorPlayer, from, to, true, false))\n                e.setCancelled();\n        } else {\n            Entity passenger = entity.getPassenger();\n            SuperiorPlayer superiorPlayer = passenger instanceof Player ? plugin.getPlayers().getSuperiorPlayer(passenger) : null;\n\n            if (superiorPlayer == null)\n                return;\n\n            handlePlayerMove(superiorPlayer, from, to, false, true);\n        }\n    }\n\n    private boolean handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to,\n                                     boolean delayTeleport, boolean forceTeleport) {\n        if (superiorPlayer.hasBypassModeEnabled())\n            return false;\n\n        Island toIsland = plugin.getGrid().getIslandAt(to);\n        if (toIsland != null && toIsland.isInsideRange(to, 1D))\n            return false;\n\n        if (delayTeleport) {\n            // If we don't delay the teleport, it will not occur due to the cancellation of PlayerMoveEvent\n            BukkitExecutor.sync(() -> handlePlayerMoveOutsideIslandTeleport(superiorPlayer, from, forceTeleport), 1L);\n        } else {\n            handlePlayerMoveOutsideIslandTeleport(superiorPlayer, from, forceTeleport);\n        }\n\n        return true;\n    }\n\n    private void handlePlayerMoveOutsideIslandTeleport(SuperiorPlayer superiorPlayer, Location from, boolean forceTeleport) {\n        Island fromIsland = plugin.getGrid().getIslandAt(from);\n\n        Player player = superiorPlayer.asPlayer();\n\n        // We don't teleport in case we're inside the island, we just cancel the event.\n        // However, if the player is in vehicle, we want to eject him and teleport.\n        if (!forceTeleport && fromIsland != null && fromIsland.isInsideRange(from) && !player.isInsideVehicle())\n            return;\n\n        player.eject();\n\n        if (fromIsland != null) {\n            superiorPlayer.teleport(fromIsland, result -> {\n                if (!result) {\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                }\n            });\n        } else {\n            superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer;\nimport org.bukkit.GameMode;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\n\npublic class IslandPreviewListener extends AbstractGameEventListener {\n\n    public IslandPreviewListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n\n        registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit);\n        registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.NORMAL, this::onPlayerTeleport);\n    }\n\n    private void onPlayerQuit(GameEvent<GameEventArgs.PlayerQuitEvent> e) {\n        Player player = e.getArgs().player;\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        // Cancelling island preview mode\n        if (plugin.getGrid().getIslandPreview(superiorPlayer) != null) {\n            GameMode gameMode = plugin.getGrid().getIslandPreview(superiorPlayer).getPreviousGameMode();\n            plugin.getGrid().cancelIslandPreview(superiorPlayer);\n            /* cancelIslandPreview changes the GameMode and teleports the player later.\n            In this case tho, we want the things to be instant - no async, no nothing. */\n            player.setGameMode(gameMode);\n            player.teleport(plugin.getGrid().getSpawnIsland().getCenter(\n                    plugin.getSettings().getWorlds().getDefaultWorldDimension()));\n        }\n    }\n\n    private void onPlayerTeleport(GameEvent<GameEventArgs.EntityTeleportEvent> e) {\n        Entity entity = e.getArgs().entity;\n        if (!(entity instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        if (((Player) entity).getGameMode() == plugin.getSettings().getIslandPreviews().getGameMode() &&\n                plugin.getGrid().getIslandPreview(superiorPlayer) != null)\n            e.setCancelled();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Entity;\n\npublic class IslandWorldEventsListener extends AbstractGameEventListener {\n\n    private final LazyReference<HologramsService> hologramsService = new LazyReference<HologramsService>() {\n        @Override\n        protected HologramsService create() {\n            return plugin.getServices().getService(HologramsService.class);\n        }\n    };\n\n    public IslandWorldEventsListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n\n        if (plugin.getSettings().isDisableRedstoneOffline() || plugin.getSettings().getAFKIntegrations().isDisableRedstone())\n            registerCallback(GameEventType.BLOCK_REDSTONE_EVENT, GameEventPriority.HIGHEST, this::onBlockRedstone);\n\n        if (plugin.getSettings().getAFKIntegrations().isDisableSpawning())\n            registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.HIGHEST, this::onEntitySpawn);\n    }\n\n    private void onBlockRedstone(GameEvent<GameEventArgs.BlockRedstoneEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null || island.isSpawn())\n            return;\n\n        if ((plugin.getSettings().isDisableRedstoneOffline() && !island.isCurrentlyActive()) ||\n                (plugin.getSettings().getAFKIntegrations().isDisableRedstone() &&\n                        island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK))) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Log.debug(Debug.DISABLE_REDSTONE, island.getOwner().getName(), block.getLocation(wrapper.getHandle()));\n            }\n\n            e.setCancelled();\n        }\n    }\n\n    private void onEntitySpawn(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        Entity entity = e.getArgs().entity;\n\n        if (hologramsService.get().isHologram(entity))\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null || island.isSpawn() || !island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK))\n            return;\n\n        e.setCancelled();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.InventoryView;\nimport org.bukkit.inventory.ItemStack;\n\npublic class MenusListener extends AbstractGameEventListener {\n\n    private final Int2ObjectMapView<ItemStack> latestClickedItem = CollectionsFactory.createInt2ObjectArrayMap();\n\n    public MenusListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n\n        registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.MONITOR, false, this::onInventoryClickDupePatch);\n        registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.MONITOR, false, this::onInventoryCloseDupePatch);\n        registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, this::onMenuClick);\n        registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.NORMAL, this::onMenuClose);\n    }\n\n    /*\n     * The following two events are here for patching a dupe glitch caused\n     * by shift clicking and closing the inventory at the same time.\n     */\n\n    private void onInventoryClickDupePatch(GameEvent<GameEventArgs.InventoryClickEvent> e) {\n        if (!e.isCancelled())\n            return;\n\n        ItemStack clickedItem = e.getArgs().bukkitEvent.getCurrentItem();\n        Inventory inventory = e.getArgs().bukkitEvent.getClickedInventory();\n\n        if (clickedItem != null && inventory != null && inventory.getHolder() instanceof MenuView) {\n            int entityId = e.getArgs().bukkitEvent.getWhoClicked().getEntityId();\n            latestClickedItem.put(entityId, clickedItem);\n            BukkitExecutor.sync(() -> latestClickedItem.remove(entityId), 20L);\n        }\n    }\n\n    private void onInventoryCloseDupePatch(GameEvent<GameEventArgs.InventoryCloseEvent> e) {\n        Player player = (Player) e.getArgs().bukkitEvent.getPlayer();\n        ItemStack clickedItem = latestClickedItem.remove(player.getEntityId());\n        if (clickedItem != null) {\n            BukkitExecutor.sync(() -> {\n                player.getInventory().removeItem(clickedItem);\n                player.updateInventory();\n            }, 1L);\n        }\n    }\n\n    /* MENU INTERACTIONS HANDLING */\n\n    private void onMenuClick(GameEvent<GameEventArgs.InventoryClickEvent> e) {\n        InventoryView inventoryView = e.getArgs().bukkitEvent.getView();\n        Inventory clickedInventory = e.getArgs().bukkitEvent.getClickedInventory();\n\n        Inventory topInventory = inventoryView.getTopInventory();\n\n        if (topInventory == null || clickedInventory == null)\n            return;\n\n        InventoryHolder inventoryHolder = topInventory.getHolder();\n\n        if (inventoryHolder instanceof MenuView) {\n            e.setCancelled();\n\n            if (clickedInventory.equals(topInventory)) {\n                MenuView menuView = (MenuView) inventoryHolder;\n                menuView.getMenu().onClick(e.getArgs().bukkitEvent, menuView);\n            }\n        } else if (inventoryHolder instanceof StackedBlocksDepositMenu) {\n            ((StackedBlocksDepositMenu) inventoryHolder).onInteract(e.getArgs().bukkitEvent);\n        }\n    }\n\n    private void onMenuClose(GameEvent<GameEventArgs.InventoryCloseEvent> e) {\n        Inventory topInventory = e.getArgs().bukkitEvent.getView().getTopInventory();\n        InventoryHolder inventoryHolder = topInventory == null ? null : topInventory.getHolder();\n\n        if (inventoryHolder instanceof MenuView) {\n            MenuView menuView = (MenuView) inventoryHolder;\n            menuView.getMenu().onClose(e.getArgs().bukkitEvent, menuView);\n        } else if (inventoryHolder instanceof StackedBlocksDepositMenu) {\n            ((StackedBlocksDepositMenu) inventoryHolder).onClose(e.getArgs().bukkitEvent);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.HitActionResult;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChest;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.api.service.region.MoveResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.SIslandChest;\nimport com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer;\nimport com.bgsoftware.superiorskyblock.player.chat.PlayerChat;\nimport com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore;\nimport com.bgsoftware.superiorskyblock.player.respawn.RespawnActions;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Arrow;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.entity.EntityDamageEvent;\nimport org.bukkit.event.player.PlayerRespawnEvent;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.InventoryView;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class PlayersListener extends AbstractGameEventListener {\n\n    private final LazyReference<RegionManagerService> regionManagerService = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public PlayersListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    /* PLAYER NOTIFIERS */\n\n    private void onPlayerLogin(GameEvent<GameEventArgs.PlayerLoginEvent> e) {\n        Player player = e.getArgs().player;\n\n        List<SuperiorPlayer> duplicatedPlayers = plugin.getPlayers().matchAllPlayers(superiorPlayer ->\n                superiorPlayer.getName().equalsIgnoreCase(player.getName()) &&\n                        !superiorPlayer.getUniqueId().equals(player.getUniqueId()));\n\n        if (!duplicatedPlayers.isEmpty()) {\n            Log.info(\"Changing UUID of \" + player.getName() + \" to \" + player.getUniqueId());\n\n            SuperiorPlayer playerWithNewUUID = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), false);\n\n            if (playerWithNewUUID != null) {\n                // Even tho we have duplicates, there's already a record for the new player.\n                // Therefore, we just want to delete the old records from DB and cache.\n                Log.info(\"Detected a record for the new player uuid already - deleting old ones...\");\n                // Delete all records\n                duplicatedPlayers.forEach(duplicatedPlayer -> {\n                    plugin.getPlayers().replacePlayers(duplicatedPlayer, null);\n                    plugin.getPlayers().getPlayersContainer().removePlayer(duplicatedPlayer);\n                });\n                // We make sure the new player is correctly set in all caches by removing it and adding it.\n                plugin.getPlayers().getPlayersContainer().removePlayer(playerWithNewUUID);\n                plugin.getPlayers().getPlayersContainer().addPlayer(playerWithNewUUID);\n            } else {\n                // We first want to remove all original players.\n                duplicatedPlayers.forEach(plugin.getPlayers().getPlayersContainer()::removePlayer);\n\n                // We now want to create the new player.\n                SuperiorPlayer newPlayer = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), true, false);\n\n                // We now want to replace all existing players\n                duplicatedPlayers.forEach(originalPlayer -> {\n                    if (originalPlayer != newPlayer)\n                        plugin.getPlayers().replacePlayers(originalPlayer, newPlayer);\n                });\n            }\n        }\n    }\n\n    private void onPlayerJoin(GameEvent<GameEventArgs.PlayerJoinEvent> e) {\n        Player player = e.getArgs().player;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        // Updating the name of the player.\n        if (!superiorPlayer.getName().equals(player.getName())) {\n            PluginEventsFactory.callPlayerChangeNameEvent(superiorPlayer, player.getName());\n            superiorPlayer.updateName();\n        }\n\n        // Handling player join\n        if (superiorPlayer.isShownAsOnline())\n            IslandNotifications.notifyPlayerJoin(superiorPlayer);\n\n        // Refresh PermissionsStore\n        PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(player.getUniqueId());\n        if (permissionsStore != null)\n            permissionsStore.refreshCache(player);\n\n        MoveResult moveResult;\n        Island island;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location playerLocation = player.getLocation(wrapper.getHandle());\n            island = plugin.getGrid().getIslandAt(playerLocation);\n            moveResult = this.regionManagerService.get().handlePlayerJoin(superiorPlayer, playerLocation);\n        }\n\n        boolean teleportToSpawn = moveResult != MoveResult.SUCCESS;\n\n        BukkitExecutor.sync(() -> {\n            if (!player.isOnline())\n                return;\n\n            // Updating skin of the player\n            if (!plugin.getProviders().notifySkinsListeners(superiorPlayer))\n                plugin.getNMSPlayers().setSkinTexture(superiorPlayer);\n\n            if (!superiorPlayer.hasBypassModeEnabled()) {\n                Island delayedIsland;\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    delayedIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n                }\n                // Checking if the player is in the islands world, not inside an island.\n                if ((delayedIsland == island && teleportToSpawn) ||\n                        (plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld()) && delayedIsland == null)) {\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland());\n                    if (!teleportToSpawn)\n                        Message.ISLAND_GOT_DELETED_WHILE_INSIDE.send(superiorPlayer);\n                }\n            }\n\n            // Checking auto language detection\n            if (plugin.getSettings().isAutoLanguageDetection() && !player.hasPlayedBefore()) {\n                Locale playerLocale = plugin.getNMSPlayers().getPlayerLocale(player);\n                if (playerLocale != null && PlayerLocales.isValidLocale(playerLocale) &&\n                        !superiorPlayer.getUserLocale().equals(playerLocale)) {\n                    if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, playerLocale))\n                        superiorPlayer.setUserLocale(playerLocale);\n                }\n            }\n        }, 5L);\n    }\n\n    private void onPlayerQuit(GameEvent<GameEventArgs.PlayerQuitEvent> e) {\n        Player player = e.getArgs().player;\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        // Removing coop status from other islands.\n        for (Island coopIsland : superiorPlayer.getCoopIslands()) {\n            if (PluginEventsFactory.callIslandUncoopPlayerEvent(coopIsland, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) {\n                coopIsland.removeCoop(superiorPlayer);\n                IslandUtils.sendMessage(coopIsland, Message.UNCOOP_LEFT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName());\n            }\n        }\n\n        // Handling player quit\n        if (superiorPlayer.isShownAsOnline())\n            IslandNotifications.notifyPlayerQuit(superiorPlayer);\n\n        // Remove coop players\n        Island island = superiorPlayer.getIsland();\n        if (island != null && plugin.getSettings().isAutoUncoopWhenAlone() && !island.getCoopPlayers().isEmpty()) {\n            boolean shouldRemoveCoops = island.getIslandMembers(true).stream().noneMatch(islandMember ->\n                    islandMember != superiorPlayer && island.hasPermission(islandMember, IslandPrivileges.UNCOOP_MEMBER) && islandMember.isOnline());\n\n            if (shouldRemoveCoops) {\n                for (SuperiorPlayer coopPlayer : island.getCoopPlayers()) {\n                    island.removeCoop(coopPlayer);\n                    Message.UNCOOP_AUTO_ANNOUNCEMENT.send(coopPlayer);\n                }\n            }\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            this.regionManagerService.get().handlePlayerQuit(superiorPlayer, player.getLocation(wrapper.getHandle()));\n        }\n\n        // Remove all player chat-listeners\n        PlayerChat.remove(player);\n    }\n\n    private void onPlayerGameModeChange(GameEvent<GameEventArgs.PlayerGamemodeChangeEvent> e) {\n        Player player = e.getArgs().player;\n        if (e.getArgs().newGamemode == GameMode.SPECTATOR) {\n            IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(player));\n        } else if (player.getGameMode() == GameMode.SPECTATOR) {\n            IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(player));\n        }\n    }\n\n    /* PLAYER MOVES */\n\n    private void onPlayerMove(GameEvent<GameEventArgs.EntityMoveEvent> e) {\n        if (!(e.getArgs().entity instanceof Player))\n            return;\n\n        Player player = (Player) e.getArgs().entity;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        if (superiorPlayer.hasPlayerStatus(PlayerStatus.VOID_TELEPORT))\n            return;\n\n        MoveResult moveResult = this.regionManagerService.get().handlePlayerMove(\n                superiorPlayer, e.getArgs().from, e.getArgs().to);\n        switch (moveResult) {\n            case VOID_TELEPORT:\n            case SUCCESS:\n                break;\n            case LEAVE_ISLAND_TO_OUTSIDE:\n                // Only cancel the event if player is not inside vehicle. If the player is inside the vehicle,\n                // IslandOutsideListener will detect it and teleport him away.\n                if (!player.isInsideVehicle())\n                    e.setCancelled();\n                break;\n            default:\n                e.setCancelled();\n                break;\n        }\n    }\n\n    private void onPlayerTeleport(GameEvent<GameEventArgs.EntityTeleportEvent> e) {\n        if (e.getArgs().to == null || !(e.getArgs().entity instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity);\n\n        if (superiorPlayer == null)\n            return;\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        MoveResult moveResult = this.regionManagerService.get().handlePlayerTeleport(\n                superiorPlayer, e.getArgs().from, e.getArgs().to);\n        if (moveResult != MoveResult.SUCCESS)\n            e.setCancelled();\n    }\n\n    private void onPlayerChangeWorld(GameEvent<GameEventArgs.PlayerChangedWorldEvent> e) {\n        Player player = e.getArgs().player;\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld()))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n        }\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (island != null && superiorPlayer.hasIslandFlyEnabled() && !player.getAllowFlight() &&\n                island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) {\n            BukkitExecutor.sync(() -> {\n                player.setAllowFlight(true);\n                player.setFlying(true);\n            }, 1L);\n        }\n    }\n\n    /* PVP */\n\n    private void onPlayerDamage(GameEvent<GameEventArgs.EntityDamageEvent> e) {\n        if (!(e.getArgs().entity instanceof Player))\n            return;\n\n        Player player = (Player) e.getArgs().entity;\n        SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (targetPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) targetPlayer).release();\n            return;\n        }\n\n        SuperiorPlayer damagerPlayer = e.getArgs().damager == null ? null :\n                BukkitEntities.getPlayerSource(e.getArgs().damager)\n                        .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null);\n\n        // Some plugins, such as Sentinel, may actually cause a NPC to attack.\n        if (damagerPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) damagerPlayer).release();\n            return;\n        }\n\n        if (damagerPlayer == null) {\n            // We do not care about spawn island when spawn protection is disabled or player damage is enabled in spawn,\n            // and therefore only island worlds are relevant.\n            if ((!plugin.getSettings().getSpawn().isProtected() || plugin.getSettings().getSpawn().isPlayersDamage()) &&\n                    !plugin.getGrid().isIslandsWorld(player.getWorld()))\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n            }\n\n            if (island != null) {\n                if (island.isSpawn() ? (plugin.getSettings().getSpawn().isProtected() && !plugin.getSettings().getSpawn().isPlayersDamage()) :\n                        ((!plugin.getSettings().isCoopDamage() && island.isCoop(targetPlayer)) ||\n                                (!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, true))))\n                    e.setCancelled();\n            }\n\n            return;\n        }\n\n        boolean cancelFlames = false;\n        boolean cancelEvent = false;\n        Message messageToSend = null;\n\n        HitActionResult hitActionResult = damagerPlayer.canHit(targetPlayer);\n\n        switch (hitActionResult) {\n            case ISLAND_TEAM_PVP:\n                messageToSend = Message.HIT_ISLAND_MEMBER;\n                break;\n            case ISLAND_PVP_DISABLE:\n            case TARGET_ISLAND_PVP_DISABLE:\n                messageToSend = Message.HIT_PLAYER_IN_ISLAND;\n                break;\n        }\n\n        if (hitActionResult != HitActionResult.SUCCESS) {\n            cancelFlames = true;\n            cancelEvent = true;\n        }\n\n        if (cancelEvent)\n            e.setCancelled();\n\n        if (messageToSend != null)\n            messageToSend.send(damagerPlayer);\n\n        Player target = targetPlayer.asPlayer();\n\n        if (target != null && cancelFlames && e.getArgs().damager instanceof Arrow && target.getFireTicks() > 0)\n            target.setFireTicks(0);\n    }\n\n    /* CHAT */\n\n    private void onPlayerChatLowest(GameEvent<GameEventArgs.PlayerChatEvent> e) {\n        PlayerChat playerChat = PlayerChat.getChatListener(e.getArgs().player);\n        if (playerChat != null && playerChat.supply(e.getArgs().message))\n            e.setCancelled();\n    }\n\n    private void onPlayerChat(GameEvent<GameEventArgs.PlayerChatEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        Island island = superiorPlayer.getIsland();\n\n        if (superiorPlayer.hasTeamChatEnabled()) {\n            if (island == null) {\n                if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer))\n                    return;\n\n                superiorPlayer.toggleTeamChat();\n                return;\n            }\n\n            e.setCancelled();\n\n            String message = e.getArgs().message;\n\n            IslandUtils.handleIslandChat(island, superiorPlayer, message);\n        } else if (e.getArgs().format != null) {\n            e.getArgs().format = Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(e.getArgs().format, superiorPlayer, island));\n        }\n    }\n\n    /* SCHEMATICS */\n\n    private void onSchematicSelection(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        if (action != Action.RIGHT_CLICK_BLOCK && action != Action.LEFT_CLICK_BLOCK)\n            return;\n\n        Player player = e.getArgs().player;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (usedItem == null || usedItem.getType() != Materials.GOLDEN_AXE.toBukkitType())\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        if (!superiorPlayer.hasSchematicModeEnabled())\n            return;\n\n        e.setCancelled();\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Block clickedBlock = e.getArgs().clickedBlock;\n            Location location = clickedBlock.getLocation(wrapper.getHandle());\n            if (action == Action.RIGHT_CLICK_BLOCK) {\n                Message.SCHEMATIC_RIGHT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location));\n                superiorPlayer.setSchematicPos1(clickedBlock);\n            } else {\n                Message.SCHEMATIC_LEFT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location));\n                superiorPlayer.setSchematicPos2(clickedBlock);\n            }\n        }\n\n        if (superiorPlayer.getSchematicPos1() != null && superiorPlayer.getSchematicPos2() != null)\n            Message.SCHEMATIC_READY_TO_CREATE.send(superiorPlayer);\n    }\n\n    /* ISLAND CHESTS */\n\n    private void onIslandChestInteract(GameEvent<GameEventArgs.InventoryClickEvent> e) {\n        InventoryView inventoryView = e.getArgs().bukkitEvent.getView();\n\n        InventoryHolder inventoryHolder = inventoryView.getTopInventory() == null ? null : inventoryView.getTopInventory().getHolder();\n\n        if (!(inventoryHolder instanceof IslandChest))\n            return;\n\n        SIslandChest islandChest = (SIslandChest) inventoryHolder;\n\n        if (islandChest.isUpdating()) {\n            e.setCancelled();\n        } else {\n            islandChest.updateContents();\n        }\n    }\n\n    /* VOID TELEPORT */\n\n    private void onPlayerFall(GameEvent<GameEventArgs.EntityDamageEvent> e) {\n        if (e.getArgs().damageCause != EntityDamageEvent.DamageCause.FALL ||\n                !(e.getArgs().entity instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity);\n        if (superiorPlayer.hasPlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED)) {\n            e.setCancelled();\n        }\n\n    }\n\n    /* PLAYER DEATH */\n\n    private void onPlayerRespawn(GameEvent<GameEventArgs.PlayerRespawnEvent> e) {\n        PlayerRespawnEvent bukkitRespawnEvent = e.getArgs().bukkitEvent;\n        for (RespawnAction respawnAction : plugin.getSettings().getPlayerRespawn()) {\n            if (respawnAction == RespawnActions.VANILLA || respawnAction.canPerform(bukkitRespawnEvent)) {\n                respawnAction.perform(bukkitRespawnEvent);\n                return;\n            }\n        }\n    }\n\n    private void onPlayerRespawnMonitor(GameEvent<GameEventArgs.PlayerRespawnEvent> e) {\n        Location respawnLocation = e.getArgs().bukkitEvent.getRespawnLocation();\n        Player player = e.getArgs().player;\n\n        BukkitExecutor.sync(() -> {\n            if (!player.isOnline())\n                return;\n\n            Island respawnAtIsland = plugin.getGrid().getIslandAt(respawnLocation);\n            if (respawnAtIsland != null) {\n                SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n                superiorPlayer.updateWorldBorder(respawnAtIsland);\n            }\n        }, 2L);\n\n\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        registerCallback(GameEventType.PLAYER_LOGIN_EVENT, GameEventPriority.MONITOR, this::onPlayerLogin);\n        registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin);\n        registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit);\n        registerCallback(GameEventType.PLAYER_GAMEMODE_CHANGE, GameEventPriority.MONITOR, this::onPlayerGameModeChange);\n        registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onPlayerMove);\n        registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.HIGHEST, this::onPlayerTeleport);\n        registerCallback(GameEventType.PLAYER_CHANGED_WORLD_EVENT, GameEventPriority.MONITOR, this::onPlayerChangeWorld);\n        /* Set to NORMAL, so it doesn't conflict with vanish plugins */\n        registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerDamage);\n        registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, false, this::onSchematicSelection);\n        registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.LOWEST, this::onIslandChestInteract);\n        registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerFall);\n        registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.NORMAL, this::onPlayerRespawn);\n        registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.MONITOR, this::onPlayerRespawnMonitor);\n        // PlayerChat should be on LOWEST priority so other chat plugins don't conflict.\n        registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.LOWEST, this::onPlayerChatLowest);\n        registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.NORMAL, this::onPlayerChat);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult;\nimport com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Either;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport org.bukkit.Bukkit;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.player.PlayerTeleportEvent;\n\npublic class PortalsListener extends AbstractGameEventListener {\n\n    private final LazyReference<PortalsManagerService> portalsManager = new LazyReference<PortalsManagerService>() {\n        @Override\n        protected PortalsManagerService create() {\n            return plugin.getServices().getService(PortalsManagerService.class);\n        }\n    };\n\n    public PortalsListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    private void registerListeners() {\n        registerCallback(GameEventType.ENTITY_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityPortal);\n        registerCallback(GameEventType.ENTITY_ENTER_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityEnterPortal);\n    }\n\n    private void onEntityPortal(GameEvent<GameEventArgs.EntityPortalEvent> e) {\n        if (e.getArgs().entity instanceof Player)\n            handlePlayerPortal(e);\n        else\n            handleEntityPortalResult(e);\n    }\n\n    private void onEntityEnterPortal(GameEvent<GameEventArgs.EntityEnterPortalEvent> e) {\n        // Simulate portals in the following cases:\n        //  - Using an end portal in the end\n        //  - The target world is disabled\n\n        Entity entity = e.getArgs().entity;\n\n        Location portalLocation = e.getArgs().portalLocation;\n\n        World world = portalLocation.getWorld();\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle()));\n        }\n\n        if (island == null) {\n            if (plugin.getGrid().isIslandsWorld(world))\n                e.setCancelled();\n            return;\n        }\n\n        // Simulate end portal\n        if (world.getEnvironment() == World.Environment.THE_END) {\n            /* We teleport the player to his island instead of cancelling the event.\n            Therefore, we must prevent the player from acting like he entered another island or left his island.*/\n\n            SuperiorPlayer teleportedPlayer = entity instanceof Player ?\n                    plugin.getPlayers().getSuperiorPlayer((Player) entity) : null;\n\n            if (teleportedPlayer != null)\n                teleportedPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND);\n\n            BukkitExecutor.sync(() -> {\n                Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension();\n                IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n                    islandWorldResult.ifRight(error -> {\n                        if (teleportedPlayer != null)\n                            teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND);\n                    }).ifLeft(unused -> {\n                        EntityTeleports.teleportUntilSuccess(entity,\n                                island.getIslandHome(dimension), 5, () -> {\n                                    if (teleportedPlayer != null)\n                                        teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND);\n                                });\n                    });\n                });\n\n            }, 5L);\n        }\n\n        if (ServerVersion.isLessThan(ServerVersion.v1_16))\n            return;\n\n        boolean isPlayer = entity instanceof Player;\n\n        Material originalMaterial = portalLocation.getBlock().getType();\n\n        PortalType portalType = originalMaterial == Materials.NETHER_PORTAL.toBukkitType() ? PortalType.NETHER : PortalType.ENDER;\n\n        if (isPlayer && (portalType == PortalType.NETHER ? Bukkit.getAllowNether() : Bukkit.getAllowEnd()))\n            return;\n\n        if (portalType == PortalType.NETHER) {\n            int ticksDelay = !isPlayer ? 0 : ((Player) entity).getGameMode() == GameMode.CREATIVE ? 1 : 80;\n            int portalTicks = plugin.getNMSEntities().getPortalTicks(entity);\n            if (portalTicks != ticksDelay)\n                return;\n        }\n\n        if (isPlayer) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(entity);\n            this.portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, portalLocation, portalType, true);\n        } else {\n            this.portalsManager.get().handleEntityPortalFromIsland(entity, island, portalLocation, portalType);\n        }\n    }\n\n    private void handlePlayerPortal(GameEvent<GameEventArgs.EntityPortalEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity);\n\n        if (superiorPlayer instanceof SuperiorNPCPlayer) {\n            ((SuperiorNPCPlayer) superiorPlayer).release();\n            return;\n        }\n\n        Island island = plugin.getGrid().getIslandAt(e.getArgs().from);\n        if (island == null) {\n            if (plugin.getGrid().isIslandsWorld(e.getArgs().from.getWorld()))\n                e.setCancelled();\n            return;\n        }\n\n        PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ?\n                PortalType.NETHER : PortalType.ENDER;\n\n        Either<Location, EntityPortalResult> destinationResult = calculateDestination(island, superiorPlayer, e.getArgs().from, portalType);\n\n        EntityPortalResult portalResult;\n        if (destinationResult.getLeft() != null) {\n            portalResult = this.portalsManager.get().handlePlayerPortalFromIsland(\n                    superiorPlayer, island, e.getArgs().from, portalType, destinationResult.getLeft(), true);\n        } else {\n            portalResult = destinationResult.getRight();\n        }\n\n        handleEntityPortalResult(portalResult, e);\n    }\n\n    public void handleEntityPortalResult(GameEvent<GameEventArgs.EntityPortalEvent> e) {\n        Location from = e.getArgs().from;\n        Location to = e.getArgs().to;\n\n        if (to == null || to.getWorld() == null || from == null || from.getWorld() == null)\n            return;\n\n        Island island = plugin.getGrid().getIslandAt(e.getArgs().from);\n        if (island == null)\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ?\n                PortalType.NETHER : PortalType.ENDER;\n\n        Either<Location, EntityPortalResult> destinationResult = calculateDestination(island, null, e.getArgs().from, portalType);\n\n        EntityPortalResult portalResult;\n        if (destinationResult.getLeft() != null) {\n            portalResult = this.portalsManager.get().handleEntityPortalFromIsland(\n                    entity, island, from, portalType, destinationResult.getLeft());\n        } else {\n            portalResult = destinationResult.getRight();\n        }\n\n        handleEntityPortalResult(portalResult, e);\n    }\n\n    @Nullable\n    private Either<Location, EntityPortalResult> calculateDestination(Island island, @Nullable SuperiorPlayer superiorPlayer, Location fromLocation, PortalType portalType) {\n        if (island.isSpawn())\n            return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD);\n\n        Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld());\n        if (portalDimension == null)\n            return Either.right(EntityPortalResult.PORTAL_NOT_IN_ISLAND);\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension);\n        Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType);\n        if (portalDestination == null)\n            return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD);\n        SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination);\n        if (destinationConfig.isEnabled()) {\n            // Check if the world actually exists\n            WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, portalDestination);\n            if (worldInfo != null)\n                return Either.left(island.getCenter(portalDestination));\n        }\n\n        if (superiorPlayer != null)\n            Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(portalDestination.getName()));\n\n        return Either.right(EntityPortalResult.DESTINATION_WORLD_DISABLED);\n    }\n\n    private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent<GameEventArgs.EntityPortalEvent> event) {\n        switch (portalResult) {\n            case PORTAL_NOT_IN_ISLAND:\n                return;\n            case DESTINATION_WORLD_DISABLED:\n            case PLAYER_IMMUNED_TO_PORTAL:\n            case SCHEMATIC_GENERATING_COOLDOWN:\n            case DESTINATION_NOT_ISLAND_WORLD:\n            case PORTAL_EVENT_CANCELLED:\n            case INVALID_SCHEMATIC:\n            case WORLD_NOT_UNLOCKED:\n            case DESTINATION_ISLAND_NOT_PERMITTED:\n            case SUCCEED:\n                event.setCancelled();\n                return;\n            default:\n                throw new IllegalStateException(\"No handling for result: \" + portalResult);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.nms.ICachedBlock;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.Sign;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.Egg;\nimport org.bukkit.entity.EnderPearl;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.FishHook;\nimport org.bukkit.entity.Hanging;\nimport org.bukkit.entity.HumanEntity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.Projectile;\nimport org.bukkit.entity.Vehicle;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.projectiles.ProjectileSource;\nimport org.bukkit.util.Vector;\n\nimport java.util.Iterator;\nimport java.util.List;\n\npublic class ProtectionListener extends AbstractGameEventListener {\n\n    @Nullable\n    private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, \"CHORUS_FLOWER\");\n    @Nullable\n    private static final Material CHORUS_FRUIT = EnumHelper.getEnum(Material.class, \"CHORUS_FRUIT\");\n    @Nullable\n    private static final Material BRUSH = EnumHelper.getEnum(Material.class, \"BRUSH\");\n    @Nullable\n    private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, \"WIND_CHARGE\");\n    @Nullable\n    private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, \"POINTED_DRIPSTONE\");\n    @Nullable\n    private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, \"TRIDENT\");\n    @Nullable\n    private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, \"DECORATED_POT\");\n    @Nullable\n    private static final Material TARGET = EnumHelper.getEnum(Material.class, \"TARGET\");\n\n    private final LazyReference<RegionManagerService> protectionManager = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n\n    public ProtectionListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    /* BLOCK INTERACTS */\n\n    private void onBlockPlace(GameEvent<GameEventArgs.BlockPlaceEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onPlayerInteract(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        if (handleBlockFertilize(e)) return;\n        if (handleBedPlace(e)) return;\n        if (handleSignColorChange(e)) return;\n        if (handleBrushUse(e)) return;\n        if (handleMinecartPlace(e)) return;\n        if (handleEntityInteract(e)) return;\n        handleBlockInteract(e, e.getArgs().player, e.getArgs().action, e.getArgs().clickedBlock, e.getArgs().usedHand, e.getArgs().usedItem);\n    }\n\n    private void onEntityInteractBlock(GameEvent<GameEventArgs.EntityInteractEvent> e) {\n        Block clickedBlock = e.getArgs().block;\n        if (clickedBlock == null)\n            return;\n\n        Entity entity = e.getArgs().entity;\n        if (!(entity instanceof Projectile))\n            return;\n\n        ProjectileSource projectileSource = ((Projectile) entity).getShooter();\n        if (!(projectileSource instanceof Player))\n            return;\n\n        if (handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null, null)) {\n            // We want to remove the projectile as well when it is not possible to interact\n            entity.remove();\n        }\n    }\n\n    private boolean handleBlockFertilize(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem))\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockFertilize(superiorPlayer, e.getArgs().clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    // Patching a dupe glitch with crops and beds: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1672\n    private boolean handleBedPlace(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.isBed(usedItem.getType()))\n            return false;\n\n        // The player right-clicked a block with a bed in his hand\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    private boolean handleSignColorChange(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || ServerVersion.isLegacy() || !Materials.isDye(usedItem.getType()))\n            return false;\n\n        Block clickedBlock = e.getArgs().clickedBlock;\n        BlockState blockState = clickedBlock.getState();\n\n        if (!(blockState instanceof Sign))\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    private boolean handleBrushUse(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || usedItem.getType() != BRUSH)\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n\n        InteractionResult interactionResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            interactionResult = this.protectionManager.get().handleCustomInteraction(\n                    superiorPlayer, e.getArgs().clickedBlock.getLocation(wrapper.getHandle()), IslandPrivileges.BRUSH);\n        }\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    private boolean handleMinecartPlace(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        Action action = e.getArgs().action;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null)\n            return false;\n\n        Material handItemType = usedItem.getType();\n        Material clickedBlockType = e.getArgs().clickedBlock.getType();\n\n        EntityType spawnType = Materials.isMinecart(handItemType) && Materials.isRail(clickedBlockType) ? EntityType.MINECART :\n                Materials.isBoat(handItemType) ? EntityType.BOAT : null;\n        if (spawnType == null)\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n\n        List<EntityCategory> entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType));\n\n        if (entityCategories.isEmpty())\n            return false;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location clickedBlockLocation = e.getArgs().clickedBlock.getLocation(wrapper.getHandle());\n\n            for (EntityCategory entityCategory : entityCategories) {\n                if (entityCategory.getSpawnPrivilege() != null) {\n                    InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(\n                            superiorPlayer, clickedBlockLocation, entityCategory.getSpawnPrivilege());\n                    if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n                        e.setCancelled();\n                        return true;\n                    }\n                }\n            }\n        }\n\n        return false;\n    }\n\n    private boolean handleEntityInteract(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        if (e.getArgs().clickedEntity == null)\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer,\n                e.getArgs().clickedEntity, e.getArgs().usedItem);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    private boolean handleBlockInteract(GameEvent<?> e, Player player, Action action, @Nullable Block clickedBlock,\n                                        @Nullable PlayerHand usedHand, @Nullable ItemStack usedItem) {\n        if (clickedBlock == null)\n            return false;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract(\n                superiorPlayer, clickedBlock, action, usedItem);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer,\n                usedItem != null || usedHand != PlayerHand.OFF_HAND)) {\n            e.setCancelled();\n            return true;\n        }\n\n        return false;\n    }\n\n    private void onBlockBreak(GameEvent<GameEventArgs.BlockBreakEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, e.getArgs().block);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onFrostWalker(GameEvent<GameEventArgs.EntityBlockFormEvent> e) {\n        Entity entity = e.getArgs().entity;\n        if (!(entity instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false))\n            e.setCancelled();\n    }\n\n    private void onBucketEmpty(GameEvent<GameEventArgs.PlayerEmptyBucketEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onBucketFill(GameEvent<GameEventArgs.PlayerFillBucketEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onBucketDispense(GameEvent<GameEventArgs.BlockDispenseEvent> e) {\n        Material itemType = e.getArgs().dispensedItem.getType();\n\n        if (!(itemType == Material.BUCKET || itemType == Material.WATER_BUCKET || itemType == Material.LAVA_BUCKET))\n            return;\n\n        Vector velocity = e.getArgs().velocity;\n\n        Location dispenseBlockLocation = new Location(e.getArgs().block.getWorld(), velocity.getBlockX(),\n                velocity.getBlockY(), velocity.getBlockZ());\n\n        Island island = plugin.getGrid().getIslandAt(dispenseBlockLocation);\n\n        if (island != null && !island.isInsideRange(dispenseBlockLocation))\n            e.setCancelled();\n    }\n\n    private void onChorusFruitConsume(GameEvent<GameEventArgs.PlayerItemConsumeEvent> e) {\n        if (CHORUS_FRUIT == null || e.getArgs().consumedItem.getType() != CHORUS_FRUIT)\n            return;\n\n        Player player = e.getArgs().player;\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        InteractionResult interactionResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            interactionResult = this.protectionManager.get().handlePlayerConsumeChorusFruit(\n                    superiorPlayer, player.getLocation(wrapper.getHandle()));\n        }\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    /* ENTITY INTERACTS */\n\n    private void onEntityAttack(GameEvent<GameEventArgs.EntityDamageEvent> e) {\n        Entity entity = e.getArgs().entity;\n        Entity damager = e.getArgs().damager;\n\n        if (damager == null || entity instanceof Player)\n            return;\n\n        SuperiorPlayer damagerSource = BukkitEntities.getPlayerSource(damager)\n                .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(damager, entity);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, damagerSource, true))\n            e.setCancelled();\n    }\n\n    private void onEntityShearing(GameEvent<GameEventArgs.PlayerShearEntityEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityShear(superiorPlayer, e.getArgs().entity);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onHangingBreak(GameEvent<GameEventArgs.HangingBreakEvent> e) {\n        BukkitEntities.getPlayerSource(e.getArgs().remover).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(removerPlayer -> {\n            InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(removerPlayer, e.getArgs().entity, null);\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, removerPlayer, true))\n                e.setCancelled();\n        });\n    }\n\n    private void onHangingPlace(GameEvent<GameEventArgs.HangingPlaceEvent> e) {\n        if (!(e.getArgs().entity instanceof Hanging))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, e.getArgs().entity, null);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onEntityTarget(GameEvent<GameEventArgs.EntityTargetEvent> e) {\n        Entity entity = e.getArgs().entity;\n        Entity target = e.getArgs().target;\n\n        if (!(target instanceof Player))\n            return;\n\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(target, entity);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false))\n            e.setCancelled();\n    }\n\n    private void onVillagerTrade(GameEvent<GameEventArgs.InventoryClickEvent> e) {\n        Inventory openInventory = e.getArgs().bukkitEvent.getView().getTopInventory();\n\n        if (openInventory == null || openInventory.getType() != InventoryType.MERCHANT)\n            return;\n\n        HumanEntity humanEntity = e.getArgs().bukkitEvent.getWhoClicked();\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(humanEntity);\n\n        InteractionResult interactionResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = humanEntity.getLocation(wrapper.getHandle());\n            interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer,\n                    location, IslandPrivileges.VILLAGER_TRADING);\n        }\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) {\n            e.setCancelled();\n            humanEntity.closeInventory();\n        }\n    }\n\n    private void onPlayerLeash(GameEvent<GameEventArgs.PlayerLeashEntityEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onPlayerUnleash(GameEvent<GameEventArgs.PlayerUnleashEntityEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    /* VEHICLE INTERACTS */\n\n    private void onVehicleEnter(GameEvent<GameEventArgs.EntityRideEvent> e) {\n        Entity rider = e.getArgs().entity;\n        if (!(rider instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) rider);\n        InteractionResult interactionResult = this.protectionManager.get().handleEntityRide(superiorPlayer, e.getArgs().vehicle);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onVehicleOpen(GameEvent<GameEventArgs.InventoryOpenEvent> e) {\n        InventoryHolder inventoryHolder = e.getArgs().bukkitEvent.getInventory().getHolder();\n\n        if (!(inventoryHolder instanceof Vehicle))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer());\n\n        List<EntityCategory> entityCategories = BukkitEntities.getCategories((Entity) inventoryHolder);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle());\n\n            if (!entityCategories.isEmpty()) {\n                InteractionResult interactionResult;\n                for (EntityCategory entityCategory : entityCategories) {\n                    if (entityCategory.getInteractPrivilege() != null) {\n                        interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer,\n                                minecartLocation, entityCategory.getInteractPrivilege());\n                        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n                            e.setCancelled();\n                            return;\n                        }\n                    }\n                }\n            }\n\n            IslandPrivilege islandPrivilege = inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN;\n            InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer,\n                    minecartLocation, islandPrivilege);\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) {\n                e.setCancelled();\n            }\n        }\n    }\n\n    private void onPlayerCollideWithEntity(GameEvent<GameEventArgs.EntityCollisionEvent> e) {\n        Entity entity = e.getArgs().entity;\n        if (!(entity instanceof Player))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity);\n        InteractionResult interactionResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location vehicleLocation = e.getArgs().target.getLocation(wrapper.getHandle());\n            interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer,\n                    vehicleLocation, IslandPrivileges.MINECART_ENTER);\n        }\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false))\n            e.setCancelled();\n    }\n\n    /* ITEMS */\n\n    private void onPlayerDropItem(GameEvent<GameEventArgs.PlayerDropItemEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handlePlayerDropItem(superiorPlayer, e.getArgs().droppedItem);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onPlayerPickupItem(GameEvent<GameEventArgs.PlayerPickupItemEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    private void onPlayerPickupArrow(GameEvent<GameEventArgs.PlayerPickupArrowEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem);\n        if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n            e.setCancelled();\n    }\n\n    /* PROJECTILE INTERACTS */\n\n    private void onPlayerLaunchProjectile(GameEvent<GameEventArgs.ProjectileLaunchEvent> e) {\n        Entity entity = e.getArgs().entity;\n        BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(launcherPlayer -> {\n            EntityType entityType = entity.getType();\n\n            InteractionResult interactionResult;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location entityLocation = entity.getLocation(wrapper.getHandle());\n\n                if (entity instanceof Egg) {\n                    List<EntityCategory> entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity));\n                    for (EntityCategory entityCategory : entityCategories) {\n                        if (entityCategory.getSpawnPrivilege() != null) {\n                            interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer,\n                                    entityLocation, entityCategory.getSpawnPrivilege());\n                            if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) {\n                                e.setCancelled();\n                                return;\n                            }\n                        }\n                    }\n                }\n\n                IslandPrivilege islandPrivilege;\n                if (entity instanceof FishHook && !ServerVersion.isLegacy()) {\n                    islandPrivilege = IslandPrivileges.FISH;\n                } else if (entityType == TRIDENT) {\n                    islandPrivilege = IslandPrivileges.PICKUP_DROPS;\n                } else if (entity instanceof EnderPearl) {\n                    islandPrivilege = IslandPrivileges.ENDER_PEARL;\n                } else if (entityType == WIND_CHARGE) {\n                    islandPrivilege = IslandPrivileges.WIND_CHARGE;\n                } else {\n                    return;\n                }\n\n                interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer,\n                        entityLocation, islandPrivilege);\n            }\n\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true))\n                e.setCancelled();\n        });\n    }\n\n    private void onProjectileHit(GameEvent<GameEventArgs.ProjectileHitEvent> e) {\n        Entity entity = e.getArgs().entity;\n        BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> {\n            Location location;\n            IslandPrivilege islandPrivilege;\n            Block hitBlock;\n            InteractionResult interactionResult;\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (entity instanceof FishHook) {\n                    Entity hitEntity = e.getArgs().hitEntity;\n                    if (hitEntity == null)\n                        return;\n\n                    hitBlock = null;\n                    location = hitEntity.getLocation(wrapper.getHandle());\n\n                    List<EntityCategory> entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity));\n                    interactionResult = InteractionResult.SUCCESS;\n\n                    for (EntityCategory entityCategory : entityCategories) {\n                        if (entityCategory.getDamagePrivilege() != null) {\n                            interactionResult = this.protectionManager.get().handleCustomInteraction(\n                                    shooterPlayer, location, entityCategory.getDamagePrivilege());\n                            if (interactionResult != InteractionResult.SUCCESS)\n                                break;\n                        }\n                    }\n                } else {\n                    hitBlock = e.getArgs().hitBlock;\n                    Material hitBlockType = hitBlock == null ? null : hitBlock.getType();\n                    if (hitBlockType != CHORUS_FLOWER && hitBlockType != DECORATED_POT && hitBlockType != TARGET)\n                        return;\n\n                    IslandPrivilege requiredPrivilege = plugin.getSettings().getInteractablesMap()\n                            .getRequiredPrivilege(ConstantKeys.TARGET);\n\n                    location = hitBlock.getLocation(wrapper.getHandle());\n                    islandPrivilege = hitBlockType == TARGET ? requiredPrivilege : IslandPrivileges.BREAK;\n\n                    if (islandPrivilege == null)\n                        return;\n\n                    interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege);\n                }\n            }\n\n            if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) {\n                entity.remove();\n                if (hitBlock != null) {\n                    ICachedBlock cachedBlock = plugin.getNMSWorld().cacheBlock(hitBlock);\n                    hitBlock.setType(Material.AIR);\n                    BukkitExecutor.sync(() -> {\n                        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                            cachedBlock.setBlock(hitBlock.getLocation(wrapper.getHandle()));\n                        }\n                        cachedBlock.release();\n                    }, 1L);\n                }\n            }\n        });\n    }\n\n    private void onSoftExplodeEvent(GameEvent<GameEventArgs.EntityExplodeEvent> e) {\n        if (!e.getArgs().isSoftExplosion)\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> {\n            Iterator<Block> blocksIterator = e.getArgs().blocks.iterator();\n            while (blocksIterator.hasNext()) {\n                Block block = blocksIterator.next();\n                Material blockType = block.getType();\n\n                IslandPrivilege islandPrivilege = blockType == CHORUS_FLOWER || blockType == POINTED_DRIPSTONE ?\n                        IslandPrivileges.BREAK : plugin.getSettings().getInteractablesMap().getRequiredPrivilege(Keys.of(block));\n\n                if (islandPrivilege == null)\n                    continue;\n\n                InteractionResult interactionResult;\n                try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                    interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer,\n                            block.getLocation(wrapper.getHandle()), islandPrivilege);\n                }\n                if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true))\n                    blocksIterator.remove();\n            }\n        });\n\n    }\n\n    /* WORLD EVENTS */\n\n    private void onRaidTrigger(GameEvent<GameEventArgs.RaidTriggerEvent> e) {\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().world))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        Location raidLocation = e.getArgs().raidLocation;\n\n        Island island = plugin.getGrid().getIslandAt(raidLocation);\n\n        if (island == null || island.isSpawn() || !island.isInside(raidLocation) || !island.isMember(superiorPlayer))\n            e.setCancelled();\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.NORMAL, this::onBlockPlace);\n        registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onPlayerInteract);\n        registerCallback(GameEventType.ENTITY_INTERACT_EVENT, GameEventPriority.NORMAL, this::onEntityInteractBlock);\n        registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onBlockBreak);\n        registerCallback(GameEventType.ENTITY_BLOCK_FORM_EVENT, GameEventPriority.NORMAL, this::onFrostWalker);\n        registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketEmpty);\n        registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketFill);\n        registerCallback(GameEventType.BLOCK_DISPENSE_EVENT, GameEventPriority.NORMAL, this::onBucketDispense);\n        registerCallback(GameEventType.PLAYER_ITEM_CONSUME_EVENT, GameEventPriority.NORMAL, this::onChorusFruitConsume);\n        registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onEntityAttack);\n        registerCallback(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, GameEventPriority.NORMAL, this::onEntityShearing);\n        registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.NORMAL, this::onHangingBreak);\n        registerCallback(GameEventType.HANGING_PLACE_EVENT, GameEventPriority.NORMAL, this::onHangingPlace);\n        registerCallback(GameEventType.ENTITY_TARGET_EVENT, GameEventPriority.NORMAL, this::onEntityTarget);\n        registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, false, this::onVillagerTrade);\n        registerCallback(GameEventType.PLAYER_LEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerLeash);\n        registerCallback(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerUnleash);\n        registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onVehicleEnter);\n        registerCallback(GameEventType.INVENTORY_OPEN_EVENT, GameEventPriority.NORMAL, this::onVehicleOpen);\n        registerCallback(GameEventType.ENTITY_COLLISION_EVENT, GameEventPriority.NORMAL, this::onPlayerCollideWithEntity);\n        registerCallback(GameEventType.PLAYER_DROP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerDropItem);\n        registerCallback(GameEventType.PLAYER_PICKUP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupItem);\n        registerCallback(GameEventType.PROJECTILE_LAUNCH_EVENT, GameEventPriority.NORMAL, this::onPlayerLaunchProjectile);\n        registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.NORMAL, this::onProjectileHit);\n        registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.NORMAL, this::onSoftExplodeEvent);\n        registerCallback(GameEventType.PLAYER_PICKUP_ARROW_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupArrow);\n        registerCallback(GameEventType.RAID_TRIGGER_EVENT, GameEventPriority.NORMAL, this::onRaidTrigger);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.signs.IslandSigns;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.block.Sign;\nimport org.bukkit.block.data.Directional;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\n\nimport java.util.Arrays;\nimport java.util.Iterator;\n\npublic class SignsListener extends AbstractGameEventListener {\n\n    private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{\n            BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST\n    };\n\n    public SignsListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    private void onSignPlace(GameEvent<GameEventArgs.SignChangeEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Player player = e.getArgs().player;\n        String[] lines = e.getArgs().lines;\n\n        String[] signLines;\n\n        IslandSigns.Result result;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location warpLocation = block.getLocation(wrapper.getHandle());\n            SignType signType = plugin.getNMSWorld().getSignType(block);\n\n            // Hanging signs are not allowed\n            if (signType == SignType.HANGING_SIGN || signType == SignType.HANGING_WALL_SIGN)\n                return;\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n            signLines = lines.clone();\n\n            result = IslandSigns.handleSignPlace(superiorPlayer, warpLocation, signLines, true);\n        }\n        switch (result.getReason()) {\n            case NOT_IN_ISLAND:\n                return;\n            case SUCCESS:\n                break;\n            default:\n                Arrays.fill(signLines, \"\");\n                break;\n        }\n\n        // Only update the lines if changed\n        if (Arrays.equals(signLines, lines))\n            return;\n\n        // We want to update the sign only one tick later, so other plugins don't interface with it\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1916\n        BukkitExecutor.sync(() -> {\n            BlockState blockState = block.getState();\n            if (blockState instanceof Sign) {\n                Sign sign = (Sign) blockState;\n                for (int i = 0; i < signLines.length; ++i)\n                    sign.setLine(i, signLines[i]);\n                sign.update();\n            }\n        }, 1L);\n    }\n\n    private void onSignBreak(GameEvent<GameEventArgs.BlockBreakEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle()));\n        }\n\n        if (!isValidIsland(island))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n\n        IslandSigns.Result result = handleBlockBreak(island, block, superiorPlayer);\n        if (result.isCancelEvent())\n            e.setCancelled();\n    }\n\n    private void onSignExplode(GameEvent<GameEventArgs.EntityExplodeEvent> e) {\n        if (e.getArgs().isSoftExplosion)\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        Island island;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle()));\n        }\n\n        if (!isValidIsland(island))\n            return;\n\n        Iterator<Block> iterator = e.getArgs().blocks.iterator();\n        while (iterator.hasNext()) {\n            Block block = iterator.next();\n            IslandSigns.Result result = handleBlockBreak(island, block, null);\n            if (result.isCancelEvent())\n                iterator.remove();\n        }\n    }\n\n    private IslandSigns.Result handleBlockBreak(Island island, Block block, @Nullable SuperiorPlayer superiorPlayer) {\n        BlockState blockState = block.getState();\n        if (blockState instanceof Sign) {\n            return IslandSigns.handleSignBreak(island, superiorPlayer, (Sign) blockState);\n        }\n\n        for (BlockFace blockFace : NEARBY_BLOCKS) {\n            Block faceBlock = block.getRelative(blockFace);\n            blockState = faceBlock.getState();\n            if (!(blockState instanceof Sign))\n                continue;\n\n            boolean isSignGonnaBreak;\n\n            if (ServerVersion.isLegacy()) {\n                org.bukkit.material.Sign sign = (org.bukkit.material.Sign) blockState.getData();\n                isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace;\n            } else {\n                Object blockData = plugin.getNMSWorld().getBlockData(faceBlock);\n                switch (plugin.getNMSWorld().getSignType(blockData)) {\n                    case WALL_SIGN:\n                        // Wall signs will only be broken if they are attached to the block\n                        isSignGonnaBreak = ((Directional) blockData).getFacing() == blockFace;\n                        break;\n                    case STANDING_SIGN:\n                        // Standing signs will only be broken if they are placed on top of the block\n                        isSignGonnaBreak = blockFace == BlockFace.UP;\n                        break;\n                    case HANGING_WALL_SIGN:\n                    case HANGING_SIGN:\n                        // Hanging signs are not allowed as warp signs\n                        isSignGonnaBreak = false;\n                        break;\n                    default:\n                        throw new RuntimeException(\"Found sign that cannot be handled: \" + blockData);\n                }\n            }\n\n            if (isSignGonnaBreak) {\n                return IslandSigns.handleSignBreak(null, superiorPlayer, (Sign) blockState);\n            }\n        }\n\n        return new IslandSigns.Result(IslandSigns.Reason.SUCCESS, false);\n    }\n\n    private void registerListeners() {\n        registerCallback(GameEventType.SIGN_CHANGE_EVENT, GameEventPriority.MONITOR, this::onSignPlace);\n        registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onSignBreak);\n        registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onSignExplode);\n    }\n\n    private static boolean isValidIsland(Island island) {\n        return island != null && (!island.getIslandWarps().isEmpty() || island.getVisitorsPosition(null) != null);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class StackedBlocksListener extends AbstractGameEventListener {\n\n    @Nullable\n    private static final Material COPPER_BLOCK = EnumHelper.getEnum(Material.class, \"COPPER_BLOCK\");\n    private static final Material HONEYCOMB = EnumHelper.getEnum(Material.class, \"HONEYCOMB\");\n    @Nullable\n    private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, \"BUILD_COPPERGOLEM\");\n    @Nullable\n    private static final Material COPPER_CHEST = EnumHelper.getEnum(Material.class, \"COPPER_CHEST\");\n\n    private final Map<CreatureSpawnEvent.SpawnReason, List<BlockOffset>> ENTITY_TEMPLATE_OFFSETS = buildEntityTemplateOffsetsMap();\n\n    private final LazyReference<StackedBlocksInteractionService> stackedBlocksInteractionService = new LazyReference<StackedBlocksInteractionService>() {\n        @Override\n        protected StackedBlocksInteractionService create() {\n            return plugin.getServices().getService(StackedBlocksInteractionService.class);\n        }\n    };\n\n    public StackedBlocksListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        this.registerListeners();\n    }\n\n    private void onStackedBlockInteract(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        if (e.getArgs().action != Action.RIGHT_CLICK_BLOCK)\n            return;\n\n        if (handleStackedBlockPlace(e)) return;\n        if (handleStackedBlockUnstack(e)) return;\n    }\n\n    /* STACK LISTENERS */\n\n    private void onStackedBlockPlace(GameEvent<GameEventArgs.BlockPlaceEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return;\n\n        Block againstBlock = e.getArgs().againstBlock;\n\n        if (againstBlock.equals(block))\n            return;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1)\n            plugin.getStackedBlocks().setStackedBlock(block, 1);\n\n        Player player = e.getArgs().player;\n        PlayerHand usedHand = e.getArgs().usedHand;\n        ItemStack inHand = e.getArgs().usedItem;\n\n        if (inHand == null) {\n            Log.error(\"BlockPlaceEvent by player \", player.getName(), \" of block \", block.getType().name(), \" with null hand item: \", usedHand);\n            throw new RuntimeException(\"BlockPlaceEvent with null hand item\");\n        }\n\n        // We do not stack blocks when the hand items has a name or a lore.\n        if (inHand.hasItemMeta() && (inHand.getItemMeta().hasDisplayName() || inHand.getItemMeta().hasLore()))\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n        InteractionResult interactionResult = this.stackedBlocksInteractionService.get().handleStackedBlockPlace(\n                superiorPlayer, againstBlock, usedHand.getEquipmentSlot());\n        if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult))\n            e.setCancelled();\n    }\n\n    private boolean handleStackedBlockPlace(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        if (!plugin.getSettings().getStackedBlocks().isEnabled())\n            return false;\n\n        boolean cancelled = false;\n\n        Player player = e.getArgs().player;\n        Block clickedBlock = e.getArgs().clickedBlock;\n        PlayerHand usedHand = e.getArgs().usedHand;\n        ItemStack usedItem = e.getArgs().usedItem;\n\n        Material clickedBlockType = clickedBlock.getType();\n\n        if (clickedBlockType == Material.DRAGON_EGG) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n\n            if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) {\n                e.setCancelled();\n                if (usedItem == null)\n                    this.stackedBlocksInteractionService.get().handleStackedBlockBreak(clickedBlock, superiorPlayer);\n                cancelled = true;\n            }\n\n            if (usedItem != null) {\n                InteractionResult interactionResult = this.stackedBlocksInteractionService.get()\n                        .handleStackedBlockPlace(superiorPlayer, clickedBlock, usedHand.getEquipmentSlot());\n                if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) {\n                    e.setCancelled();\n                    cancelled = true;\n                }\n            }\n        } else if (clickedBlockType == COPPER_BLOCK && usedItem != null && usedItem.getType() == HONEYCOMB &&\n                plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) {\n            e.setCancelled();\n            cancelled = true;\n        }\n\n        return cancelled;\n    }\n\n    /* UNSTACK LISTENERS */\n\n    private void onStackedBlockBreak(GameEvent<GameEventArgs.BlockBreakEvent> e) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player);\n        InteractionResult interactionResult = this.stackedBlocksInteractionService.get()\n                .handleStackedBlockBreak(e.getArgs().block, superiorPlayer);\n        if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult))\n            e.setCancelled();\n    }\n\n    private boolean handleStackedBlockUnstack(GameEvent<GameEventArgs.PlayerInteractEvent> e) {\n        if (e.getArgs().usedItem != null || e.getArgs().usedHand != PlayerHand.MAIN_HAND)\n            return false;\n\n        Block clickedBlock = e.getArgs().clickedBlock;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld()))\n            return false;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) <= 1)\n            return false;\n\n        Player player = e.getArgs().player;\n\n        if (plugin.getSettings().getStackedBlocks().getDepositMenu().isEnabled() && player.isSneaking()) {\n            StackedBlocksDepositMenu depositMenu = new StackedBlocksDepositMenu(clickedBlock.getLocation());\n            player.openInventory(depositMenu.getInventory());\n        } else {\n            ItemStack offHandItem = BukkitItems.getHandItem(player, PlayerHand.OFF_HAND);\n            if (offHandItem != null && offHandItem.getType() == clickedBlock.getType())\n                return false;\n\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player);\n            InteractionResult interactionResult = this.stackedBlocksInteractionService.get()\n                    .handleStackedBlockBreak(clickedBlock, superiorPlayer);\n            if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) {\n                e.setCancelled();\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private void onStackedBlockBreakByEntity(GameEvent<GameEventArgs.EntityChangeBlockEvent> e) {\n        InteractionResult interactionResult = this.stackedBlocksInteractionService.get()\n                .handleStackedBlockBreak(e.getArgs().block, null);\n        if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult))\n            e.setCancelled();\n    }\n\n    private void onStackedBlockExplode(GameEvent<GameEventArgs.EntityExplodeEvent> e) {\n        if (e.getArgs().isSoftExplosion)\n            return;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().entity.getWorld()))\n            return;\n\n        Iterator<Block> blockIterator = e.getArgs().blocks.iterator();\n        while (blockIterator.hasNext()) {\n            Block block = blockIterator.next();\n\n            // Check if block is stackable\n            if (!plugin.getSettings().getStackedBlocks().getWhitelisted().contains(Keys.of(block)))\n                continue;\n\n            int amount = plugin.getStackedBlocks().getStackedBlockAmount(block);\n\n            if (amount <= 1)\n                continue;\n\n            // All checks are done. We can remove the block from the list.\n            blockIterator.remove();\n\n            ItemStack blockItem = block.getState().getData().toItemStack(amount);\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location location = block.getLocation(wrapper.getHandle());\n\n                Island island = plugin.getGrid().getIslandAt(location);\n                if (island != null)\n                    island.handleBlockBreak(block, amount);\n\n                plugin.getStackedBlocks().removeStackedBlock(location);\n                block.setType(Material.AIR);\n\n                // Dropping the item\n                block.getWorld().dropItemNaturally(location, blockItem);\n            }\n\n        }\n    }\n\n    /* STACKED-BLOCKS PROTECTION */\n\n    private void onPistonExtend(GameEvent<GameEventArgs.PistonExtendEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        for (Block block : e.getArgs().blocks) {\n            if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) {\n                e.setCancelled();\n                break;\n            }\n        }\n    }\n\n    public void onPistonRetract(GameEvent<GameEventArgs.PistonRetractEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        for (Block block : e.getArgs().blocks) {\n            if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) {\n                e.setCancelled();\n                break;\n            }\n        }\n    }\n\n    private void onBlockChangeState(GameEvent<GameEventArgs.BlockFormEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1)\n            e.setCancelled();\n    }\n\n    private void onGolemCreate(GameEvent<GameEventArgs.EntitySpawnEvent> e) {\n        List<BlockOffset> entityTemplateOffsets = ENTITY_TEMPLATE_OFFSETS.get(e.getArgs().spawnReason);\n        if (entityTemplateOffsets == null)\n            return;\n\n        Entity entity = e.getArgs().entity;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = entity.getLocation(wrapper.getHandle());\n\n            if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) {\n                e.setCancelled();\n                return;\n            }\n\n            for (BlockOffset blockOffset : entityTemplateOffsets) {\n                if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) {\n                    e.setCancelled();\n                    if (e.getArgs().spawnReason == BUILD_COPPERGOLEM)\n                        onCopperGolemCancel(entityLocation);\n                    return;\n                }\n            }\n        }\n    }\n\n    private void onCopperGolemCancel(Location entityLocation) {\n        Block copperChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN);\n        BukkitExecutor.sync(() -> {\n            if (copperChestBlock.getType() == COPPER_CHEST) {\n                copperChestBlock.setType(COPPER_BLOCK);\n            }\n        }, 1L);\n    }\n\n    private void onSpongeAbsorb(GameEvent<GameEventArgs.SpongeAbsorbEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1)\n            e.setCancelled();\n    }\n\n    private void onStackedBlockPhysics(GameEvent<GameEventArgs.BlockPhysicsEvent> e) {\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld()))\n            return;\n\n        if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1)\n            e.setCancelled();\n    }\n\n    /* INTERNAL */\n\n    private void registerListeners() {\n        if (!plugin.getSettings().getStackedBlocks().isEnabled()) {\n            // Even if stacked blocks are disabled, we might want to keep the break or change related listeners.\n            // We only want to keep them if there are any stacked blocks registered.\n            if (!plugin.getStackedBlocks().hasStackedBlocks())\n                return;\n        } else {\n            registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockPlace);\n        }\n\n        registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreak);\n        registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockInteract);\n        registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreakByEntity);\n        registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockExplode);\n        registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.LOWEST, this::onPistonExtend);\n        registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.LOWEST, this::onPistonRetract);\n        registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.LOWEST, this::onBlockChangeState);\n        registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onGolemCreate);\n        registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.LOWEST, this::onSpongeAbsorb);\n\n        if (plugin.getSettings().isPhysicsListener())\n            registerCallback(GameEventType.BLOCK_PHYSICS_EVENT, GameEventPriority.LOWEST, this::onStackedBlockPhysics);\n    }\n\n    private static Map<CreatureSpawnEvent.SpawnReason, List<BlockOffset>> buildEntityTemplateOffsetsMap() {\n        EnumMap<CreatureSpawnEvent.SpawnReason, List<BlockOffset>> offsetsMap = new EnumMap<>(CreatureSpawnEvent.SpawnReason.class);\n\n        List<BlockOffset> blockOffsets = new LinkedList<>();\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1));\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0));\n        offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM, blockOffsets);\n\n        blockOffsets = new LinkedList<>();\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0));\n        offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN, blockOffsets);\n\n        blockOffsets = new LinkedList<>();\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1));\n        blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 1));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, 0));\n        blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, -1));\n        offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_WITHER, blockOffsets);\n\n        if (BUILD_COPPERGOLEM != null) {\n            blockOffsets = new LinkedList<>();\n            blockOffsets.add(SBlockOffset.fromOffsets(0, -1, 0));\n            offsetsMap.put(BUILD_COPPERGOLEM, blockOffsets);\n        }\n\n        return Collections.unmodifiableMap(offsetsMap);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java",
    "content": "package com.bgsoftware.superiorskyblock.listener;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\n\nimport java.util.List;\nimport java.util.function.Function;\n\npublic class WorldDestructionListener extends AbstractGameEventListener {\n\n    public WorldDestructionListener(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n        registerListeners();\n    }\n\n    //Checking for structures growing outside island.\n    private void onStructureGrow(GameEvent<GameEventArgs.StructureGrowEvent> e) {\n        Location location = e.getArgs().location;\n\n        // We care about destruction of island worlds only\n        if (!plugin.getGrid().isIslandsWorld(location.getWorld())) {\n            return;\n        }\n\n        Island island = plugin.getGrid().getIslandAt(location);\n        if (island != null) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                e.getArgs().blocks.removeIf(blockState ->\n                        !island.isInsideRange(blockState.getLocation(wrapper.getHandle())));\n            }\n        }\n    }\n\n    //Checking for chorus flower spread outside island.\n    private void onBlockSpread(GameEvent<GameEventArgs.BlockSpreadEvent> e) {\n        Block block = e.getArgs().block;\n\n        // We care about destruction of island worlds only\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventDestruction(e.getArgs().source.getLocation(wrapper.getHandle())) ||\n                    preventDestruction(block.getLocation(wrapper.getHandle())))\n                e.setCancelled();\n        }\n    }\n\n    public void onPistonExtend(GameEvent<GameEventArgs.PistonExtendEvent> e) {\n        Block pistonBlock = e.getArgs().block;\n\n        // We care about destruction of island worlds only\n        if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks,\n                    block -> block.getRelative(e.getArgs().direction)))\n                e.setCancelled();\n        }\n    }\n\n    public void onPistonRetract(GameEvent<GameEventArgs.PistonRetractEvent> e) {\n        Block pistonBlock = e.getArgs().block;\n\n        // We care about destruction of island worlds only\n        if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks,\n                    block -> block.getRelative(e.getArgs().direction)))\n                e.setCancelled();\n        }\n    }\n\n    private void onBlockFlow(GameEvent<GameEventArgs.BlockFromToEvent> e) {\n        Block block = e.getArgs().toBlock;\n\n        // We care about destruction of island worlds only\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld())) {\n            return;\n        }\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            if (preventDestruction(blockLocation))\n                e.setCancelled();\n        }\n    }\n\n    /* INTERNAL */\n\n    private boolean preventDestruction(Location location) {\n        Island island = plugin.getGrid().getIslandAt(location);\n        return island == null || !island.isInsideRange(location);\n    }\n\n    private boolean preventMultiDestruction(Location islandLocation, List<Block> blockList,\n                                            @Nullable Function<Block, Block> blockTransform) {\n        Island island = plugin.getGrid().getIslandAt(islandLocation);\n\n        if (island == null)\n            return true;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            for (Block block : blockList) {\n                if (blockTransform != null)\n                    block = blockTransform.apply(block);\n                if (!island.isInsideRange(block.getLocation(wrapper.getHandle())))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    private void registerListeners() {\n        registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.NORMAL, this::onStructureGrow);\n        registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.NORMAL, this::onBlockSpread);\n        registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.NORMAL, this::onPistonExtend);\n        registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.NORMAL, this::onPistonRetract);\n        registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.NORMAL, this::onBlockFlow);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java",
    "content": "package com.bgsoftware.superiorskyblock.mission;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.menu.TemplateItem;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class MissionData {\n\n    private static int currentIndex = 0;\n\n    private final int index;\n    private final String missionName;\n    private final List<ItemStack> itemRewards = new LinkedList<>();\n    private final List<String> commandRewards = new LinkedList<>();\n    private final boolean autoReward;\n    private final boolean islandMission;\n    private final boolean disbandReset;\n    private final boolean leaveReset;\n    private final boolean resetAfterFinish;\n    private final int resetAmount;\n    @Nullable\n    private final TemplateItem notCompleted;\n    @Nullable\n    private final TemplateItem canComplete;\n    @Nullable\n    private final TemplateItem locked;\n    @Nullable\n    private final TemplateItem completed;\n\n    MissionData(Mission<?> mission, String missionCategoryName, ConfigurationSection section) {\n        this.index = currentIndex++;\n        this.missionName = mission.getName();\n        this.islandMission = section.getBoolean(\"island\", false);\n        this.autoReward = section.getBoolean(\"auto-reward\", true);\n        this.disbandReset = section.getBoolean(\"disband-reset\", false);\n        this.leaveReset = section.getBoolean(\"leave-reset\", false);\n        this.resetAmount = section.getInt(\"reset-amount\", 1);\n        this.resetAfterFinish = section.getBoolean(\"reset-after-finish\", true);\n\n        if (section.isConfigurationSection(\"rewards.items\")) {\n            for (String key : section.getConfigurationSection(\"rewards.items\").getKeys(false)) {\n                TemplateItem templateItem = MenuParserImpl.getInstance().getItemStack(\"config.yml\", section.getConfigurationSection(\"rewards.items.\" + key));\n                if (templateItem != null) {\n                    ItemStack itemStack = templateItem.build();\n                    itemStack.setAmount(section.getInt(\"rewards.items.\" + key + \".amount\", 1));\n                    this.itemRewards.add(itemStack);\n                }\n            }\n        }\n\n        this.commandRewards.addAll(section.getStringList(\"rewards.commands\"));\n\n        String missionFilePath = \"modules/missions/categories/\" + missionCategoryName + \"/\" + this.missionName + \".yml\";\n\n        this.notCompleted = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection(\"icons.not-completed\"));\n        this.canComplete = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection(\"icons.can-complete\"));\n        this.locked = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection(\"icons.locked\"));\n        this.completed = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection(\"icons.completed\"));\n    }\n\n    public boolean isAutoReward() {\n        return autoReward;\n    }\n\n    public boolean isIslandMission() {\n        return islandMission;\n    }\n\n    public List<ItemStack> getItemRewards() {\n        return Collections.unmodifiableList(itemRewards);\n    }\n\n    public List<String> getCommandRewards() {\n        return Collections.unmodifiableList(commandRewards);\n    }\n\n    public int getIndex() {\n        return index;\n    }\n\n    public String getMissionName() {\n        return this.missionName;\n    }\n\n    public boolean isDisbandReset() {\n        return disbandReset;\n    }\n\n    public boolean isLeaveReset() {\n        return leaveReset;\n    }\n\n    public int getResetAmount() {\n        return resetAmount;\n    }\n\n    public boolean isResetAfterFinish() {\n        return resetAfterFinish;\n    }\n\n    public boolean hasLocked() {\n        return locked != null;\n    }\n\n    public ItemBuilder getCompleted() {\n        return (completed == null ? TemplateItem.AIR : completed).getBuilder();\n    }\n\n    public ItemBuilder getLocked() {\n        return (locked == null ? TemplateItem.AIR : locked).getBuilder();\n    }\n\n    public ItemBuilder getCanComplete() {\n        return (canComplete == null ? TemplateItem.AIR : canComplete).getBuilder();\n    }\n\n    public ItemBuilder getNotCompleted() {\n        return (notCompleted == null ? TemplateItem.AIR : notCompleted).getBuilder();\n    }\n\n    @Override\n    public String toString() {\n        return \"MissionData{name=\" + this.missionName + \"}\";\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/MissionReference.java",
    "content": "package com.bgsoftware.superiorskyblock.mission;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\n\npublic class MissionReference {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final String missionName;\n    private WeakReference<Mission<?>> reference;\n\n    public MissionReference(Mission<?> mission) {\n        this.missionName = mission.getName();\n        this.reference = new WeakReference<>(mission);\n    }\n\n    @Nullable\n    public Mission<?> getMission() {\n        Mission<?> mission = this.reference.get();\n\n        if (mission == null) {\n            mission = plugin.getMissions().getMission(this.missionName);\n            if (mission != null)\n                this.reference = new WeakReference<>(mission);\n        }\n\n        return mission;\n    }\n\n    public boolean isValid() {\n        return this.getMission() != null;\n    }\n\n    @Override\n    public int hashCode() {\n        return this.missionName.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        MissionReference that = (MissionReference) o;\n        return that.missionName.hashCode() == that.missionName.hashCode() &&\n                Objects.equals(missionName, that.missionName);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.mission;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.MissionsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Either;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.io.FileClassLoader;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.JarFiles;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.mission.container.MissionsContainer;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.inventory.ItemStack;\n\nimport javax.script.ScriptException;\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Consumer;\n\npublic class MissionsManagerImpl extends Manager implements MissionsManager {\n\n    private static final Object DATA_FOLDER_MUTEX = new Object();\n\n    private final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    private final Map<String, FileClassLoader> missionTypesClassLoaders = new HashMap<>();\n\n    private final MissionsContainer missionsContainer;\n\n    public MissionsManagerImpl(SuperiorSkyblockPlugin plugin, MissionsContainer missionsContainer) {\n        super(plugin);\n        this.missionsContainer = missionsContainer;\n    }\n\n    @Override\n    public void loadData() {\n        if (!BuiltinModules.MISSIONS.isEnabled())\n            return;\n\n        BukkitExecutor.asyncTimer(this::saveMissionsData, 6000L); // Save missions data every 5 minutes\n    }\n\n    public void clearData() {\n        saveMissionsData();\n\n        List<Mission<?>> missionsList = plugin.getMissions().getAllMissions();\n        this.missionsContainer.clearMissionsData();\n\n        for (Mission<?> mission : missionsList) {\n            // Unload the mission\n            mission.unload();\n        }\n\n        this.missionTypesClassLoaders.forEach((missionJarName, classLoader) -> {\n            try {\n                ((URLClassLoader) classLoader).close();\n            } catch (Exception error) {\n                Log.error(error, \"An error occurred while unloading mission jar \", missionJarName, \":\");\n            }\n        });\n        this.missionTypesClassLoaders.clear();\n\n        // This is an attempt to force Windows to free the handles of the file.\n        System.gc();\n    }\n\n    @Override\n    public Mission<?> getMission(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.missionsContainer.getMission(name);\n    }\n\n    @Override\n    public List<Mission<?>> getAllMissions() {\n        return this.missionsContainer.getAllMissions();\n    }\n\n    @Override\n    public List<Mission<?>> getPlayerMissions() {\n        return this.missionsContainer.getPlayerMissions();\n    }\n\n    @Override\n    public List<Mission<?>> getIslandMissions() {\n        return this.missionsContainer.getIslandMissions();\n    }\n\n    @Nullable\n    @Override\n    public MissionCategory getMissionCategory(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.missionsContainer.getMissionCategory(name);\n    }\n\n    @Override\n    public List<MissionCategory> getMissionCategories() {\n        return this.missionsContainer.getMissionCategories();\n    }\n\n    @Override\n    public boolean hasCompleted(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n\n        Optional<MissionData> missionDataOptional = getMissionData(mission);\n\n        if (!missionDataOptional.isPresent())\n            return false;\n\n        MissionData missionData = missionDataOptional.get();\n\n        Island playerIsland = superiorPlayer.getIsland();\n\n        if (missionData.isIslandMission()) {\n            if (playerIsland != null)\n                return playerIsland.hasCompletedMission(mission);\n        } else {\n            return superiorPlayer.hasCompletedMission(mission);\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean canComplete(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        return canCompleteNoProgress(superiorPlayer, mission) && mission.getProgress(superiorPlayer) >= 1.0;\n    }\n\n    @Override\n    public boolean canCompleteNoProgress(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        return canCompleteAgain(superiorPlayer, mission) && hasAllRequiredMissions(superiorPlayer, mission) &&\n                canPassAllChecks(superiorPlayer, mission);\n    }\n\n    @Override\n    public boolean canCompleteAgain(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n\n        Optional<MissionData> missionDataOptional = getMissionData(mission);\n\n        if (!missionDataOptional.isPresent())\n            return false;\n\n        MissionData missionData = missionDataOptional.get();\n\n        Island playerIsland = superiorPlayer.getIsland();\n\n        if (missionData.isIslandMission()) {\n            if (playerIsland != null)\n                return playerIsland.canCompleteMissionAgain(mission);\n        } else {\n            return superiorPlayer.canCompleteMissionAgain(mission);\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean hasAllRequiredMissions(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        return mission.getRequiredMissions().stream().allMatch(_mission -> {\n            Mission<?> missionToCheck = _mission == null ? null : plugin.getMissions().getMission(_mission);\n            return missionToCheck != null && hasCompleted(superiorPlayer, missionToCheck);\n        });\n    }\n\n    @Override\n    public boolean canPassAllChecks(SuperiorPlayer superiorPlayer, Mission<?> mission) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n\n        return offlinePlayer != null && mission.getRequiredChecks().stream().allMatch(check -> {\n            check = this.placeholdersService.get().parsePlaceholders(offlinePlayer, check);\n            try {\n                return Boolean.parseBoolean(plugin.getScriptEngine().eval(check) + \"\");\n            } catch (ScriptException error) {\n                Log.entering(\"ENTER\", superiorPlayer.getName(), mission.getName());\n                Log.error(error, \"An unexpected error occurred while checking mission requirements:\");\n                return false;\n            }\n        });\n    }\n\n    @Override\n    public void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        rewardMission(mission, superiorPlayer, checkAutoReward, false);\n    }\n\n    @Override\n    public void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        rewardMission(mission, superiorPlayer, checkAutoReward, forceReward, null);\n    }\n\n    @Override\n    public void rewardMission(Mission<?> mission, SuperiorPlayer superiorPlayer,\n                              boolean checkAutoReward, boolean forceReward, @Nullable Consumer<Boolean> result) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n\n        Optional<MissionData> missionDataOptional = getMissionData(mission);\n\n        if (!missionDataOptional.isPresent()) {\n            if (result != null)\n                result.accept(false);\n            return;\n        }\n\n        Log.debug(Debug.REWARD_MISSION, mission.getName(), superiorPlayer.getName(), checkAutoReward, forceReward);\n\n        MissionData missionData = missionDataOptional.get();\n\n        IMissionsHolder missionsHolder = missionData.isIslandMission() ? superiorPlayer.getIsland() : superiorPlayer;\n\n        if (missionsHolder == null) {\n            mission.onCompleteFail(superiorPlayer);\n            if (result != null)\n                result.accept(false);\n            throw new IllegalStateException(\"Cannot reward island mission \" + mission.getName() + \" as the player \" + superiorPlayer.getName() + \" does not have island.\");\n        }\n\n        BukkitExecutor.ensureAsync(() -> rewardMissionAsyncInternal(mission, missionData, superiorPlayer,\n                missionsHolder, checkAutoReward, forceReward, result));\n    }\n\n    private void rewardMissionAsyncInternal(Mission<?> mission, MissionData missionData, SuperiorPlayer superiorPlayer,\n                                            IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward,\n                                            @Nullable Consumer<Boolean> result) {\n        boolean rewarded;\n        synchronized (superiorPlayer) {\n            rewarded = tryRewardMissionLockedInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward);\n        }\n        if (result != null)\n            result.accept(rewarded);\n    }\n\n    private boolean tryRewardMissionLockedInternal(Mission<?> mission, MissionData missionData, SuperiorPlayer superiorPlayer,\n                                                   IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward) {\n        if (!forceReward) {\n            if (!canCompleteAgain(superiorPlayer, mission)) {\n                mission.onCompleteFail(superiorPlayer);\n                return false;\n            }\n\n            if (!canComplete(superiorPlayer, mission)) {\n                return false;\n            }\n\n            if (checkAutoReward) {\n                boolean shouldAutoReward = isAutoReward(mission);\n                if (shouldAutoReward && !BuiltinModules.MISSIONS.getConfiguration().isAutoRewardOutsideIslands() &&\n                        !plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) {\n                    return false;\n                }\n\n                if (!shouldAutoReward) {\n                    if (canCompleteAgain(superiorPlayer, mission)) {\n                        Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName());\n                        return false;\n                    }\n                }\n            }\n        }\n\n        List<ItemStack> itemRewards = new ArrayList<>();\n        List<String> commandRewards;\n\n        //noinspection SynchronizationOnLocalVariableOrMethodParameter\n        synchronized (missionData) {\n            missionData.getItemRewards().forEach(itemStack -> itemRewards.add(itemStack.clone()));\n            commandRewards = new LinkedList<>(missionData.getCommandRewards());\n        }\n\n        PluginEvent<PluginEventArgs.MissionComplete> event = PluginEventsFactory.callMissionCompleteEvent(\n                superiorPlayer, missionsHolder, mission, itemRewards, commandRewards);\n\n        if (event.isCancelled()) {\n            if (!forceReward)\n                mission.onCompleteFail(superiorPlayer);\n            return false;\n        }\n\n        if (!forceReward)\n            mission.onComplete(superiorPlayer);\n\n        missionsHolder.completeMission(mission);\n\n        if (missionData.isResetAfterFinish()) {\n            mission.clearData(superiorPlayer);\n        } else {\n            // We want to add the data to the next missions as well\n            Object playerMissionProgress = mission.get(superiorPlayer);\n            for (Mission otherMission : mission.getMissionCategory().getMissions()) {\n                if (otherMission.getRequiredMissions().contains(mission.getName()) &&\n                        canCompleteNoProgress(superiorPlayer, otherMission)) {\n                    try {\n                        otherMission.insertData(superiorPlayer, playerMissionProgress);\n                    } catch (ClassCastException error) {\n                        // We use raw parameterized values, therefore cast-errors can occur.\n                        // In this case, we'll just ignore these.\n                    }\n                }\n            }\n        }\n\n        List<ItemStack> rewardedItems = new LinkedList<>();\n        for (ItemStack itemStack : event.getArgs().itemRewards) {\n            ItemStack toGive = new ItemBuilder(itemStack)\n                    .replaceAll(\"{0}\", mission.getName())\n                    .replaceAll(\"{1}\", superiorPlayer.getName())\n                    .replaceAll(\"{2}\", getIslandPlaceholder(missionsHolder))\n                    .build();\n            toGive.setAmount(itemStack.getAmount());\n            rewardedItems.add(toGive);\n        }\n\n        // Auto complete other missions that depend on the mission that was just completed\n        for (Mission<?> otherMission : getAllMissions()) {\n            if (otherMission.getRequiredMissions().contains(mission.getName()) && otherMission.canComplete(superiorPlayer)) {\n                // Auto reward the next mission\n                rewardMission(otherMission, superiorPlayer, true);\n            }\n        }\n\n        if (!rewardedItems.isEmpty() || !event.getArgs().commandRewards.isEmpty()) {\n            BukkitExecutor.ensureMain(() -> {\n                if (!rewardedItems.isEmpty()) {\n                    superiorPlayer.runIfOnline(player -> {\n                        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                            for (ItemStack toGive : itemRewards) {\n                                BukkitItems.addItem(toGive, player.getInventory(), player.getLocation(wrapper.getHandle()));\n                            }\n                        }\n                    });\n                }\n\n                for (String command : event.getArgs().commandRewards) {\n                    Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command\n                            .replace(\"%mission%\", mission.getName())\n                            .replace(\"%player%\", superiorPlayer.getName())\n                            .replace(\"%island%\", getIslandPlaceholder(missionsHolder))\n                    );\n                }\n            });\n        }\n\n        return true;\n    }\n\n    private boolean moveOldDataFolder(File newDataFolder) {\n        File oldDataFolder = new File(BuiltinModules.MISSIONS.getModuleFolder(), \"data\");\n\n        if (!oldDataFolder.exists())\n            return true;\n\n        newDataFolder.mkdirs();\n\n        for (File file : Files.listFolderFiles(oldDataFolder, false)) {\n            File targetFile = new File(newDataFolder, file.getName());\n            if (!file.renameTo(targetFile))\n                return false;\n        }\n\n        Files.deleteDirectory(oldDataFolder);\n\n        return true;\n    }\n\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    @Override\n    public void saveMissionsData() {\n        File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder();\n\n        if (!dataFolder.exists())\n            dataFolder.mkdirs();\n\n        for (Mission<?> mission : getAllMissions()) {\n            YamlConfiguration data = new YamlConfiguration();\n\n            try {\n                mission.saveProgress(data);\n            } catch (Throwable error) {\n                Log.error(error, \"An unexpected error while saving mission data for \", mission.getName(), \":\");\n                continue;\n            }\n\n            boolean anyDataToWrite = !data.getKeys(true).isEmpty();\n\n            File dataFile = new File(dataFolder, mission.getName() + \".yml\");\n            boolean dataFileExists = dataFile.exists();\n\n            if (!anyDataToWrite) {\n                if (dataFileExists)\n                    dataFile.delete();\n                continue;\n            }\n\n            try {\n                if (!dataFileExists)\n                    dataFile.createNewFile();\n                synchronized (DATA_FOLDER_MUTEX) {\n                    data.save(dataFile);\n                }\n            } catch (IOException error) {\n                Log.error(error, \"An unexpected error occurred while saving missions data to file \", dataFile.getName(), \":\");\n            }\n        }\n    }\n\n    @Override\n    public void loadMissionsData() {\n        loadMissionsData(getAllMissions());\n    }\n\n    @Override\n    public void loadMissionsData(List<Mission<?>> missionsList) {\n        Preconditions.checkNotNull(missionsList, \"missionsList parameter cannot be null.\");\n\n        // Convert old data file to new format.\n        convertOldMissionsData();\n\n        File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder();\n\n        if (!moveOldDataFolder(dataFolder))\n            throw new IllegalStateException(\"Failed moving old missions folder.\");\n\n        if (!dataFolder.exists())\n            return;\n\n        for (Mission<?> mission : missionsList) {\n            File dataFile = new File(dataFolder, mission.getName() + \".yml\");\n            if (dataFile.exists()) {\n                try {\n                    synchronized (DATA_FOLDER_MUTEX) {\n                        mission.loadProgress(YamlConfiguration.loadConfiguration(dataFile));\n                    }\n                } catch (Throwable error) {\n                    Log.error(error, \"An unexpected error occurred while loading mission data for \", mission.getName(), \":\");\n                }\n            }\n        }\n    }\n\n    public void convertPlayerData(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) {\n        getAllMissions().forEach(mission -> mission.transferData(oldPlayer, newPlayer));\n\n        File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder();\n\n        if (!dataFolder.exists())\n            return;\n\n        // Convert the data in the data files as well\n        BukkitExecutor.async(() -> {\n            for (File file : Files.listFolderFiles(dataFolder, false)) {\n                synchronized (DATA_FOLDER_MUTEX) {\n                    Files.replaceString(file, oldPlayer.getUniqueId() + \"\", newPlayer.getUniqueId() + \"\");\n                }\n            }\n        });\n    }\n\n    public void loadMissionCategory(MissionCategory missionCategory) {\n        this.missionsContainer.addMissionCategory(missionCategory);\n    }\n\n    public boolean hasAllRequirements(Mission<?> mission, SuperiorPlayer superiorPlayer) {\n        return hasAllRequiredMissions(superiorPlayer, mission) && canPassAllChecks(superiorPlayer, mission);\n    }\n\n    public boolean canDisplayMission(Mission<?> mission, SuperiorPlayer superiorPlayer, boolean removeCompleted) {\n        if (mission.isOnlyShowIfRequiredCompleted() && !hasAllRequirements(mission, superiorPlayer))\n            return false;\n\n        if (removeCompleted) {\n            if (mission.getIslandMission() ? superiorPlayer.getIsland() != null &&\n                    !superiorPlayer.getIsland().canCompleteMissionAgain(mission) :\n                    !superiorPlayer.canCompleteMissionAgain(mission))\n                return false;\n        }\n\n        return true;\n    }\n\n    public boolean isPlayerMissionCategory(MissionCategory missionCategory) {\n        return this.missionsContainer.isPlayerMissionCategory(missionCategory);\n    }\n\n    public boolean hasAnyPlayerMissionCategories() {\n        return this.missionsContainer.hasAnyPlayerMissionCategories();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public Mission<?> loadMission(String missionName, String missionCategoryName, FilesLookup filesLookup, ConfigurationSection missionSection) {\n        Mission<?> newMission = null;\n\n        try {\n            Mission<?> mission = plugin.getMissions().getMission(missionName);\n\n            if (mission == null) {\n                String missionJarName = missionSection.getString(\"mission-file\") + \".jar\";\n                File missionJar = filesLookup.getFile(missionJarName);\n\n                if (!missionJar.exists())\n                    throw new RuntimeException(\"The mission file \" + missionJar.getName() + \" is not valid.\");\n\n                FileClassLoader missionClassLoader = this.missionTypesClassLoaders.computeIfAbsent(missionJarName, n -> {\n                    try {\n                        return new FileClassLoader(missionJar, plugin.getPluginClassLoader(),\n                                plugin.getNMSAlgorithms().getClassProcessor());\n                    } catch (IOException error) {\n                        throw new RuntimeException(error);\n                    }\n                });\n\n                Either<Class<?>, Throwable> missionClassLookup = JarFiles.getClass(missionJar.toURL(), Mission.class, missionClassLoader);\n\n                if (missionClassLookup.getRight() != null)\n                    throw new RuntimeException(\"An unexpected error occurred while reading \" + missionJar.getName() + \".\", missionClassLookup.getRight());\n\n                Class<?> missionClass = missionClassLookup.getLeft();\n\n                if (missionClass == null)\n                    throw new RuntimeException(\"The mission file \" + missionJar.getName() + \" is not valid.\");\n\n                boolean islandMission = missionSection.getBoolean(\"island\", false);\n                List<String> requiredMissions = missionSection.getStringList(\"required-missions\");\n                List<String> requiredChecks = missionSection.getStringList(\"required-checks\");\n\n                boolean onlyShowIfRequiredCompleted = missionSection.getBoolean(\"only-show-if-required-completed\", false);\n\n                mission = createInstance(missionClass, missionName, islandMission, requiredMissions, requiredChecks, onlyShowIfRequiredCompleted);\n                mission.load(plugin, missionSection);\n                this.missionsContainer.addMission(mission);\n                newMission = mission;\n            }\n\n            this.missionsContainer.addMissionData(new MissionData(mission, missionCategoryName, missionSection));\n\n            Log.info(\"Registered mission \" + missionName);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while registering mission \", missionName, \":\");\n        }\n\n        return newMission;\n    }\n\n    public Optional<MissionData> getMissionData(Mission<?> mission) {\n        return Optional.ofNullable(this.missionsContainer.getMissionData(mission));\n    }\n\n    private boolean isAutoReward(Mission<?> mission) {\n        Optional<MissionData> missionDataOptional = getMissionData(mission);\n        return missionDataOptional.isPresent() && missionDataOptional.get().isAutoReward();\n    }\n\n    private Mission<?> createInstance(Class<?> clazz, String name, boolean islandMission, List<String> requiredMissions, List<String> requiredChecks, boolean onlyShowIfRequiredCompleted) throws Exception {\n        Preconditions.checkArgument(Mission.class.isAssignableFrom(clazz), \"Class \" + clazz + \" is not a Mission.\");\n\n        for (Constructor<?> constructor : clazz.getConstructors()) {\n            if (constructor.getParameterCount() == 0) {\n                if (!constructor.isAccessible())\n                    constructor.setAccessible(true);\n\n                Mission<?> mission = (Mission<?>) constructor.newInstance();\n                mission.setName(name);\n                mission.setIslandMission(islandMission);\n                mission.addRequiredMission(requiredMissions.toArray(new String[0]));\n                mission.addRequiredCheck(requiredChecks.toArray(new String[0]));\n                if (onlyShowIfRequiredCompleted)\n                    mission.toggleOnlyShowIfRequiredCompleted();\n\n                return mission;\n            }\n        }\n\n        throw new IllegalArgumentException(\"Class \" + clazz + \" has no valid constructors.\");\n    }\n\n    private static String getIslandPlaceholder(@Nullable IMissionsHolder missionsHolder) {\n        if (!(missionsHolder instanceof Island))\n            return \"\";\n\n        Island island = (Island) missionsHolder;\n\n        return island.getName().isEmpty() ? island.getOwner() == null ? \"\" :\n                island.getOwner().getName() : island.getName();\n    }\n\n    private void convertOldMissionsData() {\n        File file = new File(BuiltinModules.MISSIONS.getModuleFolder(), \"_data.yml\");\n\n        if (!file.exists())\n            return;\n\n        File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder();\n\n        YamlConfiguration oldData = YamlConfiguration.loadConfiguration(file);\n\n        for (Mission<?> mission : getAllMissions()) {\n            if (oldData.isConfigurationSection(mission.getName())) {\n                ConfigurationSection dataSection = oldData.getConfigurationSection(mission.getName());\n                YamlConfiguration data = convertSectionToYaml(dataSection, new YamlConfiguration());\n\n                if (data.getKeys(true).isEmpty())\n                    continue;\n\n                File dataFile = new File(dataFolder, mission.getName() + \".yml\");\n\n                try {\n                    if (!dataFile.exists()) {\n                        dataFile.getParentFile().mkdirs();\n                        dataFile.createNewFile();\n                    }\n                    data.save(dataFile);\n                } catch (IOException error) {\n                    Log.error(error, \"An unexpected error occurred while saving old mission file \", mission.getName(), \":\");\n                }\n            }\n        }\n\n        file.delete();\n    }\n\n    private static YamlConfiguration convertSectionToYaml(ConfigurationSection section, YamlConfiguration config) {\n        for (String key : section.getKeys(false))\n            config.set(key, section.get(key));\n\n        return config;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/SMissionCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.mission;\n\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class SMissionCategory implements MissionCategory {\n\n    private final String name;\n    private final int slot;\n    private final List<Mission<?>> missions;\n\n    public SMissionCategory(String name, int slot, List<Mission<?>> missions) {\n        this.name = name;\n        this.slot = slot;\n        this.missions = missions;\n        missions.forEach(mission -> mission.setMissionCategory(this));\n    }\n\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    @Override\n    public int getSlot() {\n        return this.slot;\n    }\n\n    @Override\n    public List<Mission<?>> getMissions() {\n        return Collections.unmodifiableList(this.missions);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.mission.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.mission.MissionData;\n\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\npublic class DefaultMissionsContainer implements MissionsContainer {\n\n    private final Set<MissionCategory> playerMissionCategoriesCache = new HashSet<>();\n\n    private final Map<String, Mission<?>> missionMap = new HashMap<>();\n    private final Map<String, MissionData> missionDataMap = new HashMap<>();\n    private final Map<String, MissionCategory> missionCategoryMap = new HashMap<>();\n\n    @Override\n    public void addMission(Mission<?> mission) {\n        this.missionMap.put(mission.getName().toLowerCase(Locale.ENGLISH), mission);\n    }\n\n    @Nullable\n    @Override\n    public Mission<?> getMission(String name) {\n        return this.missionMap.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public List<Mission<?>> getAllMissions() {\n        return getFilteredMissions(missionData -> true);\n    }\n\n    @Override\n    public List<Mission<?>> getPlayerMissions() {\n        return getFilteredMissions(missionData -> !missionData.isIslandMission());\n    }\n\n    @Override\n    public List<Mission<?>> getIslandMissions() {\n        return getFilteredMissions(MissionData::isIslandMission);\n    }\n\n    @Override\n    public void addMissionData(MissionData missionData) {\n        this.missionDataMap.put(missionData.getMissionName(), missionData);\n    }\n\n    @Nullable\n    @Override\n    public MissionData getMissionData(Mission<?> mission) {\n        return this.missionDataMap.get(mission.getName());\n    }\n\n    @Override\n    public void addMissionCategory(MissionCategory missionCategory) {\n        this.missionCategoryMap.put(missionCategory.getName().toLowerCase(Locale.ENGLISH), missionCategory);\n\n        if (missionCategory.getMissions().stream().anyMatch(mission -> !mission.getIslandMission()))\n            playerMissionCategoriesCache.add(missionCategory);\n    }\n\n    @Nullable\n    @Override\n    public MissionCategory getMissionCategory(String name) {\n        return this.missionCategoryMap.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public List<MissionCategory> getMissionCategories() {\n        return new SequentialListBuilder<MissionCategory>().build(missionCategoryMap.values());\n    }\n\n    @Override\n    public boolean isPlayerMissionCategory(MissionCategory missionCategory) {\n        return playerMissionCategoriesCache.contains(missionCategory);\n    }\n\n    @Override\n    public boolean hasAnyPlayerMissionCategories() {\n        return !playerMissionCategoriesCache.isEmpty();\n    }\n\n    @Override\n    public void clearMissionsData() {\n        this.playerMissionCategoriesCache.clear();\n        this.missionMap.clear();\n        this.missionDataMap.clear();\n        this.missionCategoryMap.clear();\n    }\n\n    private List<Mission<?>> getFilteredMissions(Predicate<MissionData> predicate) {\n        return new SequentialListBuilder<MissionData>()\n                .filter(predicate)\n                .sorted(Comparator.comparingInt(MissionData::getIndex))\n                .map(missionDataMap.values(), missionData -> getMission(missionData.getMissionName()));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.mission.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.mission.MissionData;\n\nimport java.util.List;\n\npublic interface MissionsContainer {\n\n    void addMission(Mission<?> mission);\n\n    @Nullable\n    Mission<?> getMission(String name);\n\n    List<Mission<?>> getAllMissions();\n\n    List<Mission<?>> getPlayerMissions();\n\n    List<Mission<?>> getIslandMissions();\n\n    void addMissionData(MissionData missionData);\n\n    @Nullable\n    MissionData getMissionData(Mission<?> mission);\n\n    void addMissionCategory(MissionCategory missionCategory);\n\n    @Nullable\n    MissionCategory getMissionCategory(String name);\n\n    List<MissionCategory> getMissionCategories();\n\n    boolean isPlayerMissionCategory(MissionCategory missionCategory);\n\n    boolean hasAnyPlayerMissionCategories();\n\n    void clearMissionsData();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java",
    "content": "package com.bgsoftware.superiorskyblock.module;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLogger;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.core.io.Resources;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.util.Objects;\n\npublic abstract class BuiltinModule<T extends IModuleConfiguration> extends PluginModule {\n\n    protected T configuration;\n\n    public BuiltinModule(String moduleName) {\n        super(moduleName, \"Ome_R\");\n    }\n\n    @Override\n    public final void onEnable(SuperiorSkyblock plugin) {\n        onEnable((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract void onEnable(SuperiorSkyblockPlugin plugin);\n\n    @Override\n    public final void onReload(SuperiorSkyblock plugin) {\n        onReload((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected void onReload(SuperiorSkyblockPlugin plugin) {\n        onPluginInit(plugin);\n    }\n\n    @Override\n    public void onDisable(SuperiorSkyblock plugin) {\n        onDisable((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract void onDisable(SuperiorSkyblockPlugin plugin);\n\n    @Override\n    public void loadData(SuperiorSkyblock plugin) {\n        loadData((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract void loadData(SuperiorSkyblockPlugin plugin);\n\n    @Override\n    public Listener[] getModuleListeners(SuperiorSkyblock plugin) {\n        return !isEnabled() ? null : getModuleListeners((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin);\n\n    @Override\n    public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblock plugin) {\n        return !isEnabled() ? null : getSuperiorCommands((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin);\n\n    @Override\n    public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblock plugin) {\n        return !isEnabled() ? null : getSuperiorAdminCommands((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin);\n\n    public final T getConfiguration() {\n        return Objects.requireNonNull(this.configuration);\n    }\n\n    @Override\n    protected void onPluginInit(SuperiorSkyblock plugin) {\n        onPluginInit((SuperiorSkyblockPlugin) plugin);\n    }\n\n    protected void onPluginInit(SuperiorSkyblockPlugin plugin) {\n        File configFile = new File(getModuleFolder(), \"config.yml\");\n        boolean firstTime = false;\n\n        if (!configFile.exists()) {\n            Resources.saveResource(\"modules/\" + getName() + \"/config.yml\");\n            firstTime = true;\n        }\n\n        CommentedConfiguration config = CommentedConfiguration.loadConfiguration(configFile);\n\n        boolean commitChanges = onConfigCreate(plugin, config, firstTime);\n        if (commitChanges) {\n            try {\n                config.save(configFile);\n            } catch (Exception error) {\n                this.logger().e(\"An error occurred while saving config file for module \" + getName() + \":\", error);\n            }\n        }\n\n        try {\n            config.syncWithConfig(configFile,\n                    Resources.getResource(\"modules/\" + getName() + \"/config.yml\"),\n                    getIgnoredSections());\n        } catch (Exception error) {\n            this.logger().e(\"An error occurred while loading config file:\", error);\n        }\n\n\n        this.configuration = createConfigFile(config);\n    }\n\n    protected ModuleLogger logger() {\n        return (ModuleLogger) super.getLogger();\n    }\n\n    protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) {\n        return false;\n    }\n\n    public boolean isEnabled() {\n        return this.configuration.isEnabled() && isInitialized();\n    }\n\n    protected abstract T createConfigFile(CommentedConfiguration config);\n\n    protected String[] getIgnoredSections() {\n        return new String[0];\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModules.java",
    "content": "package com.bgsoftware.superiorskyblock.module;\n\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.module.bank.BankModule;\nimport com.bgsoftware.superiorskyblock.module.generators.GeneratorsModule;\nimport com.bgsoftware.superiorskyblock.module.missions.MissionsModule;\nimport com.bgsoftware.superiorskyblock.module.upgrades.UpgradesModule;\n\nimport java.util.Locale;\n\npublic class BuiltinModules {\n\n    public static final GeneratorsModule GENERATORS = new GeneratorsModule();\n    public static final MissionsModule MISSIONS = new MissionsModule();\n    public static final BankModule BANK = new BankModule();\n    public static final UpgradesModule UPGRADES = new UpgradesModule();\n\n    private BuiltinModules() {\n\n    }\n\n    public static PluginModule getBuiltinModule(String name) {\n        switch (name.toLowerCase(Locale.ENGLISH)) {\n            case \"generators\":\n                return GENERATORS;\n            case \"missions\":\n                return MISSIONS;\n            case \"bank\":\n                return BANK;\n            case \"upgrades\":\n                return UPGRADES;\n            default:\n                return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java",
    "content": "package com.bgsoftware.superiorskyblock.module;\n\npublic interface IModuleConfiguration {\n\n    boolean isEnabled();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/ModuleData.java",
    "content": "package com.bgsoftware.superiorskyblock.module;\n\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport org.bukkit.event.Listener;\n\npublic class ModuleData {\n\n    private final Listener[] listeners;\n    private final SuperiorCommand[] commands;\n    private final SuperiorCommand[] adminCommands;\n\n    public ModuleData(Listener[] listeners, SuperiorCommand[] commands, SuperiorCommand[] adminCommands) {\n        this.listeners = listeners;\n        this.commands = commands;\n        this.adminCommands = adminCommands;\n    }\n\n    public Listener[] getListeners() {\n        return listeners;\n    }\n\n    public SuperiorCommand[] getCommands() {\n        return commands;\n    }\n\n    public SuperiorCommand[] getAdminCommands() {\n        return adminCommands;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.module;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.handlers.ModulesManager;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.core.Either;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.io.FileClassLoader;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.JarFiles;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.module.container.ModulesContainer;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.net.URLClassLoader;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.stream.Stream;\n\npublic class ModulesManagerImpl extends Manager implements ModulesManager {\n\n    private final ModulesContainer modulesContainer;\n    private final File modulesFolder;\n    private final File dataFolder;\n\n    public ModulesManagerImpl(SuperiorSkyblockPlugin plugin, ModulesContainer modulesContainer) {\n        super(plugin);\n        this.modulesContainer = modulesContainer;\n        this.modulesFolder = new File(plugin.getDataFolder(), \"modules\");\n        this.dataFolder = new File(plugin.getDataFolder(), \"datastore/modules\");\n    }\n\n    @Override\n    public void loadData() {\n        if (!modulesFolder.exists())\n            //noinspection ResultOfMethodCallIgnored\n            modulesFolder.mkdirs();\n\n        registerModule(BuiltinModules.GENERATORS);\n        registerModule(BuiltinModules.MISSIONS);\n        registerModule(BuiltinModules.BANK);\n        registerModule(BuiltinModules.UPGRADES);\n        registerExternalModules();\n    }\n\n    @Override\n    public void registerModule(PluginModule pluginModule) {\n        Preconditions.checkNotNull(pluginModule, \"pluginModule parameter cannot be null.\");\n        this.modulesContainer.registerModule(pluginModule, modulesFolder, dataFolder);\n    }\n\n    @Override\n    public PluginModule registerModule(File moduleFile) throws IOException, ReflectiveOperationException {\n        Preconditions.checkArgument(moduleFile.exists(), \"The file \" + moduleFile.getName() + \" does not exist.\");\n        Preconditions.checkArgument(moduleFile.getName().endsWith(\".jar\"), \"The file \" + moduleFile.getName() + \" is not a valid jar file.\");\n\n        FileClassLoader moduleClassLoader = new FileClassLoader(moduleFile, plugin.getPluginClassLoader(),\n                plugin.getNMSAlgorithms().getClassProcessor());\n\n        Either<Class<?>, Throwable> moduleClassLookup = JarFiles.getClass(moduleFile.toURL(), PluginModule.class, moduleClassLoader);\n\n        if (moduleClassLookup.getRight() != null)\n            throw new RuntimeException(\"An error occurred while reading \" + moduleFile.getName(), moduleClassLookup.getRight());\n\n        Class<?> moduleClass = moduleClassLookup.getLeft();\n\n        if (moduleClass == null)\n            throw new RuntimeException(\"The module file \" + moduleFile.getName() + \" is not valid.\");\n\n        PluginModule pluginModule = createInstance(moduleClass);\n        pluginModule.initModuleLoader(moduleFile, moduleClassLoader);\n\n        registerModule(pluginModule);\n\n        return pluginModule;\n    }\n\n    @Override\n    public void unregisterModule(PluginModule pluginModule) {\n        Preconditions.checkNotNull(pluginModule, \"pluginModule parameter cannot be null.\");\n        Preconditions.checkState(getModule(pluginModule.getName()) != null, \"PluginModule with the name \" + pluginModule.getName() + \" is not registered in the plugin anymore.\");\n\n        Log.info(\"Disabling the module \", pluginModule.getName(), \"...\");\n\n        try {\n            pluginModule.onDisable(plugin);\n        } catch (Throwable error) {\n            Log.error(\"An unexpected error occurred while disabling the module \", pluginModule.getName(), \".\");\n            Log.error(error, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n        }\n\n        this.modulesContainer.unregisterModule(pluginModule);\n\n        if (pluginModule instanceof BuiltinModule)\n            return;\n\n        // We now want to unload the ClassLoader and free the held handles for the file.\n        ClassLoader classLoader = pluginModule.getClassLoader();\n        if (classLoader != plugin.getPluginClassLoader() && classLoader instanceof URLClassLoader) {\n            try {\n                ((URLClassLoader) classLoader).close();\n                // This is an attempt to force Windows to free the handles of the file.\n                System.gc();\n            } catch (IOException ignored) {\n            }\n        }\n\n    }\n\n    @Override\n    @Nullable\n    public PluginModule getModule(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.modulesContainer.getModule(name);\n    }\n\n    @Override\n    public Collection<PluginModule> getModules() {\n        return this.modulesContainer.getModules();\n    }\n\n    @Override\n    public void enableModule(PluginModule pluginModule) {\n        Preconditions.checkNotNull(pluginModule, \"pluginModule parameter cannot be null.\");\n\n        long startTime = System.currentTimeMillis();\n\n        Log.info(\"Enabling the module \", pluginModule.getName(), \"...\");\n\n        try {\n            pluginModule.onEnable(plugin);\n        } catch (Throwable error) {\n            Log.error(\"An unexpected error occurred while enabling the module \", pluginModule.getName(), \".\");\n            Log.error(error, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n\n            try {\n                // Unregistering the module.\n                unregisterModule(pluginModule);\n            } catch (Throwable error2) {\n                Log.error(\"An unexpected error occurred while disabling the module \", pluginModule.getName(), \".\");\n                Log.error(error2, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n            }\n\n            return;\n        }\n\n        startupModuleInternal(pluginModule);\n\n        Log.info(\"Finished enabling the module \", pluginModule.getName(), \" (Took \",\n                System.currentTimeMillis() - startTime, \"ms)\");\n    }\n\n    @Override\n    public void enableModules(ModuleLoadTime moduleLoadTime) {\n        Preconditions.checkNotNull(moduleLoadTime, \"moduleLoadTime parameter cannot be null.\");\n    }\n\n    public void runModuleLifecycle(ModuleLoadTime moduleLoadTime, boolean isReload) {\n        if (isReload) {\n            reloadModulesInternal(moduleLoadTime);\n        } else {\n            enableModulesInternal(moduleLoadTime);\n        }\n    }\n\n    private void reloadModulesInternal(ModuleLoadTime moduleLoadTime) {\n        filterModules(moduleLoadTime).forEach(this::reloadModuleInternal);\n    }\n\n    private void enableModulesInternal(ModuleLoadTime moduleLoadTime) {\n        filterModules(moduleLoadTime).forEach(this::enableModule);\n    }\n\n    private void reloadModuleInternal(PluginModule pluginModule) {\n        try {\n            pluginModule.onReload(plugin);\n        } catch (Throwable error) {\n            Log.error(\"An unexpected error occurred while reloading the module \", pluginModule.getName(), \".\");\n            Log.error(error, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n        }\n\n        // We remove the old module data, as all listeners and commands were cleared due to the reload\n        this.modulesContainer.removeModuleData(pluginModule);\n\n        // Register module data again\n        startupModuleInternal(pluginModule);\n    }\n\n    private void startupModuleInternal(PluginModule pluginModule) {\n        Listener[] listeners = pluginModule.getModuleListeners(plugin);\n        SuperiorCommand[] commands = pluginModule.getSuperiorCommands(plugin);\n        SuperiorCommand[] adminCommands = pluginModule.getSuperiorAdminCommands(plugin);\n\n        if (listeners != null || commands != null || adminCommands != null)\n            this.modulesContainer.addModuleData(pluginModule, new ModuleData(listeners, commands, adminCommands));\n\n        if (listeners != null) {\n            for (Listener listener : listeners)\n                Bukkit.getPluginManager().registerEvents(listener, plugin);\n        }\n\n        if (commands != null) {\n            for (SuperiorCommand superiorCommand : commands)\n                plugin.getCommands().registerCommand(superiorCommand);\n        }\n\n        if (adminCommands != null) {\n            for (SuperiorCommand superiorCommand : adminCommands)\n                plugin.getCommands().registerAdminCommand(superiorCommand);\n        }\n    }\n\n    public void loadModulesData(SuperiorSkyblockPlugin plugin) {\n        getModules().forEach(pluginModule -> {\n            try {\n                pluginModule.loadData(plugin);\n            } catch (Throwable error) {\n                Log.error(\"An unexpected error occurred while loading data for the module \", pluginModule.getName(), \".\");\n                Log.error(error, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n            }\n        });\n    }\n\n    private void registerExternalModules() {\n        List<File> folderFiles = Files.listFolderFiles(modulesFolder, false, file -> file.getName().endsWith(\".jar\"));\n        if (folderFiles.isEmpty())\n            return;\n\n        try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(this.modulesFolder)) {\n            for (File file : folderFiles) {\n                String fileName = file.getName();\n                try {\n                    registerModule(filesLookup.getFile(fileName));\n                } catch (Exception error) {\n                    Log.error(error, \"An unexpected error occurred while registering module \", fileName, \":\");\n                }\n            }\n        }\n    }\n\n    private Stream<PluginModule> filterModules(ModuleLoadTime moduleLoadTime) {\n        return this.modulesContainer.getModules().stream()\n                .filter(pluginModule -> pluginModule.getLoadTime() == moduleLoadTime);\n    }\n\n    private PluginModule createInstance(Class<?> clazz) throws ReflectiveOperationException {\n        Preconditions.checkArgument(PluginModule.class.isAssignableFrom(clazz), \"Class \" + clazz + \" is not a PluginModule.\");\n\n        for (Constructor<?> constructor : clazz.getConstructors()) {\n            if (constructor.getParameterCount() == 0) {\n                if (!constructor.isAccessible())\n                    constructor.setAccessible(true);\n\n                return (PluginModule) constructor.newInstance();\n            }\n        }\n\n        throw new IllegalArgumentException(\"Class \" + clazz + \" has no valid constructors.\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModule;\nimport com.bgsoftware.superiorskyblock.module.IModuleConfiguration;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminAddBankLimit;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminDeposit;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminSetBankLimit;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminWithdraw;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdBalance;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdBank;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdDeposit;\nimport com.bgsoftware.superiorskyblock.module.bank.commands.CmdWithdraw;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.math.BigDecimal;\n\npublic class BankModule extends BuiltinModule<BankModule.Configuration> {\n\n    public BankModule() {\n        super(\"bank\");\n    }\n\n    @Override\n    protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) {\n        File oldConfigFile = new File(plugin.getDataFolder(), \"config.yml\");\n        if (!oldConfigFile.exists())\n            return false;\n\n        CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile);\n        boolean updatedConfig = false;\n\n        if (syncValues(\"bank-worth-rate\", config, oldConfig))\n            updatedConfig = true;\n\n        if (syncValues(\"disband-refund\", config, oldConfig))\n            updatedConfig = true;\n\n        if (syncValues(\"bank-logs\", config, oldConfig))\n            updatedConfig = true;\n\n        if (syncValues(\"cache-logs\", config, oldConfig))\n            updatedConfig = true;\n\n        if (syncValues(\"bank-interest\", config, oldConfig))\n            updatedConfig = true;\n\n        return updatedConfig;\n    }\n\n    @Override\n    public void onEnable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void onDisable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void loadData(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) {\n        return null;\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdBalance(), new CmdBank(), new CmdDeposit(), new CmdWithdraw()};\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdAdminAddBankLimit(), new CmdAdminDeposit(),\n                new CmdAdminSetBankLimit(), new CmdAdminWithdraw()};\n    }\n\n    @Override\n    protected Configuration createConfigFile(CommentedConfiguration config) {\n        return new Configuration(config);\n    }\n\n    private static boolean syncValues(String section, YamlConfiguration newConfig, YamlConfiguration oldConfig) {\n        if (oldConfig.contains(section)) {\n            newConfig.set(section, oldConfig.get(section));\n            return true;\n        }\n\n        return false;\n    }\n\n    public static class Configuration implements IModuleConfiguration {\n\n        private final boolean enabled;\n        private final double bankWorthRate;\n        private final boolean hasDisbandRefund;\n        private final BigDecimal disbandRefund;\n        private final boolean bankLogs;\n        private final boolean cacheAllLogs;\n        private final boolean bankInterestEnabled;\n        private final int bankInterestInterval;\n        private final int bankInterestPercentage;\n        private final int bankInterestRecentActive;\n\n        Configuration(CommentedConfiguration config) {\n            this.enabled = config.getBoolean(\"enabled\");\n            int bankWorthRate = config.getInt(\"bank-worth-rate\", 1000);\n            this.bankWorthRate = bankWorthRate == 0 ? 0D : 1D / bankWorthRate;\n            double disbandRefund = Math.max(0, Math.min(100, config.getDouble(\"disband-refund\"))) / 100D;\n            this.hasDisbandRefund = disbandRefund > 0;\n            this.disbandRefund = BigDecimal.valueOf(disbandRefund);\n            this.bankLogs = config.getBoolean(\"bank-logs\", true);\n            this.cacheAllLogs = config.getBoolean(\"cache-logs\", true);\n            this.bankInterestEnabled = config.getBoolean(\"bank-interest.enabled\", true);\n            this.bankInterestInterval = config.getInt(\"bank-interest.interval\", 86400);\n            this.bankInterestPercentage = config.getInt(\"bank-interest.percentage\", 10);\n            this.bankInterestRecentActive = config.getInt(\"bank-interest.recent-active\", 86400);\n        }\n\n        @Override\n        public boolean isEnabled() {\n            return this.enabled;\n        }\n\n        public double getBankWorthRate() {\n            return bankWorthRate;\n        }\n\n        public boolean hasDisbandRefund() {\n            return hasDisbandRefund;\n        }\n\n        public BigDecimal getDisbandRefund() {\n            return disbandRefund;\n        }\n\n        public boolean isBankLogs() {\n            return bankLogs;\n        }\n\n        public boolean isCacheAllLogs() {\n            return cacheAllLogs;\n        }\n\n        public boolean isBankInterestEnabled() {\n            return bankInterestEnabled;\n        }\n\n        public int getBankInterestInterval() {\n            return bankInterestInterval;\n        }\n\n        public int getBankInterestPercentage() {\n            return bankInterestPercentage;\n        }\n\n        public int getBankInterestRecentActive() {\n            return bankInterestRecentActive;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddBankLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addbanklimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addbanklimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addbanklimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        BigDecimal limit = CommandArguments.getBigDecimalAmount(sender, args[3]);\n\n        if (limit == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBankLimit> event = PluginEventsFactory.callIslandChangeBankLimitEvent(\n                    island, sender, island.getBankLimit().add(limit));\n            if (!event.isCancelled()) {\n                island.setBankLimit(event.getArgs().bankLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_BANK_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_BANK_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminDeposit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminDeposit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"deposit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.deposit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin deposit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_DEPOSIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        BigDecimal amount = CommandArguments.getBigDecimalAmount(sender, args[3]);\n\n        if (amount == null)\n            return;\n\n        islands.forEach(island -> island.getIslandBank().depositAdminMoney(sender, amount));\n\n        if (targetPlayer == null)\n            Message.ADMIN_DEPOSIT_MONEY_NAME.send(sender, Formatters.NUMBER_FORMATTER.format(amount), islands.size() == 1 ? islands.get(0).getName() : \"all\");\n        else\n            Message.ADMIN_DEPOSIT_MONEY.send(sender, Formatters.NUMBER_FORMATTER.format(amount), targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminSetBankLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetBankLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setbanklimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setbanklimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setbanklimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        BigDecimal limit = CommandArguments.getBigDecimalAmount(sender, args[3]);\n\n        if (limit == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBankLimit> event = PluginEventsFactory.callIslandChangeBankLimitEvent(island, sender, limit);\n            if (!event.isCancelled()) {\n                island.setBankLimit(event.getArgs().bankLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_BANK_LIMIT_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_BANK_LIMIT.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminWithdraw.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminWithdraw implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"withdraw\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.withdraw\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin withdraw <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_WITHDRAW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) {\n        BigDecimal amount = BigDecimal.valueOf(-1);\n\n        if (args[3].equalsIgnoreCase(\"all\") || args[3].equals(\"*\")) {\n            amount = island.getIslandBank().getBalance();\n        } else try {\n            amount = new BigDecimal(args[3]);\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        if (amount.compareTo(BigDecimal.ZERO) <= 0) {\n            Message.INVALID_AMOUNT.send(sender, args[3]);\n            return;\n        }\n\n        if (island.getIslandBank().getBalance().compareTo(BigDecimal.ZERO) == 0) {\n            Message.ISLAND_BANK_EMPTY.send(sender);\n            return;\n        }\n\n        if (island.getIslandBank().getBalance().compareTo(amount) < 0) {\n            Message.WITHDRAW_ALL_MONEY.send(sender, island.getIslandBank().getBalance().toString());\n            amount = island.getIslandBank().getBalance();\n        }\n\n        island.getIslandBank().withdrawAdminMoney(sender, amount);\n\n        if (targetPlayer == null)\n            Message.WITHDRAWN_MONEY_NAME.send(sender, Formatters.NUMBER_FORMATTER.format(amount), island.getName());\n        else\n            Message.WITHDRAWN_MONEY.send(sender, Formatters.NUMBER_FORMATTER.format(amount), targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBalance.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdBalance implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"balance\", \"bal\", \"money\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.balance\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"balance [\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BALANCE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender) :\n                CommandArguments.getIsland(plugin, sender, args[1]);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n        SuperiorPlayer targetPlayer = arguments.getSuperiorPlayer();\n\n        if (island == superiorPlayer.getIsland())\n            Message.ISLAND_BANK_SHOW.send(sender, island.getIslandBank().getBalance());\n        else if (targetPlayer == null)\n            Message.ISLAND_BANK_SHOW_OTHER_NAME.send(sender, island.getName(), island.getIslandBank().getBalance());\n        else\n            Message.ISLAND_BANK_SHOW_OTHER.send(sender, targetPlayer.getName(), island.getIslandBank().getBalance());\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1],\n                plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdBank implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"bank\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.bank\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        if (BuiltinModules.BANK.getConfiguration().isBankLogs())\n            return \"bank [logs]\";\n        else\n            return \"bank\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_BANK.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return BuiltinModules.BANK.getConfiguration().isBankLogs() ? 2 : 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        if (args.length == 2 && args[1].equalsIgnoreCase(\"logs\") &&\n                BuiltinModules.BANK.getConfiguration().isBankLogs()) {\n            plugin.getMenus().openBankLogs(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n        } else {\n            plugin.getMenus().openIslandBank(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return args.length != 2 || !BuiltinModules.BANK.getConfiguration().isBankLogs()\n                ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[1], \"logs\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdDeposit implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"deposit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.deposit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"deposit <\" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_DEPOSIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        BigDecimal moneyInBank = plugin.getProviders().getBankEconomyProvider().getBalance(superiorPlayer);\n        BigDecimal amount = BigDecimal.valueOf(-1);\n\n        if (args[1].equalsIgnoreCase(\"all\") || args[1].equals(\"*\")) {\n            amount = moneyInBank;\n        } else try {\n            amount = BigDecimal.valueOf(Double.parseDouble(args[1]));\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        BankTransaction transaction = island.getIslandBank().depositMoney(superiorPlayer, amount);\n        MenuActions.handleDeposit(superiorPlayer, island, transaction, null, null, amount);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java",
    "content": "package com.bgsoftware.superiorskyblock.module.bank.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuActions;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdWithdraw implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"withdraw\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.withdraw\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"withdraw <\" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_WITHDRAW.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n\n        BigDecimal amount = BigDecimal.valueOf(-1);\n\n        if (args[1].equalsIgnoreCase(\"all\") || args[1].equals(\"*\")) {\n            amount = island.getIslandBank().getBalance();\n        } else try {\n            amount = new BigDecimal(args[1]);\n        } catch (IllegalArgumentException ignored) {\n        }\n\n        BankTransaction transaction = island.getIslandBank().withdrawMoney(superiorPlayer, amount, null);\n        MenuActions.handleWithdraw(superiorPlayer, island, transaction, null, null, amount);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.module.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleInitializeData;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLogger;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.module.ModuleData;\nimport com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.event.HandlerList;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class DefaultModulesContainer implements ModulesContainer {\n\n    private final Map<String, PluginModule> modulesMap = new HashMap<>();\n    private final Map<PluginModule, ModuleData> modulesData = new ArrayMap<>();\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final File globalLogsFolder;\n    private final File globalArchiveLogsFolder;\n\n    public DefaultModulesContainer(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        this.globalLogsFolder = new File(plugin.getDataFolder(), \"logs\" + File.separator + \"modules\");\n        this.globalArchiveLogsFolder = new File(plugin.getDataFolder(), \"logs\" + File.separator + \"archive\");\n    }\n\n    @Override\n    public void registerModule(PluginModule pluginModule, File modulesFolder, File modulesDataFolder) {\n        String moduleName = pluginModule.getName().toLowerCase(Locale.ENGLISH);\n\n        Preconditions.checkState(!modulesMap.containsKey(moduleName), \"PluginModule with the name \" + moduleName + \" already exists.\");\n\n        File dataFolder = new File(modulesDataFolder, pluginModule.getName());\n        File moduleFolder = new File(modulesFolder, pluginModule.getName());\n        File logsFolder = new File(this.globalLogsFolder, pluginModule.getName());\n\n        ModuleLogger moduleLogger = new ModuleLogger(pluginModule);\n        ModuleLoggerFileHandler.addToLogger(logsFolder, this.globalArchiveLogsFolder, moduleLogger);\n\n        try {\n            ModuleInitializeDataImpl context = new ModuleInitializeDataImpl(dataFolder, moduleFolder, moduleLogger);\n            pluginModule.initModule(plugin, context);\n        } catch (Throwable error) {\n            Log.error(\"An unexpected error occurred while initializing the module \", pluginModule.getName(), \".\");\n            Log.error(error, \"Contact \", pluginModule.getAuthor(), \" regarding this, this has nothing to do with the plugin.\");\n            return;\n        }\n\n        modulesMap.put(moduleName, pluginModule);\n    }\n\n    @Override\n    public void unregisterModule(PluginModule pluginModule) {\n        ModuleData moduleData = modulesData.remove(pluginModule);\n\n        if (moduleData != null) {\n            if (moduleData.getListeners() != null) {\n                for (Listener listener : moduleData.getListeners())\n                    HandlerList.unregisterAll(listener);\n            }\n\n            if (moduleData.getCommands() != null) {\n                for (SuperiorCommand superiorCommand : moduleData.getCommands())\n                    plugin.getCommands().unregisterCommand(superiorCommand);\n            }\n\n            if (moduleData.getAdminCommands() != null) {\n                for (SuperiorCommand superiorCommand : moduleData.getAdminCommands())\n                    plugin.getCommands().unregisterAdminCommand(superiorCommand);\n            }\n        }\n\n        pluginModule.disableModule();\n\n        modulesMap.remove(pluginModule.getName().toLowerCase(Locale.ENGLISH));\n    }\n\n    @Nullable\n    @Override\n    public PluginModule getModule(String name) {\n        return this.modulesMap.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public Collection<PluginModule> getModules() {\n        return new SequentialListBuilder<PluginModule>().build(modulesMap.values());\n    }\n\n    @Override\n    public void addModuleData(PluginModule pluginModule, ModuleData moduleData) {\n        this.modulesData.put(pluginModule, moduleData);\n    }\n\n    @Override\n    public void removeModuleData(PluginModule module) {\n        this.modulesData.remove(module);\n    }\n\n    private static class ModuleInitializeDataImpl implements ModuleInitializeData {\n\n        private final File dataFolder;\n        private final File moduleFolder;\n        private final ModuleLogger logger;\n\n        public ModuleInitializeDataImpl(File dataFolder, File moduleFolder, ModuleLogger logger) {\n            this.dataFolder = dataFolder;\n            this.moduleFolder = moduleFolder;\n            this.logger = logger;\n        }\n\n        @Override\n        public File getDataFolder() {\n            return this.dataFolder;\n        }\n\n        @Override\n        public File getModuleFolder() {\n            return this.moduleFolder;\n        }\n\n        @Override\n        public ModuleLogger getLogger() {\n            return this.logger;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.module.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.modules.PluginModule;\nimport com.bgsoftware.superiorskyblock.module.ModuleData;\n\nimport java.io.File;\nimport java.util.Collection;\n\npublic interface ModulesContainer {\n\n    void registerModule(PluginModule pluginModule, File modulesFolder, File modulesDataFolder);\n\n    void unregisterModule(PluginModule pluginModule);\n\n    @Nullable\n    PluginModule getModule(String name);\n\n    Collection<PluginModule> getModules();\n\n    void addModuleData(PluginModule pluginModule, ModuleData moduleData);\n\n    void removeModuleData(PluginModule module);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java",
    "content": "package com.bgsoftware.superiorskyblock.module.generators;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModule;\nimport com.bgsoftware.superiorskyblock.module.IModuleConfiguration;\nimport com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminAddGenerator;\nimport com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminClearGenerator;\nimport com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminSetGenerator;\nimport com.bgsoftware.superiorskyblock.module.generators.listeners.GeneratorsListener;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\n\npublic class GeneratorsModule extends BuiltinModule<GeneratorsModule.Configuration> {\n\n    public GeneratorsModule() {\n        super(\"generators\");\n    }\n\n    @Override\n    protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) {\n        File oldConfigFile = new File(plugin.getDataFolder(), \"config.yml\");\n        if (!oldConfigFile.exists())\n            return false;\n\n        CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile);\n        boolean updatedConfig = false;\n\n        if (oldConfig.contains(\"generators\")) {\n            config.set(\"enabled\", oldConfig.getBoolean(\"generators\"));\n        }\n\n        return updatedConfig;\n    }\n\n    @Override\n    public void onEnable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void onDisable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void loadData(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) {\n        return new Listener[]{new GeneratorsListener(plugin)};\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) {\n        return null;\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdAdminAddGenerator(), new CmdAdminClearGenerator(), new CmdAdminSetGenerator()};\n    }\n\n    @Override\n    protected Configuration createConfigFile(CommentedConfiguration config) {\n        return new Configuration(config);\n    }\n\n    public static class Configuration implements IModuleConfiguration {\n\n        private final boolean enabled;\n        private final boolean matchGeneratorWorld;\n\n        Configuration(CommentedConfiguration config) {\n            this.enabled = config.getBoolean(\"enabled\");\n            this.matchGeneratorWorld = config.getBoolean(\"match-generator-world\");\n        }\n\n        @Override\n        public boolean isEnabled() {\n            return this.enabled;\n        }\n\n        public boolean isMatchGeneratorWorld() {\n            return this.matchGeneratorWorld;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java",
    "content": "package com.bgsoftware.superiorskyblock.module.generators.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddGenerator implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addgenerator\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addgenerator\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addgenerator <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + \"> [\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 6;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key material = Keys.ofMaterialAndData(args[3]);\n        boolean percentage = args[4].endsWith(\"%\");\n\n        if (percentage)\n            args[4] = args[4].substring(0, args[4].length() - 1);\n\n        NumberArgument<Integer> arguments = CommandArguments.getAmount(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int amount = arguments.getNumber();\n\n        if (amount == 0 || (percentage && (amount < 0 || amount > 100))) {\n            Message.INVALID_PERCENTAGE.send(sender);\n            return;\n        }\n\n        Dimension dimension = args.length == 5 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() :\n                CommandArguments.getDimension(sender, args[5]);\n\n        if (dimension == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (percentage) {\n                int ratePercentage = Math.max(0, Math.min(100, island.getGeneratorPercentage(material, dimension) + amount));\n                if (!island.setGeneratorPercentage(material, ratePercentage, dimension,\n                        sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null, true)) {\n                    continue;\n                }\n            } else {\n                int generatorRate = island.getGeneratorAmount(material, dimension) + amount;\n\n                if (generatorRate <= 0) {\n                    if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension))\n                        continue;\n\n                    island.removeGeneratorAmount(material, dimension);\n                } else {\n                    PluginEvent<PluginEventArgs.IslandChangeGeneratorRate> event = PluginEventsFactory.callIslandChangeGeneratorRateEvent(\n                            island, sender, material, dimension, island.getGeneratorAmount(material, dimension) + amount);\n\n                    if (event.isCancelled())\n                        continue;\n\n                    island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension);\n                }\n            }\n            ++islandsChangedCount;\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.GENERATOR_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.GENERATOR_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.GENERATOR_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) :\n                args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java",
    "content": "package com.bgsoftware.superiorskyblock.module.generators.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminClearGenerator implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"cleargenerator\", \"cg\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.cleargenerator\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin cleargenerator <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> [\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Dimension dimension = args.length == 3 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() :\n                CommandArguments.getDimension(sender, args[3]);\n\n        if (dimension == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (!PluginEventsFactory.callIslandClearGeneratorRatesEvent(island, sender, dimension))\n                continue;\n\n            ++islandsChangedCount;\n\n            island.clearGeneratorAmounts(dimension);\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.GENERATOR_CLEARED_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.GENERATOR_CLEARED_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.GENERATOR_CLEARED.send(sender, targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java",
    "content": "package com.bgsoftware.superiorskyblock.module.generators.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetGenerator implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setgenerator\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setgenerator\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setgenerator <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + \"> [\" +\n                Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 6;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key material = Keys.ofMaterialAndData(args[3]);\n        boolean percentage = args[4].endsWith(\"%\");\n\n        if (percentage)\n            args[4] = args[4].substring(0, args[4].length() - 1);\n\n        NumberArgument<Integer> arguments = CommandArguments.getAmount(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int amount = arguments.getNumber();\n\n        if (percentage && (amount < 0 || amount > 100)) {\n            Message.INVALID_PERCENTAGE.send(sender);\n            return;\n        }\n\n        Dimension dimension = args.length == 5 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() :\n                CommandArguments.getDimension(sender, args[5]);\n\n        if (dimension == null)\n            return;\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (percentage) {\n                if (!island.setGeneratorPercentage(material, amount, dimension,\n                        sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null, true)) {\n                    continue;\n                }\n            } else {\n                if (amount <= 0) {\n                    if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension))\n                        continue;\n\n                    island.removeGeneratorAmount(material, dimension);\n                } else {\n                    PluginEvent<PluginEventArgs.IslandChangeGeneratorRate> event = PluginEventsFactory.callIslandChangeGeneratorRateEvent(\n                            island, sender, material, dimension, amount);\n\n                    if (event.isCancelled())\n                        continue;\n\n                    island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension);\n                }\n            }\n            ++islandsChangedCount;\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islands.size() != 1)\n            Message.GENERATOR_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.GENERATOR_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.GENERATOR_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) :\n                args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java",
    "content": "package com.bgsoftware.superiorskyblock.module.generators.listeners;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.world.Dimensions;\nimport com.bgsoftware.superiorskyblock.world.GeneratorType;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockFormEvent;\nimport org.bukkit.event.block.BlockFromToEvent;\n\nimport java.util.Optional;\n\n@SuppressWarnings(\"unused\")\npublic class GeneratorsListener implements Listener {\n\n    private static final Material BASALT_MATERIAL = EnumHelper.getEnum(Material.class, \"BASALT\");\n    private static final Material LAVA_MATERIAL = EnumHelper.getEnum(Material.class, \"STATIONARY_LAVA\", \"LAVA\");\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public GeneratorsListener(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n    public void onBlockFormEvent(BlockFormEvent e) {\n        if (!BuiltinModules.GENERATORS.isEnabled())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = e.getBlock().getLocation(wrapper.getHandle());\n\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n            if (island == null)\n                return;\n\n            GeneratorType generatorType = e.getNewState().getType() == BASALT_MATERIAL ?\n                    GeneratorType.BASALT : GeneratorType.NORMAL;\n\n            if (e.getBlock().getType() != LAVA_MATERIAL || generatorType != GeneratorType.BASALT)\n                return;\n\n            Dimension dimension;\n            if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) {\n                dimension = Dimensions.fromEnvironment(World.Environment.NETHER);\n            } else {\n                World blockWorld = blockLocation.getWorld();\n                dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld))\n                        .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment()));\n            }\n\n            Key generatedBlock = island.generateBlock(blockLocation, dimension, true);\n\n            if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock()))\n                e.setCancelled(true);\n        }\n    }\n\n    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)\n    public void onBlockFromToEvent(BlockFromToEvent e) {\n        if (!BuiltinModules.GENERATORS.isEnabled())\n            return;\n\n        Block block = e.getToBlock();\n\n        // Should fix solid blocks from generating custom blocks\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/837\n        if (block.getType().isSolid())\n            return;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            World blockWorld = blockLocation.getWorld();\n\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n            if (island == null)\n                return;\n\n            if (e.getBlock().getType() != LAVA_MATERIAL)\n                return;\n\n            GeneratorType generatorType = GeneratorType.detectGenerator(block);\n            if (generatorType == GeneratorType.NONE)\n                return;\n\n            Dimension dimension;\n            if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) {\n                dimension = Dimensions.fromEnvironment(generatorType == GeneratorType.BASALT ? World.Environment.NETHER : World.Environment.NORMAL);\n            } else {\n                dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld))\n                        .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment()));\n            }\n\n            Key generatedBlock = island.generateBlock(blockLocation, dimension, true);\n\n            if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock()))\n                e.setCancelled(true);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java",
    "content": "package com.bgsoftware.superiorskyblock.module.logging;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLogger;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.FileTime;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.time.ZoneOffset;\nimport java.util.Date;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.FileHandler;\nimport java.util.logging.Formatter;\nimport java.util.logging.Handler;\nimport java.util.logging.Level;\nimport java.util.logging.LogRecord;\nimport java.util.logging.Logger;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\nimport java.util.zip.ZipOutputStream;\n\npublic class ModuleLoggerFileHandler {\n\n    private static final SimpleDateFormat ARCHIVE_DATE_FORMAT = new SimpleDateFormat(\"dd-MM-yyyy\");\n    private static final Path BASE_LOGS_FOLDER = new File(SuperiorSkyblockPlugin.getPlugin().getDataFolder(), \"logs\").toPath();\n\n    public static Logger addToLogger(File logsFolder, File archiveFolder, Logger logger) {\n        try {\n            logsFolder.mkdirs();\n\n            File logsFile = new File(logsFolder, \"latest.log\");\n\n            long startOfDayTime = LocalDate.now().atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000;\n\n            if (logsFile.exists() && logsFile.lastModified() < startOfDayTime) {\n                // Save old file\n                File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + \".zip\");\n                zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped);\n            }\n\n            AsyncFileHandler asyncFileHandler = new AsyncFileHandler(archiveFolder);\n            asyncFileHandler.setFile(logsFile);\n            asyncFileHandler.setLevel(Level.ALL);\n\n            logger.addHandler(asyncFileHandler);\n        } catch (IOException error) {\n            error.printStackTrace();\n        }\n\n        return logger;\n    }\n\n    private static void zipLogsFile(File file, String name, File zipFile) {\n        zipFile.getParentFile().mkdirs();\n\n        try {\n            File tempFile = new File(zipFile.getAbsolutePath() + \".tmp\");\n\n            byte[] buffer = new byte[1024];\n\n            try (ZipInputStream zis = zipFile.exists() ? new ZipInputStream(new FileInputStream(zipFile)) : null;\n                 ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile))) {\n\n                ZipEntry entry;\n\n                if (zis != null) {\n                    // Copy existing entries\n                    while ((entry = zis.getNextEntry()) != null) {\n                        ZipEntry newEntry = new ZipEntry(entry.getName());\n                        zos.putNextEntry(newEntry);\n                        newEntry.setLastModifiedTime(entry.getLastModifiedTime());\n                        int len;\n                        while ((len = zis.read(buffer)) != -1) {\n                            zos.write(buffer, 0, len);\n                        }\n                        zos.closeEntry();\n                    }\n                }\n\n                // Create new zip entry\n                ZipEntry zipEntry = new ZipEntry(name);\n                zos.putNextEntry(zipEntry);\n                zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified()));\n                zipEntry.setLastAccessTime(FileTime.fromMillis(file.lastModified()));\n                try (FileInputStream input = new FileInputStream(file)) {\n                    int length;\n                    while ((length = input.read(buffer)) >= 0) {\n                        zos.write(buffer, 0, length);\n                    }\n                }\n                zos.closeEntry();\n            } finally {\n                zipFile.delete();\n                tempFile.renameTo(zipFile);\n            }\n        } catch (Throwable error) {\n            error.printStackTrace();\n        }\n\n        file.delete();\n    }\n\n    private static class AsyncFileHandler extends Handler implements ModuleLogger.ModuleFileHandler {\n\n        private final BlockingQueue<LogRecord> queue = new LinkedBlockingQueue<>(10000);\n        private final Thread worker;\n        private final File archiveFolder;\n\n        private FileHandler fileHandler;\n        private File logsFile;\n\n        private volatile boolean running = true;\n\n        private volatile long nextDayTime;\n\n        private AsyncFileHandler(File archiveFolder) throws IOException {\n            this.archiveFolder = archiveFolder;\n\n            calculateTimeOfNextDay();\n\n            this.worker = new Thread(() -> {\n                try {\n                    while (running || !queue.isEmpty()) {\n                        LogRecord record = queue.poll(100, TimeUnit.MILLISECONDS);\n                        if (record != null) {\n                            if (System.currentTimeMillis() > nextDayTime) {\n                                // Upgrade file\n                                nextDayLogsFile();\n                            }\n\n                            fileHandler.publish(record);\n                        }\n                    }\n                } catch (InterruptedException ignored) {\n                } finally {\n                    fileHandler.flush();\n                    fileHandler.close();\n                }\n            }, \"AsyncLoggerThread\");\n\n            this.worker.setDaemon(true);\n            this.worker.start();\n        }\n\n        private void calculateTimeOfNextDay() {\n            this.nextDayTime = LocalDate.now().plusDays(1).atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000;\n        }\n\n        public void setFile(File file) throws IOException {\n            file.createNewFile();\n            this.fileHandler = new FileHandler(file.getAbsolutePath(), true);\n            this.fileHandler.setFormatter(new DebugFormatter());\n            this.logsFile = file;\n        }\n\n        private void nextDayLogsFile() {\n            this.fileHandler.close();\n            this.fileHandler = null;\n\n            File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + \".zip\");\n            zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped);\n\n            try {\n                setFile(this.logsFile);\n            } catch (Throwable error) {\n                error.printStackTrace();\n            }\n\n            calculateTimeOfNextDay();\n        }\n\n        @Override\n        public void publish(LogRecord record) {\n            if (!running) return;\n            this.queue.offer(record);\n        }\n\n        @Override\n        public void flush() {\n            this.fileHandler.flush();\n        }\n\n        @Override\n        public void close() throws SecurityException {\n            running = false;\n            try {\n                this.worker.join(1000);\n            } catch (InterruptedException ignored) {\n            }\n        }\n\n    }\n\n    private static class DebugFormatter extends Formatter {\n\n        private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(\"HH:mm:ss\");\n\n        @Override\n        public String format(LogRecord record) {\n            String time = DATE_FORMAT.format(new Date(record.getMillis()));\n            String level = record.getLevel().getLocalizedName();\n            return String.format(\"[%s %s]: %s%n\", time, level, formatMessage(record));\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java",
    "content": "package com.bgsoftware.superiorskyblock.module.missions;\n\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.MenuParserImpl;\nimport com.bgsoftware.superiorskyblock.core.io.Resources;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuParseResult;\nimport com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots;\nimport com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers;\nimport com.bgsoftware.superiorskyblock.mission.SMissionCategory;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModule;\nimport com.bgsoftware.superiorskyblock.module.IModuleConfiguration;\nimport com.bgsoftware.superiorskyblock.module.missions.commands.CmdAdminMission;\nimport com.bgsoftware.superiorskyblock.module.missions.commands.CmdMission;\nimport com.bgsoftware.superiorskyblock.module.missions.commands.CmdMissions;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.configuration.InvalidConfigurationException;\nimport org.bukkit.configuration.file.YamlConfiguration;\nimport org.bukkit.event.Listener;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Paths;\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class MissionsModule extends BuiltinModule<MissionsModule.Configuration> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final String[] IGNORED_SECTIONS = new String[]{\"categories\"};\n    private static final int MAX_MISSIONS_NAME_LENGTH = 255;\n\n    public MissionsModule() {\n        super(\"missions\");\n    }\n\n    @Override\n    protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) {\n        boolean updatedConfig = false;\n\n        if (convertOldMissions(plugin, config))\n            updatedConfig = true;\n        if (convertNonCategorizedMissions(plugin, config))\n            updatedConfig = true;\n\n        generateDefaultMissionJars();\n\n        if (firstTime) {\n            generateDefaultFiles();\n        }\n\n        return updatedConfig;\n    }\n\n    @Override\n    protected void onEnable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing\n    }\n\n    @Override\n    public void onReload(SuperiorSkyblockPlugin plugin) {\n        plugin.getMissions().saveMissionsData();\n        // Before we continue with the reload, we want to unload all the missions.\n        plugin.getMissions().clearData();\n        super.onReload(plugin);\n        onEnable(plugin);\n        plugin.getMissions().loadMissionsData();\n    }\n\n    @Override\n    public void onDisable(SuperiorSkyblockPlugin plugin) {\n        if (isEnabled())\n            plugin.getMissions().saveMissionsData();\n    }\n\n    @Override\n    public void loadData(SuperiorSkyblockPlugin plugin) {\n        List<Mission<?>> missionsToLoad = this.configuration.missionsToLoad;\n        if (!missionsToLoad.isEmpty()) {\n            plugin.getMissions().loadMissionsData(missionsToLoad);\n            missionsToLoad.clear();\n        }\n    }\n\n    @Override\n    public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) {\n        return null;\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdMission(), new CmdMissions()};\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdAdminMission()};\n    }\n\n    @Override\n    protected String[] getIgnoredSections() {\n        return IGNORED_SECTIONS;\n    }\n\n    @Override\n    protected Configuration createConfigFile(CommentedConfiguration config) {\n        return new Configuration(config);\n    }\n\n    public class Configuration implements IModuleConfiguration {\n\n        private final boolean enabled;\n        private final boolean autoRewardOutsideIslands;\n        private final List<Mission<?>> missionsToLoad = new LinkedList<>();\n\n        Configuration(CommentedConfiguration config) {\n            this.enabled = config.getBoolean(\"enabled\");\n            this.autoRewardOutsideIslands = config.getBoolean(\"auto-reward-outside-islands\");\n            if (this.enabled) {\n                loadMissionCategories(config);\n            }\n        }\n\n        @Override\n        public boolean isEnabled() {\n            return this.enabled;\n        }\n\n        public boolean isAutoRewardOutsideIslands() {\n            return this.autoRewardOutsideIslands;\n        }\n\n        private void loadMissionCategories(CommentedConfiguration config) {\n            ConfigurationSection categoriesSection = config.getConfigurationSection(\"categories\");\n\n            if (categoriesSection != null) {\n                for (String categoryName : categoriesSection.getKeys(false)) {\n                    ConfigurationSection categorySection = categoriesSection.getConfigurationSection(categoryName);\n\n                    if (categorySection == null)\n                        continue;\n\n                    List<Mission<?>> categoryMissions = new LinkedList<>();\n\n                    if (!canLoadCategory(categoryName, categoryMissions))\n                        continue;\n\n                    int slot = categorySection.getInt(\"slot\");\n\n                    String formattedCategoryName = categorySection.getString(\"name\", categoryName);\n\n                    plugin.getMissions().loadMissionCategory(new SMissionCategory(formattedCategoryName, slot, categoryMissions));\n\n                    missionsToLoad.addAll(categoryMissions);\n                }\n            }\n        }\n\n        private boolean canLoadCategory(String categoryName, List<Mission<?>> categoryMissions) {\n            File categoryFolder = new File(getModuleFolder(), \"categories/\" + categoryName);\n\n            if (!categoryFolder.exists()) {\n                logger().w(\"The directory of the mission category \" + categoryName + \" doesn't exist, skipping...\");\n                return false;\n            }\n\n            if (!categoryFolder.isDirectory()) {\n                logger().w(\"The directory of the mission category \" + categoryName + \" is not valid, skipping...\");\n                return false;\n            }\n\n            File[] missionFiles = categoryFolder.listFiles(file ->\n                    file.isFile() && file.getName().endsWith(\".yml\"));\n\n            if (missionFiles == null || missionFiles.length == 0) {\n                logger().w(\"The mission category \" + categoryName + \" doesn't have missions, skipping...\");\n                return false;\n            }\n\n            Map<Mission<?>, Integer> missionWeights = new ArrayMap<>();\n\n            try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(getModuleFolder())) {\n                for (File missionFile : missionFiles) {\n                    String missionName = missionFile.getName().replace(\".yml\", \"\");\n\n                    if (missionName.length() > MAX_MISSIONS_NAME_LENGTH)\n                        missionName = missionName.substring(0, MAX_MISSIONS_NAME_LENGTH);\n\n                    YamlConfiguration missionConfigFile = new YamlConfiguration();\n\n                    try {\n                        missionConfigFile.load(missionFile);\n                    } catch (InvalidConfigurationException error) {\n                        logger().e(\"A format-error occurred while parsing the mission file \" + missionFile.getName() + \":\", error);\n                        continue;\n                    } catch (IOException error) {\n                        logger().e(\"An unexpected error occurred while parsing the mission file \" + missionFile.getName() + \":\", error);\n                        continue;\n                    }\n\n                    ConfigurationSection missionSection = missionConfigFile.getConfigurationSection(\"\");\n\n                    Mission<?> mission = plugin.getMissions().loadMission(missionName, categoryName, filesLookup, missionSection);\n\n                    if (mission != null) {\n                        categoryMissions.add(mission);\n                        missionWeights.put(mission, missionSection.getInt(\"weight\", 0));\n                    }\n                }\n            }\n\n            if (categoryMissions.isEmpty()) {\n                logger().w(\"The mission category \" + categoryName + \" doesn't have missions, skipping...\");\n                return false;\n            }\n\n            // Sort missions by their names and weights.\n            categoryMissions.sort(new MissionsComparator(missionWeights));\n\n            return true;\n        }\n\n    }\n\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) {\n        ConfigurationSection missionsSection = config.getConfigurationSection(\"missions\");\n\n        if (missionsSection == null)\n            return false;\n\n        ConfigurationSection categoriesSection = config.createSection(\"categories\");\n\n        MenuParseResult<MenuIslandMembers.View> menuLoadResult = MenuParserImpl.getInstance().loadMenu(\"missions.yml\",\n                null);\n\n        if (menuLoadResult == null)\n            return false;\n\n        MenuPatternSlots menuPatternSlots = menuLoadResult.getPatternSlots();\n        YamlConfiguration missionsMenuConfig = menuLoadResult.getConfig();\n\n        List<Integer> islandsCategorySlot = menuPatternSlots.getSlots(missionsMenuConfig.getString(\"island-missions\", \"\"));\n        if (islandsCategorySlot.isEmpty()) {\n            categoriesSection.set(\"islands.name\", \"Islands\");\n            categoriesSection.set(\"islands.slot\", islandsCategorySlot.get(0));\n        }\n\n        List<Integer> playersCategorySlot = menuPatternSlots.getSlots(missionsMenuConfig.getString(\"player-missions\", \"\"));\n        if (playersCategorySlot.isEmpty()) {\n            categoriesSection.set(\"players.name\", \"Players\");\n            categoriesSection.set(\"players.slot\", playersCategorySlot.get(0));\n        }\n\n        File islandsCategoryFile = new File(getModuleFolder(), \"categories/islands\");\n        File playersCategoryFile = new File(getModuleFolder(), \"categories/players\");\n\n        islandsCategoryFile.mkdirs();\n        playersCategoryFile.mkdirs();\n\n        for (String missionName : missionsSection.getKeys(false)) {\n            ConfigurationSection missionSection = missionsSection.getConfigurationSection(missionName);\n\n            if (missionSection == null)\n                continue;\n\n            boolean islandsMission = missionSection.getBoolean(\"island\", false);\n\n            File missionFile = new File(islandsMission ? islandsCategoryFile : playersCategoryFile, missionName + \".yml\");\n\n            try {\n                missionFile.createNewFile();\n            } catch (IOException error) {\n                logger().e(\"An unexpected error occurred while converting non-categorized mission \" + missionName + \":\", error);\n                continue;\n            }\n\n            YamlConfiguration missionConfigFile = new YamlConfiguration();\n            missionSection.getValues(true).forEach(missionConfigFile::set);\n\n            try {\n                missionConfigFile.save(missionFile);\n            } catch (Exception error) {\n                logger().e(\"An unexpected error occurred while saving non-categorized mission \" + missionName + \":\", error);\n            }\n        }\n\n        config.set(\"missions\", \"\");\n\n        copyOldMissionsMenuFile(plugin);\n\n        return true;\n    }\n\n    @SuppressWarnings(\"ResultOfMethodCallIgnored\")\n    private boolean convertOldMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) {\n        boolean updatedConfig = false;\n\n        File oldMissionsFolder = new File(plugin.getDataFolder(), \"missions\");\n        if (oldMissionsFolder.exists()) {\n            File oldMissionsFile = new File(oldMissionsFolder, \"missions.yml\");\n\n            if (oldMissionsFile.exists()) {\n                YamlConfiguration oldConfig = YamlConfiguration.loadConfiguration(oldMissionsFile);\n                config.set(\"missions\", oldConfig.getConfigurationSection(\"\"));\n\n                updatedConfig = true;\n\n                oldMissionsFile.delete();\n            }\n\n            for (File jarFile : Files.listFolderFiles(oldMissionsFolder, false, f -> f.getName().endsWith(\".jar\"))) {\n                jarFile.renameTo(new File(getModuleFolder(), jarFile.getName()));\n            }\n\n            File oldDataFile = new File(oldMissionsFolder, \"_data.yml\");\n            if (oldDataFile.exists())\n                oldDataFile.renameTo(new File(getModuleFolder(), \"_data.yml\"));\n\n            Files.deleteDirectory(oldMissionsFolder);\n        }\n\n        return updatedConfig;\n    }\n\n    private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) {\n        File oldMissionsMenuFile = new File(plugin.getDataFolder(), \"menus/island-missions.yml\");\n        File newMissionsCategoryMenuFile = new File(plugin.getDataFolder(), \"menus/missions-category.yml\");\n\n        try {\n            java.nio.file.Files.copy(Paths.get(oldMissionsMenuFile.toURI()), Paths.get(newMissionsCategoryMenuFile.toURI()));\n        } catch (IOException error) {\n            logger().e(\"An unexpected error occurred while copying old missions-menu to the new format:\", error);\n            return;\n        }\n\n        YamlConfiguration newMissionsCategoryMenuConfig = YamlConfiguration.loadConfiguration(newMissionsCategoryMenuFile);\n        newMissionsCategoryMenuConfig.set(\"title\", \"&l{0} Missions\");\n\n        try {\n            newMissionsCategoryMenuConfig.save(newMissionsCategoryMenuFile);\n        } catch (IOException ignored) {\n        }\n    }\n\n    private void generateDefaultFiles() {\n        File categoriesFolder = new File(getModuleFolder(), \"categories\");\n\n        if ((!categoriesFolder.exists() || !categoriesFolder.isDirectory()) && categoriesFolder.mkdirs()) {\n            Resources.saveResource(\"modules/missions/categories/farmer/farmer_1.yml\");\n            Resources.saveResource(\"modules/missions/categories/farmer/farmer_2.yml\");\n            Resources.saveResource(\"modules/missions/categories/farmer/farmer_3.yml\");\n            Resources.saveResource(\"modules/missions/categories/farmer/farmer_4.yml\");\n            Resources.saveResource(\"modules/missions/categories/farmer/farmer_5.yml\");\n            Resources.saveResource(\"modules/missions/categories/miner/miner_1.yml\");\n            Resources.saveResource(\"modules/missions/categories/miner/miner_2.yml\");\n            Resources.saveResource(\"modules/missions/categories/miner/miner_3.yml\");\n            Resources.saveResource(\"modules/missions/categories/miner/miner_4.yml\");\n            Resources.saveResource(\"modules/missions/categories/miner/miner_5.yml\");\n            Resources.saveResource(\"modules/missions/categories/slayer/slayer_1.yml\");\n            Resources.saveResource(\"modules/missions/categories/slayer/slayer_2.yml\");\n            Resources.saveResource(\"modules/missions/categories/slayer/slayer_3.yml\");\n            Resources.saveResource(\"modules/missions/categories/slayer/slayer_4.yml\");\n            Resources.saveResource(\"modules/missions/categories/fisherman/fisherman_1.yml\");\n            Resources.saveResource(\"modules/missions/categories/fisherman/fisherman_2.yml\");\n            Resources.saveResource(\"modules/missions/categories/fisherman/fisherman_3.yml\");\n            Resources.saveResource(\"modules/missions/categories/explorer/explorer_1.yml\");\n            Resources.saveResource(\"modules/missions/categories/explorer/explorer_2.yml\");\n        }\n    }\n\n    private void generateDefaultMissionJars() {\n        Resources.copyResource(\"modules/missions/BlocksMissions\");\n        Resources.copyResource(\"modules/missions/BrewingMissions\");\n        Resources.copyResource(\"modules/missions/CraftingMissions\");\n        Resources.copyResource(\"modules/missions/EnchantingMissions\");\n        Resources.copyResource(\"modules/missions/FarmingMissions\");\n        Resources.copyResource(\"modules/missions/FishingMissions\");\n        Resources.copyResource(\"modules/missions/IslandMissions\");\n        Resources.copyResource(\"modules/missions/ItemsMissions\");\n        Resources.copyResource(\"modules/missions/KillsMissions\");\n        Resources.copyResource(\"modules/missions/StatisticsMissions\");\n    }\n\n    private static class MissionsComparator implements Comparator<Mission<?>> {\n\n        private final Map<Mission<?>, Integer> missionWeights;\n\n        public MissionsComparator(Map<Mission<?>, Integer> missionWeights) {\n            this.missionWeights = missionWeights;\n        }\n\n        @Override\n        public int compare(Mission<?> o1, Mission<?> o2) {\n            int firstWeight = this.missionWeights.getOrDefault(o1, 0);\n            int secondWeight = this.missionWeights.getOrDefault(o2, 0);\n            return firstWeight == secondWeight ? o1.getName().compareTo(o2.getName()) : Integer.compare(firstWeight, secondWeight);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java",
    "content": "package com.bgsoftware.superiorskyblock.module.missions.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class CmdAdminMission implements IAdminPlayerCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"mission\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.mission\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin mission <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"> <complete/reset> <\" +\n                Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_MISSIONS.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_MISSION.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultiplePlayers() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        List<Mission<?>> missions = CommandArguments.getMultipleMissions(plugin, sender, args[4]);\n\n        if (missions.isEmpty())\n            return;\n\n        if (args[3].equalsIgnoreCase(\"complete\")) {\n            missions.forEach(mission -> plugin.getMissions().rewardMission(mission, targetPlayer, false, true));\n            if (missions.size() == 1)\n                Message.MISSION_STATUS_COMPLETE.send(sender, missions.get(0).getName(), targetPlayer.getName());\n            else\n                Message.MISSION_STATUS_COMPLETE_ALL.send(sender, targetPlayer.getName());\n            return;\n        } else if (args[3].equalsIgnoreCase(\"reset\")) {\n            Island island = targetPlayer.getIsland();\n\n            int islandsChangedCount = 0;\n\n            for (Mission<?> mission : missions) {\n                IMissionsHolder missionsHolder = mission.getIslandMission() ? island : targetPlayer;\n                if (missionsHolder != null && PluginEventsFactory.callMissionResetEvent(sender, missionsHolder, mission)) {\n                    ++islandsChangedCount;\n                    missionsHolder.resetMission(mission);\n                }\n            }\n\n            if (islandsChangedCount <= 0)\n                return;\n\n            if (missions.size() == 1)\n                Message.MISSION_STATUS_RESET.send(sender, missions.get(0).getName(), targetPlayer.getName());\n            else\n                Message.MISSION_STATUS_RESET_ALL.send(sender, targetPlayer.getName());\n            return;\n        }\n\n        Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(PlayerLocales.getLocale(sender)));\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) {\n        if (args.length == 4) {\n            return CommandTabCompletes.getCustomComplete(args[3], \"complete\", \"reset\");\n        } else if (args.length == 5) {\n            List<String> list = new LinkedList<>();\n\n            if (args[3].equalsIgnoreCase(\"complete\"))\n                list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission ->\n                        plugin.getMissions().canCompleteAgain(targetPlayer, mission)));\n            else if (args[3].equalsIgnoreCase(\"reset\"))\n                list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission ->\n                        !plugin.getMissions().canCompleteAgain(targetPlayer, mission)));\n\n            if (\"*\".contains(args[4]) && !list.isEmpty())\n                list.add(\"*\");\n\n            return Collections.unmodifiableList(list);\n        }\n\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java",
    "content": "package com.bgsoftware.superiorskyblock.module.missions.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\npublic class CmdMission implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"mission\", \"challenge\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.mission\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"mission complete <\" + Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_MISSION.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (!args[1].equalsIgnoreCase(\"complete\")) {\n            Locale locale = PlayerLocales.getLocale(sender);\n            Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + \" \" + getUsage(locale));\n            return;\n        }\n\n        Mission<?> mission = CommandArguments.getMission(plugin, superiorPlayer, args[2]);\n\n        if (mission == null)\n            return;\n\n        List<String> requiredMissions = mission.getRequiredMissions();\n\n        if (!requiredMissions.isEmpty()) {\n            StringBuilder stringBuilder = new StringBuilder();\n            requiredMissions.forEach(requiredMission -> {\n                Mission<?> _mission = plugin.getMissions().getMission(requiredMission);\n                if (_mission != null && plugin.getMissions().canCompleteAgain(superiorPlayer, _mission))\n                    stringBuilder.append(_mission.getName()).append(\", \");\n            });\n            if (stringBuilder.length() != 0) {\n                Message.MISSION_NOT_COMPLETE_REQUIRED_MISSIONS.send(superiorPlayer, stringBuilder.substring(0, stringBuilder.length() - 2));\n                return;\n            }\n        }\n\n        if (!plugin.getMissions().canComplete(superiorPlayer, mission)) {\n            Message.MISSION_CANNOT_COMPLETE.send(superiorPlayer);\n            return;\n        }\n\n        try {\n            plugin.getMissions().rewardMission(mission, superiorPlayer, false);\n        } catch (IllegalStateException ex) {\n            Message.INVALID_MISSION.send(superiorPlayer, args[2]);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], \"complete\") :\n                args.length == 3 && args[1].equalsIgnoreCase(\"complete\") ?\n                        CommandTabCompletes.getMissions(plugin, args[2], mission ->\n                                mission.canComplete(superiorPlayer)) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java",
    "content": "package com.bgsoftware.superiorskyblock.module.missions.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.missions.MissionCategory;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdMissions implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"missions\", \"challenges\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.missions\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"missions [\" + Message.COMMAND_ARGUMENT_MISSION_CATEGORY.getMessage(locale) + \"]\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_MISSIONS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender);\n\n        if (args.length == 1) {\n            if (!superiorPlayer.hasIsland() && !plugin.getMissions().hasAnyPlayerMissionCategories()) {\n                Message.INVALID_ISLAND.send(superiorPlayer);\n                return;\n            }\n\n            plugin.getMenus().openMissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()));\n        } else {\n            MissionCategory missionCategory = CommandArguments.getMissionCategory(plugin, sender, args[1]);\n\n            if (missionCategory == null)\n                return;\n\n            if (!superiorPlayer.hasIsland() && !plugin.getMissions().isPlayerMissionCategory(missionCategory)) {\n                Message.INVALID_ISLAND.send(superiorPlayer);\n                return;\n            }\n\n            plugin.getMenus().openMissionsCategory(superiorPlayer,\n                    MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), missionCategory);\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        if (args.length == 2) {\n            boolean hasIsland = plugin.getPlayers().getSuperiorPlayer(sender).hasIsland();\n            return CommandTabCompletes.getMissionCategories(plugin, args[1], category ->\n                    hasIsland || plugin.getMissions().isPlayerMissionCategory(category));\n        }\n\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.config.CommentedConfiguration;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.value.Value;\nimport com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgrade;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel;\nimport com.bgsoftware.superiorskyblock.island.upgrade.UpgradeRequirement;\nimport com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModule;\nimport com.bgsoftware.superiorskyblock.module.IModuleConfiguration;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRankup;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetUpgrade;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSyncUpgrades;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdRankup;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdUpgrade;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.IUpgradeType;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeBlockLimits;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeMobDrops;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates;\nimport org.bukkit.configuration.ConfigurationSection;\nimport org.bukkit.event.Listener;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.io.File;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.OptionalDouble;\nimport java.util.OptionalInt;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\npublic class UpgradesModule extends BuiltinModule<UpgradesModule.Configuration> {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final String[] IGNORED_SECTIONS = new String[]{\"upgrades\"};\n    private static final int MAX_UPGRADES_NAME_LENGTH = 255;\n\n    private final Map<Class<?>, IUpgradeType> classToUpgrade = new IdentityHashMap<>();\n\n    public UpgradesModule() {\n        super(\"upgrades\");\n    }\n\n    @Override\n    protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) {\n        File oldUpgradesFile = new File(plugin.getDataFolder(), \"upgrades.yml\");\n        boolean updatedConfig = false;\n\n        if (oldUpgradesFile.exists()) {\n            CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldUpgradesFile);\n\n            if (oldConfig.isConfigurationSection(\"upgrades\"))\n                config.set(\"upgrades\", oldConfig.getConfigurationSection(\"upgrades\"));\n\n            oldUpgradesFile.delete();\n        }\n\n        if (!config.isBoolean(\"enabled\")) {\n            boolean status = false;\n\n            if (config.getBoolean(\"crop-growth\", true))\n                status = true;\n            else if (config.getBoolean(\"mob-drops\", true))\n                status = true;\n            else if (config.getBoolean(\"island-effects\", true))\n                status = true;\n            else if (config.getBoolean(\"spawner-rates\", true))\n                status = true;\n            else if (config.getBoolean(\"block-limits\", true))\n                status = true;\n            else if (config.getBoolean(\"entity-limits\", true))\n                status = true;\n\n            config.set(\"enabled\", status);\n            updatedConfig = true;\n        }\n\n        return updatedConfig;\n    }\n\n    @Override\n    public void onEnable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void onDisable(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public void loadData(SuperiorSkyblockPlugin plugin) {\n        // Do nothing.\n    }\n\n    @Override\n    public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) {\n        List<Listener> listenersList = new ArrayList<>();\n\n        for (IUpgradeType upgradeType : this.configuration.enabledUpgrades) {\n            listenersList.addAll(upgradeType.getListeners());\n        }\n\n        return listenersList.toArray(new Listener[0]);\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) {\n        return new SuperiorCommand[]{new CmdRankup(), new CmdUpgrade()};\n    }\n\n    @Override\n    public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) {\n        List<SuperiorCommand> adminCommands = this.configuration.enabledUpgrades.stream()\n                .map(IUpgradeType::getCommands)\n                .flatMap(List::stream)\n                .collect(Collectors.toList());\n\n        adminCommands.add(new CmdAdminRankup());\n        adminCommands.add(new CmdAdminSetUpgrade());\n        adminCommands.add(new CmdAdminSyncUpgrades());\n\n        return adminCommands.toArray(new SuperiorCommand[0]);\n    }\n\n    @Override\n    protected String[] getIgnoredSections() {\n        return IGNORED_SECTIONS;\n    }\n\n    @Override\n    protected Configuration createConfigFile(CommentedConfiguration config) {\n        this.classToUpgrade.clear();\n        Configuration configuration = new Configuration(config);\n        for (IUpgradeType enabledUpgrade : configuration.enabledUpgrades) {\n            this.classToUpgrade.put(enabledUpgrade.getClass(), enabledUpgrade);\n        }\n        return configuration;\n    }\n\n    @Nullable\n    public <T extends IUpgradeType> T getEnabledUpgradeType(Class<T> clazz) {\n        IUpgradeType enabledUpgrade = this.classToUpgrade.get(clazz);\n        return enabledUpgrade == null ? null : (T) enabledUpgrade;\n    }\n\n    public boolean isUpgradeTypeEnabled(Class<? extends IUpgradeType> clazz) {\n        return getEnabledUpgradeType(clazz) != null;\n    }\n\n    public class Configuration implements IModuleConfiguration {\n\n        private final boolean enabled;\n        private final List<IUpgradeType> enabledUpgrades = new LinkedList<>();\n\n        Configuration(CommentedConfiguration config) {\n            this.enabled = config.getBoolean(\"enabled\", true);\n            loadUpgrades(config);\n        }\n\n        @Override\n        public boolean isEnabled() {\n            return this.enabled;\n        }\n\n        private void loadUpgrades(CommentedConfiguration config) {\n            plugin.getUpgrades().clearUpgrades();\n\n            if (!enabled) return;\n\n            if (config.getBoolean(\"crop-growth\", true))\n                enabledUpgrades.add(new UpgradeTypeCropGrowth(plugin));\n            if (config.getBoolean(\"mob-drops\", true))\n                enabledUpgrades.add(new UpgradeTypeMobDrops(plugin));\n            if (config.getBoolean(\"island-effects\", true))\n                enabledUpgrades.add(new UpgradeTypeIslandEffects(plugin));\n            if (config.getBoolean(\"spawner-rates\", true))\n                enabledUpgrades.add(new UpgradeTypeSpawnerRates(plugin));\n            if (config.getBoolean(\"block-limits\", true))\n                enabledUpgrades.add(new UpgradeTypeBlockLimits(plugin));\n            if (config.getBoolean(\"entity-limits\", true))\n                enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin));\n\n            ConfigurationSection upgrades = config.getConfigurationSection(\"upgrades\");\n            if (upgrades != null) {\n                for (String upgradeName : upgrades.getKeys(false)) {\n                    if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH)\n                        upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH);\n\n                    SUpgrade upgrade = new SUpgrade(upgradeName);\n                    for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) {\n                        loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + \".\" + _level));\n                    }\n\n                    plugin.getUpgrades().addUpgrade(upgrade);\n                }\n            }\n\n            IslandUpgrades.onUpgradesUpdate();\n        }\n\n    }\n\n    private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade upgrade,\n                                             String sectionName, ConfigurationSection levelSection) {\n        int level = Integer.parseInt(sectionName);\n\n        String priceType = levelSection.getString(\"price-type\", \"money\");\n        UpgradeCostLoader costLoader = plugin.getUpgrades().getUpgradeCostLoader(priceType);\n\n        if (costLoader == null) {\n            this.logger().w(\"Upgrade by name \" + upgrade.getName() + \" (level \" + level + \") has invalid price-type. Skipping...\");\n            return;\n        }\n\n        UpgradeCost upgradeCost;\n\n        try {\n            upgradeCost = costLoader.loadCost(levelSection);\n        } catch (UpgradeCostLoadException error) {\n            this.logger().e(\"Upgrade by name \" + upgrade.getName() + \" (level \" + level + \") failed to initialize:\", error);\n            return;\n        }\n\n        List<String> commands = levelSection.getStringList(\"commands\");\n        String permission = levelSection.getString(\"permission\", \"\");\n        Set<UpgradeRequirement> requirements = new HashSet<>();\n        for (String line : levelSection.getStringList(\"required-checks\")) {\n            String[] sections = line.split(\";\");\n            requirements.add(new UpgradeRequirement(sections[0], Formatters.COLOR_FORMATTER.format(sections[1])));\n        }\n\n        Value<OptionalDouble> cropGrowth = Value.syncedFixed(readDouble(levelSection, \"crop-growth\"));\n        Value<OptionalDouble> spawnerRates = Value.syncedFixed(readDouble(levelSection, \"spawner-rates\"));\n        Value<OptionalDouble> mobDrops = Value.syncedFixed(readDouble(levelSection, \"mob-drops\"));\n        Value<OptionalInt> teamLimit = Value.syncedFixed(readInt(levelSection, \"team-limit\"));\n        Value<OptionalInt> warpsLimit = Value.syncedFixed(readInt(levelSection, \"warps-limit\"));\n        Value<OptionalInt> coopLimit = Value.syncedFixed(readInt(levelSection, \"coop-limit\"));\n        Value<OptionalInt> borderSize = Value.syncedFixed(readInt(levelSection, \"border-size\"));\n\n        if (borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE) > plugin.getSettings().getMaxIslandSize()) {\n            this.logger().w(\"Upgrade by name \" + upgrade.getName() + \" (level \" + level + \") has illegal border-size, skipping...\");\n            return;\n        }\n\n        Value<Optional<BigDecimal>> bankLimit = Value.syncedFixed(readString(levelSection, \"bank-limit\").map(BigDecimal::new));\n        KeyMap<Integer> blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n        if (levelSection.isConfigurationSection(\"block-limits\")) {\n            for (String block : levelSection.getConfigurationSection(\"block-limits\").getKeys(false)) {\n                Key blockKey = Keys.ofMaterialAndData(block);\n                blockLimits.put(blockKey, levelSection.getInt(\"block-limits.\" + block));\n                plugin.getBlockValues().addCustomBlockKey(blockKey);\n            }\n        }\n        KeyMap<Integer> entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE);\n        if (levelSection.isConfigurationSection(\"entity-limits\")) {\n            for (String entity : levelSection.getConfigurationSection(\"entity-limits\").getKeys(false))\n                entityLimits.put(Keys.ofEntityType(entity), levelSection.getInt(\"entity-limits.\" + entity));\n        }\n        EnumerateMap<Dimension, Map<Key, Integer>> generatorRates = new EnumerateMap<>(Dimension.values());\n        if (levelSection.isConfigurationSection(\"generator-rates\")) {\n            for (String blockOrEnv : levelSection.getConfigurationSection(\"generator-rates\").getKeys(false)) {\n                try {\n                    Dimension dimension = Dimension.getByName(blockOrEnv.toUpperCase(Locale.ENGLISH));\n                    for (String block : levelSection.getConfigurationSection(\"generator-rates.\" + blockOrEnv).getKeys(false)) {\n                        generatorRates.computeIfAbsent(dimension, e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL)).put(\n                                Keys.ofMaterialAndData(block), levelSection.getInt(\"generator-rates.\" + blockOrEnv + \".\" + block));\n                    }\n                } catch (Exception ex) {\n                    generatorRates.computeIfAbsent(plugin.getSettings().getWorlds().getDefaultWorldDimension(), e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL))\n                            .put(Keys.ofMaterialAndData(blockOrEnv), levelSection.getInt(\"generator-rates.\" + blockOrEnv));\n                }\n            }\n        }\n        Map<PotionEffectType, Integer> islandEffects = new ArrayMap<>();\n        if (levelSection.isConfigurationSection(\"island-effects\")) {\n            for (String effect : levelSection.getConfigurationSection(\"island-effects\").getKeys(false)) {\n                PotionEffectType potionEffectType = PotionEffectType.getByName(effect);\n                if (potionEffectType != null)\n                    islandEffects.put(potionEffectType, levelSection.getInt(\"island-effects.\" + effect) - 1);\n            }\n        }\n        Int2IntMapView rolesLimits = CollectionsFactory.createInt2IntArrayMap();\n        if (levelSection.isConfigurationSection(\"role-limits\")) {\n            for (String roleId : levelSection.getConfigurationSection(\"role-limits\").getKeys(false)) {\n                try {\n                    rolesLimits.put(Integer.parseInt(roleId), levelSection.getInt(\"role-limits.\" + roleId));\n                } catch (NumberFormatException ignored) {\n                }\n            }\n        }\n\n        SUpgradeLevel upgradeLevel = new SUpgradeLevel(level, upgradeCost, commands, permission, requirements,\n                cropGrowth, spawnerRates, mobDrops, teamLimit, warpsLimit, coopLimit, borderSize,\n                Value.syncedFixed(blockLimits), Value.syncedFixed(entityLimits), Value.syncedFixed(generatorRates),\n                Value.syncedFixed(islandEffects), bankLimit, Value.syncedFixed(rolesLimits));\n\n        upgrade.addUpgradeLevel(level, upgradeLevel);\n    }\n\n    private static OptionalDouble readDouble(ConfigurationSection section, String key) {\n        if (section.contains(key))\n            return OptionalDouble.of(section.getDouble(key));\n\n        return OptionalDouble.empty();\n    }\n\n    private static OptionalInt readInt(ConfigurationSection section, String key) {\n        if (section.contains(key))\n            return OptionalInt.of(section.getInt(key));\n\n        return OptionalInt.empty();\n    }\n\n    private static Optional<String> readString(ConfigurationSection section, String key) {\n        if (section.contains(key))\n            return Optional.of(section.getString(key));\n\n        return Optional.empty();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddBlockLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddBlockLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addblocklimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addblocklimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addblocklimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key key = Keys.ofMaterialAndData(args[3]);\n\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBlockLimit> event =\n                    PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, island.getBlockLimit(key) + limit);\n            if (!event.isCancelled()) {\n                island.setBlockLimit(key, event.getArgs().blockLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddCropGrowth implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addcropgrowth\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addcropgrowth\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addcropgrowth <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeCropGrowth> event = PluginEventsFactory.callIslandChangeCropGrowthEvent(\n                    island, sender, island.getCropGrowthMultiplier() + multiplier);\n            if (!event.isCancelled()) {\n                island.setCropGrowthMultiplier(event.getArgs().cropGrowth);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_CROP_GROWTH_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_CROP_GROWTH.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddEffect implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addeffect\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addeffect\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addeffect <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_EFFECT.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        PotionEffectType effectType = CommandArguments.getPotionEffect(sender, args[3]);\n\n        if (effectType == null)\n            return;\n\n        NumberArgument<Integer> arguments = CommandArguments.getLevel(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int level = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            int newLevel = island.getPotionEffectLevel(effectType) + level;\n            if (newLevel <= 0) {\n                if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) {\n                    ++islandsChangedCount;\n                    island.removePotionEffect(effectType);\n                }\n            } else {\n                PluginEvent<PluginEventArgs.IslandChangeEffectLevel> event = PluginEventsFactory.callIslandChangeEffectLevelEvent(\n                        island, sender, effectType, newLevel);\n                if (!event.isCancelled()) {\n                    island.setPotionEffect(effectType, event.getArgs().effectLevel);\n                    ++islandsChangedCount;\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()));\n        else if (targetPlayer == null)\n            Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName());\n        else\n            Message.CHANGED_ISLAND_EFFECT_LEVEL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getPotionEffects(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEntityLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddEntityLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addentitylimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addentitylimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addentitylimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key entityKey = Keys.ofEntityType(args[3]);\n\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeEntityLimit> event = PluginEventsFactory.callIslandChangeEntityLimitEvent(\n                    island, sender, entityKey, island.getEntityLimit(entityKey) + limit);\n            if (!event.isCancelled()) {\n                island.setEntityLimit(entityKey, event.getArgs().entityLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddMobDrops implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addmobdrops\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addmobdrops\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addmobdrops <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeMobDrops> event = PluginEventsFactory.callIslandChangeMobDropsEvent(\n                    island, sender, island.getMobDropsMultiplier() + multiplier);\n            if (!event.isCancelled()) {\n                island.setMobDropsMultiplier(event.getArgs().mobDrops);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_MOB_DROPS_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_MOB_DROPS.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminAddSpawnerRates implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"addspawnerrates\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.addspawnerrates\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin addspawnerrates <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeSpawnerRates> event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent(\n                    island, sender, island.getSpawnerRatesMultiplier() + multiplier);\n            if (!event.isCancelled()) {\n                island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_SPAWNER_RATES_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_SPAWNER_RATES.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminRankup implements IAdminIslandCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"rankup\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.rankup\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin rankup <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_RANKUP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Upgrade upgrade = CommandArguments.getUpgrade(plugin, sender, args[3]);\n\n        if (upgrade == null)\n            return;\n\n        SuperiorPlayer playerSender = sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null;\n\n        islands.forEach(island -> {\n            UpgradeLevel currentLevel = island.getUpgradeLevel(upgrade);\n            UpgradeLevel nextLevel = upgrade.getUpgradeLevel(currentLevel.getLevel() + 1);\n\n            PluginEvent<PluginEventArgs.IslandUpgrade> event = PluginEventsFactory.callIslandUpgradeEvent(\n                    island, playerSender, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP);\n\n            if (!event.isCancelled()) {\n                SuperiorPlayer owner = island.getOwner();\n\n                for (String command : event.getArgs().commands) {\n                    Bukkit.dispatchCommand(Bukkit.getConsoleSender(),\n                            placeholdersService.get().parsePlaceholders(owner.asOfflinePlayer(), command\n                                    .replace(\"%player%\", owner.getName())\n                                    .replace(\"%leader%\", owner.getName()))\n                    );\n                }\n            }\n        });\n\n        if (islands.size() > 1)\n            Message.RANKUP_SUCCESS_ALL.send(sender, upgrade.getName());\n        else if (targetPlayer == null)\n            Message.RANKUP_SUCCESS_NAME.send(sender, upgrade.getName(), islands.get(0).getName());\n        else\n            Message.RANKUP_SUCCESS.send(sender, upgrade.getName(), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getUpgrades(plugin, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveBlockLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminRemoveBlockLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"removeblocklimit\", \"remblocklimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.removeblocklimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin removeblocklimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key key = Keys.ofMaterialAndData(args[3]);\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (PluginEventsFactory.callIslandRemoveBlockLimitEvent(island, sender, key)) {\n                ++islandsChangedCount;\n                island.removeBlockLimit(key);\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveEntityLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminRemoveEntityLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"removeentitylimit\", \"rementitylimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.removeentitylimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin removeentitylimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key key = Keys.ofEntityType(args[3]);\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (PluginEventsFactory.callIslandRemoveEntityLimitEvent(island, sender, key)) {\n                ++islandsChangedCount;\n                island.removeEntityLimit(key);\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetBlockLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetBlockLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setblocklimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setblocklimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setblocklimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key key = Keys.ofMaterialAndData(args[3]);\n\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeBlockLimit> event = PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, limit);\n            if (!event.isCancelled()) {\n                island.setBlockLimit(key, event.getArgs().blockLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetCropGrowth implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setcropgrowth\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setcropgrowth\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setcropgrowth <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeCropGrowth> event = PluginEventsFactory.callIslandChangeCropGrowthEvent(\n                    island, sender, multiplier);\n            if (!event.isCancelled()) {\n                island.setCropGrowthMultiplier(event.getArgs().cropGrowth);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_CROP_GROWTH_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_CROP_GROWTH.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetEffect implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"seteffect\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.seteffect\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin seteffect <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_EFFECT.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_EFFECT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        PotionEffectType effectType = CommandArguments.getPotionEffect(sender, args[3]);\n\n        if (effectType == null)\n            return;\n\n        NumberArgument<Integer> arguments = CommandArguments.getLevel(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int level = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            if (level <= 0) {\n                if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) {\n                    ++islandsChangedCount;\n                    island.removePotionEffect(effectType);\n                }\n            } else {\n                PluginEvent<PluginEventArgs.IslandChangeEffectLevel> event = PluginEventsFactory.callIslandChangeEffectLevelEvent(\n                        island, sender, effectType, level);\n                if (!event.isCancelled()) {\n                    island.setPotionEffect(effectType, event.getArgs().effectLevel);\n                    ++islandsChangedCount;\n                }\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()));\n        else if (targetPlayer == null)\n            Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName());\n        else\n            Message.CHANGED_ISLAND_EFFECT_LEVEL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getPotionEffects(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEntityLimit.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetEntityLimit implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setentitylimit\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setentitylimit\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setentitylimit <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Key entityKey = Keys.ofEntityType(args[3]);\n\n        NumberArgument<Integer> arguments = CommandArguments.getLimit(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int limit = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeEntityLimit> event = PluginEventsFactory.callIslandChangeEntityLimitEvent(\n                    island, sender, entityKey, limit);\n            if (!event.isCancelled()) {\n                island.setEntityLimit(entityKey, event.getArgs().entityLimit);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()));\n        else if (targetPlayer == null)\n            Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName());\n        else\n            Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetMobDrops implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setmobdrops\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setmobdrops\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setmobdrops <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeMobDrops> event = PluginEventsFactory.callIslandChangeMobDropsEvent(\n                    island, sender, multiplier);\n            if (!event.isCancelled()) {\n                island.setMobDropsMultiplier(event.getArgs().mobDrops);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_MOB_DROPS_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_MOB_DROPS.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetSpawnerRates implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setspawnerrates\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setspawnerrates\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setspawnerrates <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 4;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 4;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        NumberArgument<Double> arguments = CommandArguments.getMultiplier(sender, args[3]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        double multiplier = arguments.getNumber();\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandChangeSpawnerRates> event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent(\n                    island, sender, multiplier);\n            if (!event.isCancelled()) {\n                island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.CHANGED_SPAWNER_RATES_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.CHANGED_SPAWNER_RATES.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSetUpgrade implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"setupgrade\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.setupgrade\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin setupgrade <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + \"> <\" +\n                Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 5;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 5;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        Upgrade upgrade = CommandArguments.getUpgrade(plugin, sender, args[3]);\n\n        if (upgrade == null)\n            return;\n\n        NumberArgument<Integer> arguments = CommandArguments.getLevel(sender, args[4]);\n\n        if (!arguments.isSucceed())\n            return;\n\n        int level = arguments.getNumber();\n        int maxLevel = upgrade.getMaxUpgradeLevel();\n\n        if (level > maxLevel) {\n            Message.MAXIMUM_LEVEL.send(sender, maxLevel);\n            return;\n        }\n\n        int islandsChangedCount = 0;\n\n        for (Island island : islands) {\n            PluginEvent<PluginEventArgs.IslandUpgrade> event = PluginEventsFactory.callIslandUpgradeEvent(\n                    island, sender, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE);\n            if (!event.isCancelled()) {\n                island.setUpgradeLevel(upgrade, level);\n                ++islandsChangedCount;\n            }\n        }\n\n        if (islandsChangedCount <= 0)\n            return;\n\n        if (islandsChangedCount > 1)\n            Message.SET_UPGRADE_LEVEL_ALL.send(sender, upgrade.getName());\n        else if (targetPlayer == null)\n            Message.SET_UPGRADE_LEVEL_NAME.send(sender, upgrade.getName(), islands.get(0).getName());\n        else\n            Message.SET_UPGRADE_LEVEL.send(sender, upgrade.getName(), targetPlayer.getName());\n    }\n\n    @Override\n    public List<String> adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) {\n        return args.length == 4 ? CommandTabCompletes.getUpgrades(plugin, args[3]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSyncUpgrades.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdAdminSyncUpgrades implements IAdminIslandCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"syncupgrades\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.admin.syncupgrades\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"admin syncupgrades <\" +\n                Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + \"/\" +\n                Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + \">\";\n\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 3;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 3;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return true;\n    }\n\n    @Override\n    public boolean supportMultipleIslands() {\n        return true;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List<Island> islands, String[] args) {\n        islands.forEach(Island::syncUpgrades);\n\n        if (islands.size() > 1)\n            Message.SYNC_UPGRADES_ALL.send(sender);\n        else if (targetPlayer == null)\n            Message.SYNC_UPGRADES_NAME.send(sender, islands.get(0).getName());\n        else\n            Message.SYNC_UPGRADES.send(sender, targetPlayer.getName());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.modules.ModuleLogger;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel;\nimport com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost;\nimport com.bgsoftware.superiorskyblock.api.world.GameSound;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandTabCompletes;\nimport com.bgsoftware.superiorskyblock.commands.IPermissibleCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport org.bukkit.Bukkit;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdRankup implements IPermissibleCommand {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final LazyReference<PlaceholdersService> placeholdersService = new LazyReference<PlaceholdersService>() {\n        @Override\n        protected PlaceholdersService create() {\n            return plugin.getServices().getService(PlaceholdersService.class);\n        }\n    };\n\n    @Override\n    public List<String> getAliases() {\n        return Collections.singletonList(\"rankup\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.rankup\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"rankup <\" + Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + \">\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_RANKUP.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 2;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 2;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public IslandPrivilege getPrivilege() {\n        return IslandPrivileges.RANKUP;\n    }\n\n    @Override\n    public Message getPermissionLackMessage() {\n        return Message.NO_RANKUP_PERMISSION;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        Upgrade upgrade = CommandArguments.getUpgrade(plugin, superiorPlayer, args[1]);\n\n        if (upgrade == null)\n            return;\n\n        UpgradeLevel currentLevel = island.getUpgradeLevel(upgrade);\n        UpgradeLevel nextLevel = upgrade.getUpgradeLevel(currentLevel.getLevel() + 1);\n\n        String permission = nextLevel == null ? \"\" : nextLevel.getPermission();\n\n        if (!permission.isEmpty() && !superiorPlayer.hasPermission(permission)) {\n            Message.NO_UPGRADE_PERMISSION.send(superiorPlayer);\n            return;\n        }\n\n        boolean hasNextLevel;\n\n        if (island.hasActiveUpgradeCooldown()) {\n            long timeNow = System.currentTimeMillis();\n            long lastUpgradeTime = island.getLastTimeUpgrade();\n            long duration = lastUpgradeTime + plugin.getSettings().getUpgradeCooldown() - timeNow;\n            Message.UPGRADE_COOLDOWN_FORMAT.send(superiorPlayer, Formatters.TIME_FORMATTER.format(\n                    Duration.ofMillis(duration), superiorPlayer.getUserLocale()));\n            hasNextLevel = false;\n        } else {\n            String requiredCheckFailure = nextLevel == null ? \"\" : nextLevel.checkRequirements(superiorPlayer);\n\n            if (!requiredCheckFailure.isEmpty()) {\n                Message.CUSTOM.send(superiorPlayer, requiredCheckFailure, false);\n                hasNextLevel = false;\n            } else {\n                PluginEvent<PluginEventArgs.IslandUpgrade> event = PluginEventsFactory.callIslandUpgradeEvent(\n                        island, superiorPlayer, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP);\n\n                UpgradeCost upgradeCost = event.getArgs().upgradeCost;\n\n                if (event.isCancelled()) {\n                    hasNextLevel = false;\n\n                } else if (!upgradeCost.hasEnoughBalance(superiorPlayer)) {\n                    Message.NOT_ENOUGH_MONEY_TO_UPGRADE.send(superiorPlayer);\n                    hasNextLevel = false;\n\n                } else {\n                    upgradeCost.withdrawCost(superiorPlayer);\n\n                    for (String command : event.getArgs().commands) {\n                        String parsedCommand = placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), command\n                                .replace(\"%player%\", superiorPlayer.getName())\n                                .replace(\"%leader%\", island.getOwner().getName()));\n\n                        try {\n                            Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsedCommand);\n                        } catch (Throwable error) {\n                            ModuleLogger logger = (ModuleLogger) BuiltinModules.UPGRADES.getLogger();\n                            logger.e(\"An unexpected error occurred while executing command:\\n\" + parsedCommand, error);\n                        }\n                    }\n\n                    hasNextLevel = true;\n                }\n            }\n        }\n\n        SUpgradeLevel.ItemData itemData = ((SUpgradeLevel) currentLevel).getItemData();\n        if (itemData != null) {\n            GameSound sound = hasNextLevel ? itemData.hasNextLevelSound : itemData.noNextLevelSound;\n            if (sound != null)\n                superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, sound));\n        }\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) {\n        return args.length == 2 ? CommandTabCompletes.getUpgrades(plugin, args[1]) : Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdUpgrade.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.commands;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments;\nimport com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument;\nimport com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport org.bukkit.command.CommandSender;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class CmdUpgrade implements ISuperiorCommand {\n\n    @Override\n    public List<String> getAliases() {\n        return Arrays.asList(\"upgrade\", \"upgrades\");\n    }\n\n    @Override\n    public String getPermission() {\n        return \"superior.island.upgrade\";\n    }\n\n    @Override\n    public String getUsage(java.util.Locale locale) {\n        return \"upgrade\";\n    }\n\n    @Override\n    public String getDescription(java.util.Locale locale) {\n        return Message.COMMAND_DESCRIPTION_UPGRADE.getMessage(locale);\n    }\n\n    @Override\n    public int getMinArgs() {\n        return 1;\n    }\n\n    @Override\n    public int getMaxArgs() {\n        return 1;\n    }\n\n    @Override\n    public boolean canBeExecutedByConsole() {\n        return false;\n    }\n\n    @Override\n    public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender);\n\n        Island island = arguments.getIsland();\n\n        if (island == null)\n            return;\n\n        SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer();\n        plugin.getMenus().openUpgrades(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island);\n    }\n\n    @Override\n    public List<String> tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/IUpgradeType.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport org.bukkit.event.Listener;\n\nimport java.util.List;\n\npublic interface IUpgradeType {\n\n    List<Listener> getListeners();\n\n    List<ISuperiorCommand> getCommands();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableObject;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddBlockLimit;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveBlockLimit;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetBlockLimit;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.block.BlockDispenseEvent;\nimport org.bukkit.event.block.BlockFormEvent;\nimport org.bukkit.event.block.BlockGrowEvent;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.event.player.PlayerBucketEmptyEvent;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.event.world.StructureGrowEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.material.Directional;\nimport org.bukkit.material.MaterialData;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class UpgradeTypeBlockLimits implements IUpgradeType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public UpgradeTypeBlockLimits(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        return Collections.singletonList(new BlockLimitsListener());\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddBlockLimit(), new CmdAdminRemoveBlockLimit(), new CmdAdminSetBlockLimit());\n    }\n\n    private class BlockLimitsListener implements Listener {\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onBlockPlace(BlockPlaceEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlockPlaced().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.of(e.getBlock());\n\n            if (island.hasReachedBlockLimit(blockKey)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            }\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onPlayerRightClickBlock(PlayerInteractEvent e) {\n            if (e.getAction() != Action.RIGHT_CLICK_BLOCK)\n                return;\n\n            PlayerHand playerHand = BukkitItems.getHand(e);\n            if (playerHand != PlayerHand.MAIN_HAND)\n                return;\n\n            ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand);\n            if (handItem == null)\n                return;\n\n            Material clickedBlockType = e.getClickedBlock().getType();\n\n            if (onCartPlaceInternal(e, clickedBlockType, handItem) ||\n                    onSpawnerChangeInternal(e, clickedBlockType, handItem))\n                e.setCancelled(true);\n        }\n\n        private boolean onCartPlaceInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) {\n            if (!Materials.isRail(clickedBlockType))\n                return false;\n\n            Material handItemType = handItem.getType();\n\n            if (!Materials.isMinecart(handItemType))\n                return false;\n\n            MutableObject<Key> minecraftKey = new MutableObject<>(null);\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (preventMinecartPlace(handItemType, e.getClickedBlock().getLocation(wrapper.getHandle()), minecraftKey)) {\n                    Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(\n                            minecraftKey.getValue().getGlobalKey()));\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private boolean onSpawnerChangeInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) {\n            if (clickedBlockType != Materials.SPAWNER.toBukkitType())\n                return false;\n\n            Material handItemType = handItem.getType();\n            if (!Materials.isSpawnEgg(handItemType))\n                return false;\n\n            Key oldSpawnerKey = Keys.of(e.getClickedBlock());\n            Key newSpawnerKey = Keys.ofSpawner(BukkitItems.getEntityType(e.getItem()));\n\n            if (oldSpawnerKey.equals(newSpawnerKey))\n                return false;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return false;\n\n            try {\n                island.handleBlockBreak(oldSpawnerKey, 1, 0);\n                if (island.hasReachedBlockLimit(newSpawnerKey)) {\n                    Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(newSpawnerKey.toString()));\n                    return true;\n                }\n            } finally {\n                island.handleBlockPlace(oldSpawnerKey, 1, 0);\n            }\n\n            return false;\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        private void onMinecartPlaceByDispenser(BlockDispenseEvent e) {\n            Material dispenseItemType = e.getItem().getType();\n\n            if (!Materials.isMinecart(dispenseItemType) || e.getBlock().getType() != Material.DISPENSER)\n                return;\n\n            Block targetBlock = null;\n\n            if (ServerVersion.isLegacy()) {\n                MaterialData materialData = e.getBlock().getState().getData();\n                if (materialData instanceof Directional) {\n                    targetBlock = e.getBlock().getRelative(((Directional) materialData).getFacing());\n                }\n            } else {\n                Object blockData = plugin.getNMSWorld().getBlockData(e.getBlock());\n                if (blockData instanceof org.bukkit.block.data.Directional) {\n                    targetBlock = e.getBlock().getRelative(((org.bukkit.block.data.Directional) blockData).getFacing());\n                }\n            }\n\n            if (targetBlock == null)\n                return;\n\n            if (!Materials.isRail(targetBlock.getType()))\n                return;\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                if (preventMinecartPlace(dispenseItemType, targetBlock.getLocation(wrapper.getHandle()), null))\n                    e.setCancelled(true);\n            }\n\n        }\n\n        private boolean preventMinecartPlace(Material minecartType, Location location, @Nullable MutableObject<Key> minecraftKey) {\n            Island island = plugin.getGrid().getIslandAt(location);\n\n            if (island == null)\n                return false;\n\n            Key key = null;\n\n            switch (minecartType.name()) {\n                case \"HOPPER_MINECART\":\n                    key = ConstantKeys.HOPPER;\n                    break;\n                case \"COMMAND_MINECART\":\n                case \"COMMAND_BLOCK_MINECART\":\n                    key = ConstantKeys.COMMAND_BLOCK;\n                    break;\n                case \"EXPLOSIVE_MINECART\":\n                case \"TNT_MINECART\":\n                    key = ConstantKeys.TNT;\n                    break;\n                case \"POWERED_MINECART\":\n                case \"FURNACE_MINECART\":\n                    key = ConstantKeys.FURNACE;\n                    break;\n                case \"STORAGE_MINECART\":\n                case \"CHEST_MINECART\":\n                    key = ConstantKeys.CHEST;\n                    break;\n            }\n\n            if (key != null && island.hasReachedBlockLimit(key)) {\n                if (minecraftKey != null)\n                    minecraftKey.setValue(key);\n                return true;\n            }\n\n            return false;\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onBucketEmpty(PlayerBucketEmptyEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlockClicked().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.ofMaterialAndData(e.getBucket().name().replace(\"_BUCKET\", \"\"));\n\n            if (island.hasReachedBlockLimit(blockKey)) {\n                e.setCancelled(true);\n                Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString()));\n            }\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onBlockGrow(BlockGrowEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.of(e.getNewState());\n\n            if (island.hasReachedBlockLimit(blockKey))\n                e.setCancelled(true);\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onStructureGrow(StructureGrowEvent e) {\n            Island island = plugin.getGrid().getIslandAt(e.getLocation());\n\n            if (island == null)\n                return;\n\n            e.getBlocks().removeIf(blockState -> island.hasReachedBlockLimit(Keys.of(blockState)));\n        }\n\n        @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)\n        public void onBlockForm(BlockFormEvent e) {\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            Key blockKey = Keys.of(e.getNewState());\n\n            if (island.hasReachedBlockLimit(blockKey)) {\n                e.setCancelled(true);\n            }\n        }\n\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddCropGrowth;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetCropGrowth;\nimport org.bukkit.Location;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockGrowEvent;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class UpgradeTypeCropGrowth implements IUpgradeType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public UpgradeTypeCropGrowth(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        return Collections.singletonList(new CropGrowthListener());\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddCropGrowth(), new CmdAdminSetCropGrowth());\n    }\n\n    private class CropGrowthListener implements Listener {\n\n        // Should potentially fix crop growth tile entities \"disappearing\"\n        @EventHandler(priority = EventPriority.LOWEST)\n        public void onBlockGrow(BlockGrowEvent e) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location blockLocation = e.getBlock().getLocation(wrapper.getHandle());\n                Island island = plugin.getGrid().getIslandAt(blockLocation);\n                if (island != null && island.isInsideRange(blockLocation))\n                    plugin.getNMSChunks().startTickingChunk(island, e.getBlock().getChunk(), false);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEntityLimit;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveEntityLimit;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEntityLimit;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.event.entity.EntityBreedEvent;\nimport org.bukkit.event.hanging.HangingPlaceEvent;\nimport org.bukkit.event.player.PlayerInteractAtEntityEvent;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.event.vehicle.VehicleCreateEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.PlayerInventory;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\npublic class UpgradeTypeEntityLimits implements IUpgradeType {\n\n    @Nullable\n    private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, \"GOLDEN_DANDELION\");\n\n    private final Map<EntityType, SpawningPlayerData> entityBreederPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS);\n    private final Map<Location, SpawningPlayerData> vehiclesOwners = AutoRemovalMap.newMap(2, TimeUnit.SECONDS, Location2ObjectMap::new);\n    private final Map<EntityType, SpawningPlayerData> spawnEggPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS);\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public UpgradeTypeEntityLimits(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        List<Listener> listeners = new LinkedList<>();\n\n        listeners.add(new EntityLimitsListener());\n\n        checkEntityBreedListener().ifPresent(listeners::add);\n\n        return listeners;\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddEntityLimit(), new CmdAdminRemoveEntityLimit(), new CmdAdminSetEntityLimit());\n    }\n\n    private Optional<Listener> checkEntityBreedListener() {\n        try {\n            Class.forName(\"org.bukkit.event.entity.EntityBreedEvent\");\n            return Optional.of(new EntityLimitsBreedListener());\n        } catch (ClassNotFoundException error) {\n            return Optional.empty();\n        }\n    }\n\n    private class EntityLimitsListener implements Listener {\n\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onEntitySpawn(CreatureSpawnEvent e) {\n            Entity entity = e.getEntity();\n            EntityType entityType = entity.getType();\n\n            if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType))\n                return;\n\n            Island island = plugin.getGrid().getIslandAt(e.getLocation());\n\n            if (island == null)\n                return;\n\n            SpawningPlayerData spawningPlayerData = getSpawningPlayerFromSpawnEvent(e);\n            Player spawningPlayer = spawningPlayerData == null ? null : spawningPlayerData.player.get();\n\n            boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join();\n\n            if (hasReachedLimit) {\n                e.setCancelled(true);\n                if (spawningPlayer != null && spawningPlayer.isOnline()) {\n                    Message.REACHED_ENTITY_LIMIT.send(spawningPlayer, Formatters.CAPITALIZED_FORMATTER.format(entityType.toString()));\n                    List<ItemStack> itemsToGiveBack = spawningPlayerData.itemStacks;\n                    try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                        Location location = spawningPlayer.getLocation(wrapper.getHandle());\n                        PlayerInventory inventory = spawningPlayer.getInventory();\n                        for (ItemStack itemStack : itemsToGiveBack) {\n                            BukkitItems.addItem(itemStack, inventory, location);\n                        }\n                    }\n                }\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onHangingPlace(HangingPlaceEvent e) {\n            Entity entity = e.getEntity();\n            EntityType entityType = entity.getType();\n\n            if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType))\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join();\n\n            if (hasReachedLimit) {\n                e.setCancelled(true);\n                Message.REACHED_ENTITY_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(entityType.toString()));\n            }\n        }\n\n        @EventHandler\n        public void onVehicleSpawn(PlayerInteractEvent e) {\n            if (e.getAction() != Action.RIGHT_CLICK_BLOCK)\n                return;\n\n            PlayerHand playerHand = BukkitItems.getHand(e);\n            if (playerHand != PlayerHand.MAIN_HAND)\n                return;\n\n            ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand);\n            if (handItem == null)\n                return;\n\n            Material handType = handItem.getType();\n\n            // Check if minecart or boat\n            boolean isMinecart = Materials.isRail(e.getClickedBlock().getType()) && Materials.isMinecart(handType);\n            boolean isBoat = Materials.isBoat(handType);\n            if (!isMinecart && !isBoat)\n                return;\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle());\n                Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n                if (island == null)\n                    return;\n\n                Location futureEntitySpawnLocation = isMinecart ? blockLocation :\n                        blockLocation.add(0, 1, 0);\n\n                vehiclesOwners.put(futureEntitySpawnLocation, new SpawningPlayerData(e.getPlayer()));\n            }\n        }\n\n        @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)\n        public void onVehicleSpawn(VehicleCreateEvent e) {\n            Entity entity = e.getVehicle();\n            EntityType entityType = entity.getType();\n\n            if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType))\n                return;\n\n            Island island;\n            SpawningPlayerData vehicleOwnerData;\n\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location entityLocation = entity.getLocation(wrapper.getHandle());\n                island = plugin.getGrid().getIslandAt(entityLocation);\n\n                if (island == null)\n                    return;\n\n                vehicleOwnerData = vehiclesOwners.remove(entityLocation);\n            }\n\n            Player vehicleOwner = vehicleOwnerData == null ? null : vehicleOwnerData.player.get();\n\n            boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join();\n\n            if (hasReachedLimit) {\n                entity.remove();\n                if (vehicleOwner != null && vehicleOwner.isOnline()) {\n                    Message.REACHED_ENTITY_LIMIT.send(vehicleOwner, Formatters.CAPITALIZED_FORMATTER.format(entityType.toString()));\n                }\n            }\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnEggUse(PlayerInteractEvent e) {\n            if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() == null)\n                return;\n\n            PlayerHand usedHand = BukkitItems.getHand(e);\n            ItemStack usedItem = BukkitItems.getHandItem(e.getPlayer(), usedHand);\n            EntityType spawnEggEntityType = usedItem == null ? EntityType.UNKNOWN :\n                    usedItem.getType() == Material.ARMOR_STAND ? EntityType.ARMOR_STAND :\n                            BukkitItems.getEntityType(usedItem);\n\n            if (spawnEggEntityType == EntityType.UNKNOWN || !BukkitEntities.canHaveLimit(spawnEggEntityType))\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            spawnEggPlayers.put(spawnEggEntityType, new SpawningPlayerData(e.getPlayer()));\n        }\n\n        @Nullable\n        private SpawningPlayerData getSpawningPlayerFromSpawnEvent(CreatureSpawnEvent event) {\n            EntityType entityType = event.getEntityType();\n\n            if (entityType == EntityType.ARMOR_STAND) {\n                return spawnEggPlayers.remove(entityType);\n            }\n\n            switch (event.getSpawnReason()) {\n                case SPAWNER_EGG:\n                    return spawnEggPlayers.remove(entityType);\n                case BREEDING:\n                    return entityBreederPlayers.remove(entityType);\n            }\n\n            return null;\n        }\n\n    }\n\n    private class EntityLimitsBreedListener implements Listener {\n\n        private final Int2ObjectMapView<ItemStack> trackedBreedItems = CollectionsFactory.createInt2ObjectArrayMap();\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onEntityBreed(EntityBreedEvent e) {\n            Entity child = e.getEntity();\n            EntityType childEntityType = child.getType();\n\n            if (!(e.getBreeder() instanceof Player) || !BukkitEntities.canHaveLimit(childEntityType))\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(child.getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            ItemStack fatherBreedItem = trackedBreedItems.remove(e.getFather().getEntityId());\n            ItemStack motherBreedItem = e.getFather().equals(e.getMother()) ? null :\n                    trackedBreedItems.remove(e.getMother().getEntityId());\n\n            entityBreederPlayers.put(childEntityType, new SpawningPlayerData((Player) e.getBreeder(), fatherBreedItem, motherBreedItem));\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onEntityFeed(PlayerInteractAtEntityEvent e) {\n            if (!(e.getRightClicked() instanceof Animals))\n                return;\n\n            PlayerHand usedHand = BukkitItems.getHand(e);\n            ItemStack usedItem = BukkitItems.getHandItem(e.getPlayer(), usedHand);\n\n            if (usedItem == null || (usedItem.getType() != GOLDEN_DANDELION_TYPE &&\n                    !plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) e.getRightClicked())))\n                return;\n\n            // We want to calculate the amount of items consumed by breeding this animal.\n            // We do that by checking the held item one tick later, and subtracting the\n            // amount after 1 tick of the item from the original amount.\n            int mainHandSlot = e.getPlayer().getInventory().getHeldItemSlot();\n            int originalAmount = usedItem.getAmount();\n            ItemStack breedItem = usedItem.clone();\n\n            BukkitExecutor.sync(() -> {\n                ItemStack inventoryItem = usedHand == PlayerHand.MAIN_HAND ?\n                        e.getPlayer().getInventory().getItem(mainHandSlot) :\n                        BukkitItems.getHandItem(e.getPlayer(), PlayerHand.OFF_HAND);\n\n                boolean isInventoryItemEmpty = inventoryItem == null || inventoryItem.getType() == Material.AIR;\n\n                if (!isInventoryItemEmpty && !inventoryItem.isSimilar(usedItem))\n                    return;\n\n                int currAmount = isInventoryItemEmpty ? 0 : inventoryItem.getAmount();\n\n                int consumedAmount = originalAmount - currAmount;\n                if (consumedAmount <= 0)\n                    return;\n\n                breedItem.setAmount(consumedAmount);\n                trackedBreedItems.put(e.getRightClicked().getEntityId(), breedItem);\n            }, 5L);\n        }\n\n    }\n\n    private static class SpawningPlayerData {\n\n        private final WeakReference<Player> player;\n        private final List<ItemStack> itemStacks = new LinkedList<>();\n\n        SpawningPlayerData(Player player) {\n            this(player, (ItemStack) null);\n        }\n\n        SpawningPlayerData(Player player, @Nullable ItemStack itemStack) {\n            this.player = new WeakReference<>(player);\n            addItem(itemStack);\n        }\n\n        SpawningPlayerData(Player player, ItemStack... itemStacks) {\n            this.player = new WeakReference<>(player);\n            for (ItemStack itemStack : itemStacks)\n                addItem(itemStack);\n        }\n\n        private void addItem(@Nullable ItemStack itemStack) {\n            if (itemStack != null && itemStack.getType() != Material.AIR && itemStack.getAmount() > 0)\n                this.itemStacks.add(itemStack);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEffect;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEffect;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.entity.EntityPotionEffectEvent;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class UpgradeTypeIslandEffects implements IUpgradeType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public UpgradeTypeIslandEffects(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        return ServerVersion.isAtLeast(ServerVersion.v1_15) ?\n                Collections.singletonList(new IslandEffectsListener()) :\n                Collections.emptyList();\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddEffect(), new CmdAdminSetEffect());\n    }\n\n    private class IslandEffectsListener implements Listener {\n\n        @EventHandler(ignoreCancelled = true)\n        public void onPlayerEffect(EntityPotionEffectEvent e) {\n            if (e.getAction() == EntityPotionEffectEvent.Action.ADDED || !(e.getEntity() instanceof Player) ||\n                    e.getCause() == EntityPotionEffectEvent.Cause.PLUGIN || e.getCause() == EntityPotionEffectEvent.Cause.BEACON)\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle()));\n            }\n\n            if (island == null)\n                return;\n\n            int islandEffectLevel = island.getPotionEffectLevel(e.getModifiedType());\n\n            if (islandEffectLevel > 0 && (e.getOldEffect() == null || e.getOldEffect().getAmplifier() == islandEffectLevel)) {\n                e.setCancelled(true);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddMobDrops;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetMobDrops;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Location;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.LivingEntity;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.entity.EntityDamageByEntityEvent;\nimport org.bukkit.event.entity.EntityDamageEvent;\nimport org.bukkit.event.entity.EntityDeathEvent;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class UpgradeTypeMobDrops implements IUpgradeType {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final boolean isWildStackerInstalled;\n\n    public UpgradeTypeMobDrops(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n        isWildStackerInstalled = Bukkit.getPluginManager().isPluginEnabled(\"WildStacker\");\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        return Collections.singletonList(new MobDropsListener());\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddMobDrops(), new CmdAdminSetMobDrops());\n    }\n\n    private static boolean canDupeDropsForEntity(Entity entity) {\n        return entity instanceof LivingEntity && !(entity instanceof Player) && !(entity instanceof ArmorStand);\n    }\n\n    private class MobDropsListener implements Listener {\n\n        // Priority is set to HIGH for fixing detection with WildStacker\n        // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/540\n        @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)\n        public void onLastDamageEntity(EntityDamageEvent e) {\n            if (!canDupeDropsForEntity(e.getEntity()))\n                return;\n\n            LivingEntity livingEntity = (LivingEntity) e.getEntity();\n\n            if (livingEntity.getHealth() - e.getFinalDamage() > 0)\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(livingEntity.getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            BukkitEntities.cacheEntityEquipment(livingEntity);\n        }\n\n        @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)\n        public void onEntityDeath(EntityDeathEvent e) {\n            if (!canDupeDropsForEntity(e.getEntity()))\n                return;\n\n            Island island;\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle()));\n            }\n            if (island == null)\n                return;\n\n            if (plugin.getSettings().isDropsUpgradePlayersMultiply()) {\n                EntityDamageEvent lastDamage = e.getEntity().getLastDamageCause();\n                if (!(lastDamage instanceof EntityDamageByEntityEvent) ||\n                        !BukkitEntities.getPlayerSource(((EntityDamageByEntityEvent) lastDamage).getDamager()).isPresent())\n                    return;\n            }\n\n            double mobDropsMultiplier = island.getMobDropsMultiplier();\n            if (mobDropsMultiplier > 1)\n                modifyEventDrops(e.getDrops(), e.getEntity(), mobDropsMultiplier);\n\n            BukkitEntities.clearEntityEquipment(e.getEntity());\n        }\n\n        private void modifyEventDrops(List<ItemStack> drops, LivingEntity livingEntity, double mobDropsMultiplier) {\n            List<ItemStack> dropsToAdd = isWildStackerInstalled ? null : new LinkedList<>();\n\n            for (ItemStack itemStack : drops) {\n                if (itemStack != null && !BukkitEntities.isEquipment(livingEntity, itemStack)) {\n                    int newAmount = (int) Math.floor(itemStack.getAmount() * mobDropsMultiplier);\n\n                    if (isWildStackerInstalled) {\n                        itemStack.setAmount(newAmount);\n                    } else {\n                        int stackAmounts = newAmount / itemStack.getMaxStackSize();\n                        int leftOvers = newAmount % itemStack.getMaxStackSize();\n                        boolean usedOriginal = false;\n\n                        if (stackAmounts > 0) {\n                            itemStack.setAmount(itemStack.getMaxStackSize());\n                            usedOriginal = true;\n\n                            ItemStack stackItem = itemStack.clone();\n                            stackItem.setAmount(itemStack.getMaxStackSize());\n\n                            for (int i = 0; i < stackAmounts - 1; i++)\n                                dropsToAdd.add(itemStack.clone());\n                        }\n\n                        if (leftOvers > 0) {\n                            if (usedOriginal) {\n                                ItemStack leftOversItem = itemStack.clone();\n                                leftOversItem.setAmount(leftOvers);\n                                dropsToAdd.add(leftOversItem);\n                            } else {\n                                itemStack.setAmount(leftOvers);\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (dropsToAdd != null)\n                drops.addAll(dropsToAdd);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java",
    "content": "package com.bgsoftware.superiorskyblock.module.upgrades.type;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.commands.ISuperiorCommand;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddSpawnerRates;\nimport com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetSpawnerRates;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.block.Block;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.EventPriority;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.event.world.ChunkLoadEvent;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class UpgradeTypeSpawnerRates implements IUpgradeType {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public UpgradeTypeSpawnerRates(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public List<Listener> getListeners() {\n        return Collections.singletonList(new SpawnerRatesListener());\n    }\n\n    @Override\n    public List<ISuperiorCommand> getCommands() {\n        return Arrays.asList(new CmdAdminAddSpawnerRates(), new CmdAdminSetSpawnerRates());\n    }\n\n    public void handleSpawnerPlace(Block block) {\n        Location location = block.getLocation();\n        Island island = plugin.getGrid().getIslandAt(location);\n\n        if (island == null)\n            return;\n\n        // We want to replace the spawner in a delay so other plugins that might change the spawner will be taken in action as well.\n        BukkitExecutor.sync(() -> {\n            if (block.getType() == Materials.SPAWNER.toBukkitType())\n                plugin.getNMSWorld().listenSpawner(location, spawnDelay -> calculateNewSpawnerDelay(island, spawnDelay));\n        }, 20L);\n    }\n\n    private int calculateNewSpawnerDelay(Island island, int spawnDelay) {\n        double spawnerRatesMultiplier = island.getSpawnerRatesMultiplier();\n        if (spawnerRatesMultiplier > 1) {\n            return (int) Math.round(spawnDelay / spawnerRatesMultiplier);\n        } else {\n            return spawnDelay;\n        }\n    }\n\n    private class SpawnerRatesListener implements Listener {\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onSpawnerPlace(BlockPlaceEvent e) {\n            if (e.getBlock().getType() == Materials.SPAWNER.toBukkitType())\n                handleSpawnerPlace(e.getBlock());\n        }\n\n        @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)\n        public void onChunkLoad(ChunkLoadEvent e) {\n            List<Island> chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk());\n            chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk()));\n        }\n\n        private void handleIslandChunkLoad(Island island, Chunk chunk) {\n            List<Location> blockEntities = plugin.getNMSChunks().getBlockEntities(chunk);\n\n            if (blockEntities.isEmpty())\n                return;\n\n            // We want to replace the spawner in a delay so other plugins that might change the spawner will be taken in action as well.\n            // Block entities that are not spawners will not be touched.\n            BukkitExecutor.sync(() -> {\n                if (chunk.isLoaded()) {\n                    blockEntities.forEach(blockEntity -> {\n                        plugin.getNMSWorld().listenSpawner(blockEntity, spawnDelay -> calculateNewSpawnerDelay(island, spawnDelay));\n                    });\n                }\n            }, 20L);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport org.bukkit.Location;\n\npublic interface ICachedBlock extends ObjectsPool.Releasable {\n\n    void setBlock(Location location);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.io.ClassProcessor;\nimport com.bgsoftware.superiorskyblock.listener.BukkitEventsListener;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Biome;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.command.defaults.BukkitCommand;\nimport org.bukkit.entity.FallingBlock;\nimport org.bukkit.entity.Minecart;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.meta.ItemMeta;\nimport org.bukkit.inventory.meta.PotionMeta;\nimport org.bukkit.potion.PotionEffect;\n\nimport java.util.Optional;\n\npublic interface NMSAlgorithms {\n\n    EnumBridge<Biome> BIOME_ENUM_BRIDGE = new EnumBridge<Biome>() {\n        @Override\n        public Biome[] getValues() {\n            return Biome.values();\n        }\n\n        @Override\n        public String getName(Biome enumValue) {\n            return enumValue.name();\n        }\n    };\n\n    void registerCommand(BukkitCommand command);\n\n    String parseSignLine(String original);\n\n    int getCombinedId(Location location);\n\n    int getCombinedId(Material material, byte data);\n\n    Optional<String> getTileEntityIdFromCombinedId(int combinedId);\n\n    int compareMaterials(Material o1, Material o2);\n\n    short getBlockDataValue(BlockState blockState);\n\n    short getBlockDataValue(Block block);\n\n    short getMaxBlockDataValue(Material material);\n\n    Key getBlockKey(int combinedId);\n\n    Key getMinecartBlock(Minecart minecart);\n\n    Key getFallingBlockType(FallingBlock fallingBlock);\n\n    void setCustomModel(ItemMeta itemMeta, int customModel);\n\n    void setItemModel(ItemMeta itemMeta, String itemModel);\n\n    void setRarity(ItemMeta itemMeta, String rarity) throws IllegalArgumentException;\n\n    void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) throws IllegalArgumentException;\n\n    void setHideTooltip(ItemMeta itemMeta);\n\n    void addPotion(PotionMeta potionMeta, PotionEffect potionEffect);\n\n    String getMinecraftKey(ItemStack itemStack);\n\n    void makeItemGlow(ItemMeta itemMeta);\n\n    @Nullable\n    Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title);\n\n    int getMaxWorldSize();\n\n    double getCurrentTps();\n\n    int getDataVersion();\n\n    Biome getBiome(String biomeName);\n\n    default ClassProcessor getClassProcessor() {\n        return null;\n    }\n\n    default void handlePaperChatRenderer(Object event) {\n        throw new UnsupportedOperationException();\n    }\n\n    default void hideAttributes(ItemMeta itemMeta) {\n\n    }\n\n    default EnumBridge<Biome> getBiomeBridge() {\n        return BIOME_ENUM_BRIDGE;\n    }\n\n    default BukkitEventsListener.GameEventCreator getGenericGameCreator() {\n        throw new UnsupportedOperationException(\"Not supported in this version\");\n    }\n\n    interface EnumBridge<T> {\n\n        T[] getValues();\n\n        String getName(T enumValue);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.core.CalculatedChunk;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.block.Biome;\nimport org.bukkit.entity.Player;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface NMSChunks {\n\n    void setBiome(List<ChunkPosition> chunkPositions, Biome biome, Collection<Player> playersToUpdate);\n\n    void deleteChunks(Island island, List<ChunkPosition> chunkPositions, @Nullable Runnable onFinish);\n\n    CompletableFuture<List<CalculatedChunk.Blocks>> calculateChunks(List<ChunkPosition> chunkPositions,\n                                                             Synchronized<Chunk2ObjectMap<CalculatedChunk.Blocks>> unloadedChunksCache);\n\n    CompletableFuture<List<CalculatedChunk.Entities>> calculateChunkEntities(Collection<ChunkPosition> chunkPositions);\n\n    void injectChunkSections(Chunk chunk);\n\n    boolean isChunkEmpty(Chunk chunk);\n\n    @Nullable\n    Chunk getChunkIfLoaded(ChunkPosition chunkPosition);\n\n    void startTickingChunk(Island island, Chunk chunk, boolean stop);\n\n    void updateCropsTicker(List<ChunkPosition> chunkPositions, double newCropGrowthMultiplier);\n\n    void shutdown();\n\n    List<Location> getBlockEntities(Chunk chunk);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFight.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.EnderDragon;\nimport org.bukkit.entity.Player;\n\npublic interface NMSDragonFight {\n\n    void prepareEndWorld(World bukkitWorld);\n\n    @Nullable\n    EnderDragon getEnderDragon(Island island, Dimension dimension);\n\n    void startDragonBattle(Island island, Location location);\n\n    void removeDragonBattle(Island island, Dimension dimension);\n\n    void awardTheEndAchievement(Player player);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFightChooser.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.nmsloader.NMSLoadException;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.EnderDragon;\nimport org.bukkit.entity.Player;\n\npublic class NMSDragonFightChooser implements NMSDragonFight {\n\n    private final SuperiorSkyblockPlugin plugin;\n    private final NMSDragonFightSupplier enabledInstanceSupplier;\n    private NMSDragonFight delegate;\n\n    public NMSDragonFightChooser(SuperiorSkyblockPlugin plugin, NMSDragonFightSupplier enabledInstanceSupplier) {\n        this.plugin = plugin;\n        this.enabledInstanceSupplier = enabledInstanceSupplier;\n    }\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        getDelegate().prepareEndWorld(bukkitWorld);\n    }\n\n    @Override\n    public EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        return getDelegate().getEnderDragon(island, dimension);\n    }\n\n    @Override\n    public void startDragonBattle(Island island, Location location) {\n        getDelegate().startDragonBattle(island, location);\n    }\n\n    @Override\n    public void removeDragonBattle(Island island, Dimension dimension) {\n        getDelegate().removeDragonBattle(island, dimension);\n    }\n\n    @Override\n    public void awardTheEndAchievement(Player player) {\n        getDelegate().awardTheEndAchievement(player);\n    }\n\n    private NMSDragonFight getDelegate() {\n        if (this.delegate == null) {\n            if (plugin.getSettings() == null)\n                throw new RuntimeException(\"Called NMSDragonFightChooser#getDelegate before settings initialized\");\n\n            for (Dimension dimension : Dimension.values()) {\n                if (dimension.getEnvironment() == World.Environment.THE_END) {\n                    SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n                    if (dimensionConfig instanceof SettingsManager.Worlds.End &&\n                            ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) {\n                        try {\n                            this.delegate = this.enabledInstanceSupplier.get();\n                        } catch (NMSLoadException error) {\n                            Log.error(error, \"Failed to load NMSDragonFight, disabling it...\");\n                            this.delegate = new NMSDragonFightImpl();\n                        }\n\n                        return this.delegate;\n                    }\n                }\n            }\n\n            this.delegate = new NMSDragonFightImpl();\n        }\n\n\n        return this.delegate;\n    }\n\n    public interface NMSDragonFightSupplier {\n\n        NMSDragonFight get() throws NMSLoadException;\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFightImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.EnderDragon;\nimport org.bukkit.entity.Player;\n\npublic class NMSDragonFightImpl implements NMSDragonFight {\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        // Do nothing.\n    }\n\n    @Nullable\n    @Override\n    public EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        return null;\n    }\n\n    @Override\n    public void startDragonBattle(Island island, Location location) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeDragonBattle(Island island, Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public void awardTheEndAchievement(Player player) {\n        // Do nothing.\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.inventory.EntityEquipment;\nimport org.bukkit.inventory.ItemStack;\n\npublic interface NMSEntities {\n\n    ItemStack[] getEquipment(EntityEquipment entityEquipment);\n\n    boolean isAnimalFood(ItemStack itemStack, Animals animals);\n\n    boolean isMinecartFuel(ItemStack itemStack, PoweredMinecart minecart);\n\n    int getPortalTicks(Entity entity);\n\n    default boolean canShearSaddleFromEntity(Entity entity) {\n        // Not implemented for most versions\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSHolograms.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\npublic interface NMSHolograms {\n\n    Hologram createHologram(Location location);\n\n    boolean isHologram(Entity entity);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport com.mojang.authlib.properties.Property;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\n\npublic interface NMSPlayers {\n\n    OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer);\n\n    void setSkinTexture(SuperiorPlayer superiorPlayer);\n\n    void setSkinTexture(SuperiorPlayer superiorPlayer, Property property);\n\n    void sendActionBar(Player player, String message);\n\n    BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun);\n\n    void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut);\n\n    boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer);\n\n    @Nullable\n    Locale getPlayerLocale(Player player);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Set;\n\npublic interface NMSTags {\n\n    CompoundTag serializeItem(ItemStack itemStack);\n\n    ItemStack deserializeItem(CompoundTag compoundTag);\n\n    default ItemStack getSkullWithTexture(ItemStack itemStack, String texture) {\n        return ItemSkulls.getPlayerHeadNoNMS(itemStack, texture);\n    }\n\n    void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag);\n\n    byte[] getNBTByteArrayValue(Object object);\n\n    byte getNBTByteValue(Object object);\n\n    Set<String> getNBTCompoundValue(Object object);\n\n    double getNBTDoubleValue(Object object);\n\n    float getNBTFloatValue(Object object);\n\n    int[] getNBTIntArrayValue(Object object);\n\n    int getNBTIntValue(Object object);\n\n    Object getNBTListIndexValue(Object object, int index);\n\n    long getNBTLongValue(Object object);\n\n    short getNBTShortValue(Object object);\n\n    String getNBTStringValue(Object object);\n\n    Object parseList(ListTag listTag);\n\n    Object getNBTCompoundTag(Object object, String key);\n\n    void setNBTCompoundTagValue(Object object, String key, Object value);\n\n    int getNBTTagListSize(Object object);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java",
    "content": "package com.bgsoftware.superiorskyblock.nms;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.SignType;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport org.bukkit.Chunk;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockState;\n\nimport java.util.function.IntFunction;\n\npublic interface NMSWorld {\n\n    Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z);\n\n    boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z);\n\n    void listenSpawner(Location location, IntFunction<Integer> delayChangeCallback);\n\n    default void replaceTrialBlockPlayerDetector(Island island, Location location) {\n        // Does not exist.\n    }\n\n    default void replaceSculkSensorListener(Island island, Location location) {\n        // Does not exist.\n    }\n\n    void setWorldBorder(SuperiorPlayer superiorPlayer, Island island);\n\n    Object getBlockData(Block block);\n\n    void setBlock(Location location, int combinedId);\n\n    ICachedBlock cacheBlock(Block block);\n\n    boolean isWaterLogged(Block block);\n\n    default SignType getSignType(Block block) {\n        return getSignType(getBlockData(block));\n    }\n\n    SignType getSignType(Object sign);\n\n    default boolean hasBerries(Block block) {\n        return false;\n    }\n\n    PistonPushReaction getPistonReaction(Block block);\n\n    int getDefaultAmount(Block block);\n\n    int getDefaultAmount(BlockState blockState);\n\n    boolean canPlayerSuffocate(Block block);\n\n    void placeSign(Island island, Location location);\n\n    void playGeneratorSound(Location location);\n\n    void playBreakAnimation(Block block);\n\n    void playPlaceSound(Location location);\n\n    int getMinHeight(World world);\n\n    void removeAntiXray(World world);\n\n    void setOceanLevel(World world);\n\n    void listenBlockStateChanges(World world);\n\n    IslandsGenerator createGenerator(Dimension dimension);\n\n    WorldEditSession createEditSession(World world);\n\n    WorldEditSession createPartialEditSession(Dimension dimension);\n\n    ChunkReader createChunkReader(Chunk chunk);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/bridge/PistonPushReaction.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.bridge;\n\npublic enum PistonPushReaction {\n\n    /* Keep in sync with PushReaction nms */\n    NORMAL,\n    DESTROY,\n    BLOCK,\n    IGNORE,\n    PUSH_ONLY\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.player;\n\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\npublic interface OfflinePlayerData extends ObjectsPool.Releasable {\n\n    Player getFakeOnlinePlayer();\n\n    void setLocation(Location location);\n\n    void applyChanges();\n\n    @Override\n    void release();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\n\npublic interface ChunkReader {\n\n    int getX();\n\n    int getZ();\n\n    Material getType(int x, int y, int z);\n\n    short getData(int x, int y, int z);\n\n    @Nullable\n    CompoundTag getTileEntity(int x, int y, int z);\n\n    @Nullable\n    CompoundTag readBlockStates(int x, int y, int z);\n\n    byte[] getLightLevels(int x, int y, int z);\n\n    void forEachEntity(EntityConsumer consumer);\n\n    interface EntityConsumer {\n\n        void apply(EntityType entityType, CompoundTag entityTag, Location location);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java",
    "content": "package com.bgsoftware.superiorskyblock.nms.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\n\nimport java.util.List;\n\npublic interface WorldEditSession extends ObjectsPool.Releasable {\n\n    void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData);\n\n    List<ChunkPosition> getAffectedChunks();\n\n    void applyBlocks(Chunk chunk);\n\n    void finish(Island island);\n\n    Data readData(Location baseLocation);\n\n    void applyData(Data data, Location baseLocation);\n\n    interface Data {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java",
    "content": "package com.bgsoftware.superiorskyblock.platform;\n\nimport com.bgsoftware.superiorskyblock.platform.event.GameEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.GameEventPriority;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\n\npublic interface IPlatform {\n\n    <Args extends IEventArgs> void notifyGameEvent(GameEvent<Args> gameEvent, GameEventPriority priority);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\nimport com.bgsoftware.superiorskyblock.core.events.IEvent;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\n\npublic class GameEvent<Args extends IEventArgs> implements IEvent<GameEventType<?>> {\n\n    private final GameEventType<Args> type;\n    private final Args args;\n\n    private boolean cancelled = false;\n\n    public GameEvent(GameEventType<Args> type, Args args) {\n        this.type = type;\n        this.args = args;\n    }\n\n    @Override\n    public GameEventType<Args> getType() {\n        return type;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        return this.cancelled;\n    }\n\n    public Args getArgs() {\n        return args;\n    }\n\n    public void setCancelled() {\n        this.cancelled = true;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\nimport com.bgsoftware.superiorskyblock.core.events.EventCallback;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\n\npublic interface GameEventCallback<Args extends IEventArgs> extends EventCallback<GameEvent<Args>> {\n\n    void execute(GameEvent<Args> gameEvent);\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\npublic @interface GameEventFlags {\n\n    int ENTITY_EVENT = 1 << 0;\n    int MAYBE_ENTITY_EVENT = 1 << 1;\n    int BLOCK_EVENT = 1 << 2;\n    int MAYBE_BLOCK_EVENT = 1 << 3;\n    int PLAYER_EVENT = 1 << 4;\n    int GENERIC_WORLD_EVENT = 1 << 5;\n    int INVENTORY_EVENT = 1 << 5;\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\npublic enum GameEventPriority {\n\n    LOWEST,\n    LOW,\n    NORMAL,\n    HIGH,\n    HIGHEST,\n    MONITOR\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\nimport com.bgsoftware.superiorskyblock.core.events.EventType;\nimport com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBreakEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBurnEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockDispenseEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFadeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFormEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFromToEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockGrowEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockIgniteEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPhysicsEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPlaceEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockRedstoneEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockSpreadEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockUpdateShapeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkLoadEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkUnloadEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityBlockFormEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityChangeBlockEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityCollisionEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDamageEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDeathEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityEnterPortalEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityExplodeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityInteractEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityMoveEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityPortalEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityRideEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntitySpawnEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTargetEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTeleportEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.GenericGameEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingBreakEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingPlaceEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryClickEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryCloseEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryOpenEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.LeavesDecayEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonExtendEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonRetractEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChangedWorldEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChatEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerCommandEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerDropItemEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerEmptyBucketEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerFillBucketEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerGamemodeChangeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerInteractEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerItemConsumeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerJoinEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLeashEntityEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLoginEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupArrowEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupItemEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerQuitEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerRespawnEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerShearEntityEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerUnleashEntityEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileHitEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileLaunchEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.RaidTriggerEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SignChangeEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SpongeAbsorbEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.StructureGrowEvent;\nimport static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.WorldUnloadEvent;\n\npublic class GameEventType<Args extends IEventArgs> extends EventType<Args, GameEvent<Args>> {\n\n    private static final List<GameEventType<?>> ALL_TYPES = new LinkedList<>();\n\n    // Block Events\n    public static final GameEventType<BlockBreakEvent> BLOCK_BREAK_EVENT = register(BlockBreakEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<BlockBurnEvent> BLOCK_BURN_EVENT = register(BlockBurnEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockDispenseEvent> BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockFadeEvent> BLOCK_FADE_EVENT = register(BlockFadeEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockFormEvent> BLOCK_FORM_EVENT = register(BlockFormEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockFromToEvent> BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockGrowEvent> BLOCK_GROW_EVENT = register(BlockGrowEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockIgniteEvent> BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockPhysicsEvent> BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockPlaceEvent> BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<BlockRedstoneEvent> BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockSpreadEvent> BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<BlockUpdateShapeEvent> BLOCK_UPDATE_SHAPE_EVENT = register(BlockUpdateShapeEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<LeavesDecayEvent> LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<PistonExtendEvent> PISTON_EXTEND_EVENT = register(PistonExtendEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<PistonRetractEvent> PISTON_RETRACT_EVENT = register(PistonRetractEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<SignChangeEvent> SIGN_CHANGE_EVENT = register(SignChangeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<SpongeAbsorbEvent> SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class, GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<StructureGrowEvent> STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class, GameEventFlags.BLOCK_EVENT);\n\n    // World Events\n    public static final GameEventType<ChunkLoadEvent> CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT);\n    public static final GameEventType<ChunkUnloadEvent> CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT);\n    public static final GameEventType<WorldUnloadEvent> WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT);\n    public static final GameEventType<RaidTriggerEvent> RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<GenericGameEvent> GENERIC_GAME_EVENT = register(GenericGameEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT);\n\n    // Entity Events\n    public static final GameEventType<EntityBlockFormEvent> ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityChangeBlockEvent> ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityCollisionEvent> ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityDamageEvent> ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityDeathEvent> ENTITY_DEATH_EVENT = register(EntityDeathEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityEnterPortalEvent> ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityExplodeEvent> ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityInteractEvent> ENTITY_INTERACT_EVENT = register(EntityInteractEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n    public static final GameEventType<EntityMoveEvent> ENTITY_MOVE_EVENT = register(EntityMoveEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityPortalEvent> ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityRideEvent> ENTITY_RIDE_EVENT = register(EntityRideEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntitySpawnEvent> ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityTargetEvent> ENTITY_TARGET_EVENT = register(EntityTargetEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<EntityTeleportEvent> ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<HangingBreakEvent> HANGING_BREAK_EVENT = register(HangingBreakEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<HangingPlaceEvent> HANGING_PLACE_EVENT = register(HangingPlaceEvent.class, GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<ProjectileHitEvent> PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT);\n    public static final GameEventType<ProjectileLaunchEvent> PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class, GameEventFlags.ENTITY_EVENT);\n\n    // Inventory Events\n    public static final GameEventType<InventoryClickEvent> INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<InventoryCloseEvent> INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<InventoryOpenEvent> INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT);\n\n    // Player Events\n    public static final GameEventType<PlayerChangedWorldEvent> PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerChatEvent> PLAYER_CHAT_EVENT = register(PlayerChatEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerCommandEvent> PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerDropItemEvent> PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<PlayerEmptyBucketEvent> PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<PlayerFillBucketEvent> PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT);\n    public static final GameEventType<PlayerGamemodeChangeEvent> PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerInteractEvent> PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT);\n    public static final GameEventType<PlayerItemConsumeEvent> PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerJoinEvent> PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerLeashEntityEvent> PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<PlayerLoginEvent> PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerPickupArrowEvent> PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<PlayerPickupItemEvent> PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<PlayerQuitEvent> PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerRespawnEvent> PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class, GameEventFlags.PLAYER_EVENT);\n    public static final GameEventType<PlayerShearEntityEvent> PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n    public static final GameEventType<PlayerUnleashEntityEvent> PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT);\n\n    @GameEventFlags\n    private final int flags;\n\n    private GameEventType(@GameEventFlags int flags) {\n        this.flags = flags;\n    }\n\n    @GameEventFlags\n    public int getFlags() {\n        return this.flags;\n    }\n\n    public GameEvent<Args> createEvent(Args args) {\n        return new GameEvent<>(this, args);\n    }\n\n    private static <Args extends IEventArgs> GameEventType<Args> register(Class<Args> eventArgsType, @GameEventFlags int flags) {\n        GameEventType<Args> eventType = new GameEventType<>(flags);\n        ALL_TYPES.add(eventType);\n        return eventType;\n    }\n\n    public static Collection<GameEventType<?>> values() {\n        return Collections.unmodifiableList(ALL_TYPES);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.events.EventsDispatcher;\nimport com.bgsoftware.superiorskyblock.listener.AbstractGameEventListener;\n\npublic class GameEventsDispatcher extends EventsDispatcher<\n        AbstractGameEventListener,\n        GameEventType<?>,\n        GameEventPriority,\n        GameEvent<?>> {\n\n    @GameEventFlags\n    private int capturedEventsFlags = 0;\n\n    public GameEventsDispatcher(SuperiorSkyblockPlugin plugin) {\n        super(plugin, GameEventPriority.class, GameEventType.values());\n    }\n\n    @Override\n    public void startCaptureEvents() {\n        this.startCaptureEvents(0xFFFFFFFF);\n    }\n\n    public void startCaptureEvents(@GameEventFlags int capturedEventsFlags) {\n        super.startCaptureEvents();\n        this.capturedEventsFlags = capturedEventsFlags;\n    }\n\n    @Override\n    protected boolean filterCapturedEvent(GameEvent<?> event) {\n        return this.capturedEventsFlags == 0xFFFFFFFF || (event.getType().getFlags() & this.capturedEventsFlags) != 0;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event.args;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport org.bukkit.Chunk;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.Vehicle;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.entity.CreatureSpawnEvent;\nimport org.bukkit.event.player.PlayerTeleportEvent;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.util.Vector;\n\nimport java.util.List;\n\npublic class GameEventArgs implements IEventArgs {\n\n    private GameEventArgs() {\n\n    }\n\n    public static class BlockFromToEvent extends BlockEvent {\n\n        public Block toBlock;\n\n    }\n\n    public static class BlockIgniteEvent extends BlockEvent {\n\n        public org.bukkit.event.block.BlockIgniteEvent.IgniteCause igniteCause;\n\n    }\n\n    public static class PistonExtendEvent extends PistonEvent {\n\n    }\n\n    public static class PistonRetractEvent extends PistonEvent {\n\n    }\n\n    public static class BlockPlaceEvent extends BlockEvent {\n\n        public Player player;\n        public Block againstBlock;\n        public BlockState replacedState;\n        public PlayerHand usedHand;\n        public ItemStack usedItem;\n\n    }\n\n    public static class ChunkLoadEvent extends ChunkEvent {\n\n        public boolean isNewChunk;\n\n    }\n\n    public static class EntityChangeBlockEvent extends EntityEvent {\n\n        public Block block;\n        public Key newType;\n\n    }\n\n    public static class EntityDamageEvent extends EntityEvent {\n\n        public org.bukkit.event.entity.EntityDamageEvent.DamageCause damageCause;\n        @Nullable\n        public Entity damager;\n\n    }\n\n    public static class EntityMoveEvent extends EntityEvent {\n\n        public Location from;\n        public Location to;\n\n    }\n\n    public static class EntityRideEvent extends EntityEvent {\n\n        public Vehicle vehicle;\n\n    }\n\n    public static class HangingBreakEvent extends EntityEvent {\n\n        public Entity remover;\n        public org.bukkit.event.hanging.HangingBreakEvent.RemoveCause removeCause;\n\n    }\n\n    public static class HangingPlaceEvent extends EntitySpawnEvent {\n\n        public Player player;\n\n    }\n\n    public static class EntityTargetEvent extends EntityEvent {\n\n        public Entity target;\n\n    }\n\n    public static class InventoryClickEvent extends GameEventArgs {\n\n        public org.bukkit.event.inventory.InventoryClickEvent bukkitEvent;\n\n    }\n\n    public static class PlayerChangedWorldEvent extends PlayerEvent {\n\n        public World from;\n\n    }\n\n    public static class PlayerChatEvent extends PlayerEvent {\n\n        public String message;\n        @Nullable\n        public String format;\n\n    }\n\n    public static class PlayerCommandEvent extends PlayerEvent {\n\n        public String command;\n\n    }\n\n    public static class PlayerGamemodeChangeEvent extends PlayerEvent {\n\n        public GameMode newGamemode;\n\n    }\n\n    public static class PlayerInteractEvent extends PlayerEvent {\n\n        public Action action;\n        @Nullable\n        public PlayerHand usedHand;\n        @Nullable\n        public ItemStack usedItem;\n        @Nullable\n        public Block clickedBlock;\n        @Nullable\n        public Entity clickedEntity;\n\n    }\n\n    public static class PlayerRespawnEvent extends PlayerEvent {\n\n        public org.bukkit.event.player.PlayerRespawnEvent bukkitEvent;\n\n    }\n\n    public static class SpongeAbsorbEvent extends BlockEvent {\n\n        public List<BlockState> blocks;\n\n    }\n\n    public static class StructureGrowEvent extends WorldEvent {\n\n        public Location location;\n        public List<BlockState> blocks;\n\n    }\n\n    public static class PlayerJoinEvent extends PlayerEvent {\n\n    }\n\n    public static class PlayerQuitEvent extends PlayerEvent {\n\n    }\n\n    public static class PlayerEmptyBucketEvent extends PlayerBucketEvent {\n\n    }\n\n    public static class PlayerFillBucketEvent extends PlayerBucketEvent {\n\n    }\n\n    public static class BlockGrowEvent extends BlockTransformEvent {\n\n    }\n\n    public static class BlockFormEvent extends BlockTransformEvent {\n\n    }\n\n    public static class BlockSpreadEvent extends BlockTransformEvent {\n\n        public Block source;\n\n    }\n\n    public static class BlockBreakEvent extends BlockEvent {\n\n        public Player player;\n\n    }\n\n    public static class EntityDeathEvent extends EntityEvent {\n\n    }\n\n    public static class LeavesDecayEvent extends BlockEvent {\n\n    }\n\n    public static class EntityExplodeEvent extends EntityEvent {\n\n        public List<Block> blocks;\n        public boolean isSoftExplosion;\n\n    }\n\n    public static class ProjectileHitEvent extends EntityEvent {\n\n        @Nullable\n        public Block hitBlock;\n        @Nullable\n        public Entity hitEntity;\n\n    }\n\n    public static class ProjectileLaunchEvent extends EntityEvent {\n\n    }\n\n    public static class ChunkUnloadEvent extends ChunkEvent {\n\n    }\n\n    public static class WorldUnloadEvent extends WorldEvent {\n\n    }\n\n    public static class EntitySpawnEvent extends EntityEvent {\n\n        public CreatureSpawnEvent.SpawnReason spawnReason;\n\n    }\n\n    public static class BlockBurnEvent extends BlockEvent {\n\n    }\n\n    public static class EntityTeleportEvent extends EntityMoveEvent {\n\n        public PlayerTeleportEvent.TeleportCause cause;\n\n    }\n\n    public static class BlockRedstoneEvent extends BlockEvent {\n\n    }\n\n    public static class InventoryCloseEvent extends GameEventArgs {\n\n        public org.bukkit.event.inventory.InventoryCloseEvent bukkitEvent;\n\n    }\n\n    public static class InventoryOpenEvent extends GameEventArgs {\n\n        public org.bukkit.event.inventory.InventoryOpenEvent bukkitEvent;\n\n    }\n\n    public static class PlayerLoginEvent extends PlayerEvent {\n\n    }\n\n    public static class EntityPortalEvent extends EntityTeleportEvent {\n\n    }\n\n    public static class EntityEnterPortalEvent extends EntityEvent {\n\n        public Location portalLocation;\n\n    }\n\n    public static class EntityBlockFormEvent extends BlockFormEvent {\n\n        public Entity entity;\n\n    }\n\n    public static class BlockDispenseEvent extends BlockEvent {\n\n        public ItemStack dispensedItem;\n        public Vector velocity;\n\n    }\n\n    public static class BlockFadeEvent extends BlockEvent {\n\n        public BlockState newState;\n\n    }\n\n\n    public static class PlayerItemConsumeEvent extends PlayerEvent {\n\n        public ItemStack consumedItem;\n\n    }\n\n\n    public static class PlayerShearEntityEvent extends PlayerEvent {\n\n        public Entity entity;\n\n    }\n\n\n    public static class PlayerLeashEntityEvent extends PlayerEvent {\n\n        public Entity entity;\n\n    }\n\n\n    public static class PlayerUnleashEntityEvent extends PlayerEvent {\n\n        public Entity entity;\n\n    }\n\n\n    public static class EntityCollisionEvent extends EntityEvent {\n\n        public Entity target;\n\n    }\n\n\n    public static class PlayerDropItemEvent extends PlayerEvent {\n\n        public Item droppedItem;\n\n    }\n\n\n    public static class PlayerPickupItemEvent extends PlayerEvent {\n\n        public Item pickedUpItem;\n\n    }\n\n    public static class PlayerPickupArrowEvent extends PlayerPickupItemEvent {\n\n    }\n\n    public static class RaidTriggerEvent extends WorldEvent {\n\n        public Player player;\n        public Location raidLocation;\n\n    }\n\n    public static class SignChangeEvent extends BlockEvent {\n\n        public Player player;\n        public String[] lines;\n\n    }\n\n    public static class BlockPhysicsEvent extends BlockEvent {\n\n    }\n\n    public static class BlockUpdateShapeEvent extends BlockEvent {\n\n        public BlockState oldState;\n\n    }\n\n    public static class GenericGameEvent extends WorldEvent {\n\n        public String gameEvent;\n        public Location location;\n\n    }\n\n    public static class EntityInteractEvent extends EntityEvent {\n\n        @Nullable\n        public Block block;\n\n    }\n\n    private static class BlockEvent extends GameEventArgs {\n\n        public Block block;\n\n    }\n\n    private static class PistonEvent extends BlockEvent {\n\n        public List<Block> blocks;\n        public BlockFace direction;\n\n    }\n\n    private static class ChunkEvent extends GameEventArgs {\n\n        public Chunk chunk;\n\n    }\n\n    private static class EntityEvent extends GameEventArgs {\n\n        public Entity entity;\n\n    }\n\n    private static class PlayerEvent extends GameEventArgs {\n\n        public Player player;\n\n    }\n\n    private static class WorldEvent extends GameEventArgs {\n\n        public World world;\n\n    }\n\n    private static class BlockTransformEvent extends BlockEvent {\n\n        public BlockState newState;\n\n    }\n\n    private static class PlayerBucketEvent extends PlayerEvent {\n\n        public Material bucket;\n        public Block clickedBlock;\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java",
    "content": "package com.bgsoftware.superiorskyblock.platform.event.args;\n\npublic interface IEventArgs {\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/PlayerLocales.java",
    "content": "package com.bgsoftware.superiorskyblock.player;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\npublic class PlayerLocales {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Pattern RTL_LOCALE_PATTERN = Pattern.compile(\n            \"^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)\");\n    private static final Pattern LOCALE_PATTERN = Pattern.compile(\"^[a-zA-Z]{2}[_|-][a-zA-Z]{2}$\");\n\n    private static final Set<Locale> locales = new HashSet<>();\n    private static java.util.Locale defaultLocale = null;\n\n    private PlayerLocales() {\n\n    }\n\n    public static Locale getLocale(CommandSender sender) {\n        return sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender).getUserLocale() : defaultLocale;\n    }\n\n    public static java.util.Locale getLocale(String str) throws IllegalArgumentException {\n        str = str.replace(\"_\", \"-\");\n\n        Preconditions.checkArgument(LOCALE_PATTERN.matcher(str).matches(), \"String \" + str + \" is not a valid language.\");\n\n        String[] numberFormatSections = str.split(\"-\");\n\n        return new java.util.Locale(numberFormatSections[0], numberFormatSections[1]);\n    }\n\n    public static boolean isRightToLeft(Locale locale) {\n        return RTL_LOCALE_PATTERN.matcher(locale.getLanguage()).matches();\n    }\n\n    public static void clearLocales() {\n        locales.clear();\n    }\n\n    public static void registerLocale(java.util.Locale locale) {\n        if (locales.isEmpty())\n            defaultLocale = locale;\n        locales.add(locale);\n    }\n\n    public static java.util.Locale getDefaultLocale() {\n        return defaultLocale;\n    }\n\n    public static void setDefaultLocale(Locale defaultLocale) {\n        PlayerLocales.defaultLocale = defaultLocale;\n    }\n\n    public static boolean isValidLocale(java.util.Locale locale) {\n        return locales.contains(locale);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.player;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.PlayersManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.UUID;\nimport java.util.function.Predicate;\n\npublic class PlayersManagerImpl extends Manager implements PlayersManager {\n\n    private PlayersContainer playersContainer;\n\n    public PlayersManagerImpl(SuperiorSkyblockPlugin plugin) {\n        super(plugin);\n    }\n\n    @Override\n    public void loadData() {\n        // Data is loaded by the database bridge.\n        if (this.playersContainer == null)\n            throw new RuntimeException(\"PlayersManager was not initialized correctly. Contact Ome_R regarding this!\");\n    }\n\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.playersContainer.getSuperiorPlayer(name);\n    }\n\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(Player player) {\n        Preconditions.checkNotNull(player, \"player parameter cannot be null.\");\n        return player.hasMetadata(\"NPC\") ? SuperiorNPCPlayer.obtain(player) : getSuperiorPlayer(player.getUniqueId());\n    }\n\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(UUID uuid) {\n        return Objects.requireNonNull(getSuperiorPlayer(uuid, true));\n    }\n\n    @Nullable\n    public SuperiorPlayer getSuperiorPlayer(UUID uuid, boolean createIfNotExists) {\n        return this.getSuperiorPlayer(uuid, createIfNotExists, true);\n    }\n\n    @Nullable\n    public SuperiorPlayer getSuperiorPlayer(UUID uuid, boolean createIfNotExists, boolean saveToDatabase) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        SuperiorPlayer superiorPlayer = this.playersContainer.getSuperiorPlayer(uuid);\n\n        if (createIfNotExists && superiorPlayer == null) {\n            superiorPlayer = plugin.getFactory().createPlayer(uuid);\n            this.playersContainer.addPlayer(superiorPlayer);\n            if (saveToDatabase)\n                PlayersDatabaseBridge.insertPlayer(superiorPlayer);\n        }\n\n        return superiorPlayer;\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayers() {\n        return this.playersContainer.getAllPlayers();\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getPlayerRole(int index) {\n        return plugin.getRoles().getPlayerRole(index);\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getPlayerRoleFromId(int id) {\n        return plugin.getRoles().getPlayerRoleFromId(id);\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getPlayerRole(String name) {\n        return plugin.getRoles().getPlayerRole(name);\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getDefaultRole() {\n        return plugin.getRoles().getDefaultRole();\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getLastRole() {\n        return plugin.getRoles().getLastRole();\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getGuestRole() {\n        return plugin.getRoles().getGuestRole();\n    }\n\n    @Override\n    @Deprecated\n    public PlayerRole getCoopRole() {\n        return plugin.getRoles().getCoopRole();\n    }\n\n    @Override\n    @Deprecated\n    public List<PlayerRole> getRoles() {\n        return plugin.getRoles().getRoles();\n    }\n\n    @Override\n    public PlayersContainer getPlayersContainer() {\n        return this.playersContainer;\n    }\n\n    @Override\n    public void setPlayersContainer(PlayersContainer playersContainer) {\n        Preconditions.checkNotNull(playersContainer, \"playersContainer parameter cannot be null\");\n        this.playersContainer = playersContainer;\n    }\n\n    public SuperiorPlayer getSuperiorPlayer(CommandSender commandSender) {\n        return getSuperiorPlayer((Player) commandSender);\n    }\n\n    public List<SuperiorPlayer> matchAllPlayers(Predicate<? super SuperiorPlayer> predicate) {\n        return new SequentialListBuilder<SuperiorPlayer>()\n                .filter(predicate)\n                .build(this.playersContainer.getAllPlayers());\n    }\n\n    public void replacePlayers(SuperiorPlayer originPlayer, @Nullable SuperiorPlayer newPlayer) {\n        Log.debug(Debug.REPLACE_PLAYER, originPlayer, newPlayer);\n\n        // We first want to replace the player for his own island\n        Island playerIsland = originPlayer.getIsland();\n        if (playerIsland != null) {\n            playerIsland.replacePlayers(originPlayer, newPlayer);\n            if (playerIsland.getOwner() != newPlayer)\n                Log.debugResult(Debug.REPLACE_PLAYER, \"Owner was not replaced\", \"Curr owner: \" + playerIsland.getOwner().getUniqueId());\n        }\n\n        for (Island island : plugin.getGrid().getIslands()) {\n            if (island != playerIsland)\n                island.replacePlayers(originPlayer, newPlayer);\n        }\n\n        if (newPlayer == null) {\n            PlayersDatabaseBridge.deletePlayer(originPlayer);\n        } else {\n            newPlayer.merge(originPlayer);\n            PluginEventsFactory.callPlayerReplaceEvent(originPlayer, newPlayer);\n        }\n    }\n\n    // Updating last time status\n    public void savePlayers() {\n        for (Player player : Bukkit.getOnlinePlayers())\n            PlayersDatabaseBridge.saveLastTimeStatus(getSuperiorPlayer(player));\n\n        List<SuperiorPlayer> modifiedPlayers = new SequentialListBuilder<SuperiorPlayer>()\n                .filter(PlayersDatabaseBridge::isModified)\n                .build(getAllPlayers());\n\n        if (!modifiedPlayers.isEmpty())\n            modifiedPlayers.forEach(PlayersDatabaseBridge::executeFutureSaves);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java",
    "content": "package com.bgsoftware.superiorskyblock.player;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.HitActionResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SBlockPosition;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.config.PvPWorldsCache;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.mission.MissionData;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl;\nimport com.bgsoftware.superiorskyblock.player.cache.PlayerCacheImpl;\nimport com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.InventoryHolder;\nimport org.bukkit.inventory.InventoryView;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class SSuperiorPlayer implements SuperiorPlayer {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static PvPWorldsCache pvpWorldsCache = null;\n\n    private final DatabaseBridge databaseBridge;\n    private final PlayerTeleportAlgorithm playerTeleportAlgorithm;\n    @Nullable\n    private PersistentDataContainer persistentDataContainer; // Lazy loading\n    private final LazyReference<PlayerCache> playerCache = new LazyReference<PlayerCache>() {\n        @Override\n        protected PlayerCache create() {\n            return new PlayerCacheImpl(SSuperiorPlayer.this);\n        }\n    };\n    private final PlayerPermissionsStore permissionsStore;\n\n    private final Map<MissionReference, Counter> completedMissions = new ConcurrentHashMap<>();\n    private final List<UUID> pendingInvites = new LinkedList<>();\n    private final List<Island> coopIslands = new LinkedList<>();\n\n    private final UUID uuid;\n\n    private Island playerIsland = null;\n    private String name;\n    private String textureValue;\n    private WeakReference<PlayerRole> playerRole;\n    private int playerRoleId;\n    private java.util.Locale userLocale;\n\n    private boolean worldBorderEnabled;\n    private boolean blocksStackerEnabled = plugin.getSettings().isDefaultStackedBlocks();\n    private boolean schematicModeEnabled = false;\n    private boolean bypassModeEnabled = false;\n    private boolean teamChatEnabled = false;\n    private boolean toggledPanel;\n    private boolean islandFly;\n    private boolean adminSpyEnabled = false;\n\n    private SBlockPosition schematicPos1 = null;\n    private SBlockPosition schematicPos2 = null;\n    private int disbands;\n    private BorderColor borderColor;\n    private long lastTimeStatus;\n\n    private BukkitTask teleportTask = null;\n    private EnumSet<PlayerStatus> playerStatuses = EnumSet.noneOf(PlayerStatus.class);\n\n    public SSuperiorPlayer(SuperiorPlayerBuilderImpl builder) {\n        this.uuid = builder.uuid;\n        this.name = builder.name;\n        setPlayerRoleInternal(builder.playerRole);\n        this.disbands = builder.disbands;\n        this.userLocale = builder.locale;\n        this.textureValue = builder.textureValue;\n        this.lastTimeStatus = builder.lastTimeUpdated;\n        this.toggledPanel = builder.toggledPanel;\n        this.islandFly = builder.islandFly;\n        this.borderColor = builder.borderColor;\n        this.worldBorderEnabled = builder.worldBorderEnabled;\n        this.completedMissions.putAll(builder.completedMissions);\n        if (builder.persistentData.length > 0)\n            getPersistentDataContainer().load(builder.persistentData);\n\n        this.databaseBridge = plugin.getFactory().createDatabaseBridge(this);\n        this.playerTeleportAlgorithm = plugin.getFactory().createPlayerTeleportAlgorithm(this);\n        this.permissionsStore = new PlayerPermissionsStore(this);\n\n        databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);\n    }\n\n    /*\n     *   General Methods\n     */\n\n    private static HitActionResult checkPvPAllow(SuperiorPlayer player, boolean target) {\n        // Checks for online status\n        if (!player.isOnline())\n            return target ? HitActionResult.TARGET_NOT_ONLINE : HitActionResult.NOT_ONLINE;\n\n        // Checks for pvp warm-up\n        if (player.hasPlayerStatus(PlayerStatus.PVP_IMMUNED))\n            return target ? HitActionResult.TARGET_PVP_WARMUP : HitActionResult.PVP_WARMUP;\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld()))\n            return HitActionResult.SUCCESS;\n\n        Island standingIsland;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            standingIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle()));\n        }\n\n        if (standingIsland != null && (plugin.getSettings().getSpawn().isProtected() || !standingIsland.isSpawn())) {\n            // Checks for pvp status\n            if (!standingIsland.hasSettingsEnabled(IslandFlags.PVP))\n                return target ? HitActionResult.TARGET_ISLAND_PVP_DISABLE : HitActionResult.ISLAND_PVP_DISABLE;\n\n            if (!plugin.getSettings().isCoopDamage() && standingIsland.isCoop(player)) {\n                // Checks for coop damage\n                return target ? HitActionResult.TARGET_COOP_DAMAGE : HitActionResult.COOP_DAMAGE;\n            } else if (!plugin.getSettings().isVisitorsDamage() && standingIsland.isVisitor(player, true)) {\n                // Checks for visitors damage\n                return target ? HitActionResult.TARGET_VISITOR_DAMAGE : HitActionResult.VISITOR_DAMAGE;\n            }\n        }\n\n        return HitActionResult.SUCCESS;\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return uuid;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public PlayerCache getCache() {\n        return this.playerCache.get();\n    }\n\n    @Override\n    public String getTextureValue() {\n        return textureValue;\n    }\n\n    @Override\n    public void setTextureValue(String textureValue) {\n        Preconditions.checkNotNull(textureValue, \"textureValue parameter cannot be null.\");\n\n        Log.debug(Debug.SET_TEXTURE_VALUE, getName(), textureValue);\n\n        String oldTextureValue = this.textureValue;\n\n        // We first update the texture value, even if they are equal.\n        this.textureValue = textureValue;\n\n        // We now compare them but remove the timestamp when comparing.\n        if (Objects.equals(removeTextureValueTimeStamp(oldTextureValue), removeTextureValueTimeStamp(textureValue)))\n            return;\n\n        // We only save the value if it's actually different.\n        PlayersDatabaseBridge.saveTextureValue(this);\n    }\n\n    @Override\n    public void updateLastTimeStatus() {\n        setLastTimeStatus(System.currentTimeMillis() / 1000);\n    }\n\n    @Override\n    public void setLastTimeStatus(long lastTimeStatus) {\n        Log.debug(Debug.SET_PLAYER_LAST_TIME_UPDATED, getName(), lastTimeStatus);\n\n        if (this.lastTimeStatus == lastTimeStatus)\n            return;\n\n        this.lastTimeStatus = lastTimeStatus;\n\n        PlayersDatabaseBridge.saveLastTimeStatus(this);\n    }\n\n    @Override\n    public long getLastTimeStatus() {\n        return lastTimeStatus;\n    }\n\n    @Override\n    public void updateName() {\n        Player player = asPlayer();\n        if (player != null)\n            this.setName(player.getName());\n    }\n\n    @Override\n    public void setName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n\n        if (Objects.equals(this.name, name))\n            return;\n\n        try {\n            plugin.getPlayers().getPlayersContainer().removePlayer(this);\n            this.name = name;\n            PlayersDatabaseBridge.savePlayerName(this);\n        } finally {\n            plugin.getPlayers().getPlayersContainer().addPlayer(this);\n        }\n    }\n\n    @Override\n    public Player asPlayer() {\n        return Bukkit.getPlayer(uuid);\n    }\n\n    @Override\n    public OfflinePlayer asOfflinePlayer() {\n        return Bukkit.getOfflinePlayer(uuid);\n    }\n\n    @Override\n    public boolean isOnline() {\n        OfflinePlayer offlinePlayer = asOfflinePlayer();\n        return offlinePlayer != null && offlinePlayer.isOnline();\n    }\n\n    @Override\n    public void runIfOnline(Consumer<Player> toRun) {\n        Player player = asPlayer();\n        if (player != null)\n            toRun.accept(player);\n    }\n\n    @Override\n    public boolean hasFlyGamemode() {\n        Player player = asPlayer();\n        return player != null && (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR);\n    }\n\n    @Nullable\n    @Override\n    public MenuView<?, ?> getOpenedView() {\n        Player player = asPlayer();\n\n        if (player != null) {\n            InventoryView openInventory = player.getOpenInventory();\n            if (openInventory != null && openInventory.getTopInventory() != null) {\n                InventoryHolder inventoryHolder = openInventory.getTopInventory().getHolder();\n                if (inventoryHolder instanceof MenuView)\n                    return (MenuView<?, ?>) inventoryHolder;\n            }\n        }\n\n        return null;\n    }\n\n    @Override\n    public boolean isAFK() {\n        Player player = asPlayer();\n        return player != null && plugin.getProviders().isAFK(player);\n    }\n\n    @Override\n    public boolean isVanished() {\n        Player player = asPlayer();\n        return player != null && plugin.getProviders().getVanishProvider().isVanished(player);\n    }\n\n    @Override\n    public boolean isShownAsOnline() {\n        Player player = asPlayer();\n        return player != null && player.getGameMode() != GameMode.SPECTATOR && !isVanished();\n    }\n\n    @Override\n    public boolean hasPermission(String permission) {\n        Preconditions.checkNotNull(permission, \"permission parameter cannot be null.\");\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Checking for permission\", permission);\n\n        if (permission.isEmpty())\n            return true;\n\n        Log.debug(Debug.PERMISSION_LOOKUP, getName(), permission);\n\n        Player player = asPlayer();\n        if (player == null) {\n            Log.debugResult(Debug.PERMISSION_LOOKUP, \"Result\", \"Player is not online\");\n            return false;\n        }\n\n        boolean res = player.hasPermission(permission);\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Result\", res);\n\n        return res;\n    }\n\n    @Override\n    public boolean hasPermissionWithoutOP(String permission) {\n        Preconditions.checkNotNull(permission, \"permission parameter cannot be null.\");\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Checking for permission\", permission);\n\n        if (permission.isEmpty())\n            return true;\n\n        Log.debug(Debug.PERMISSION_LOOKUP, getName(), permission, \"No-Op Check\");\n\n        Player player = asPlayer();\n\n        PlayerPermissionsStore.PermissionResult permissionResult =\n                this.permissionsStore.hasCustomPermission(player, permission);\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Result\", permissionResult);\n\n        return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED;\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege permission) {\n        Preconditions.checkNotNull(permission, \"permission parameter cannot be null.\");\n        Island island = getIsland();\n        return island != null && island.hasPermission(this, permission);\n    }\n\n    @Override\n    public boolean hasBypassPermission(IslandPrivilege permission) {\n        Preconditions.checkNotNull(permission, \"permission parameter cannot be null.\");\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Checking for IslandPrivilege bypass permission\", permission);\n\n        Player player = asPlayer();\n\n        PlayerPermissionsStore.PermissionResult permissionResult =\n                this.permissionsStore.hasBypassPermission(player, permission);\n\n        Log.debugResult(Debug.PERMISSION_LOOKUP, \"Result\", permissionResult);\n\n        return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED;\n    }\n\n    /*\n     *   Location Methods\n     */\n\n    @Override\n    public HitActionResult canHit(SuperiorPlayer otherPlayer) {\n        Preconditions.checkNotNull(otherPlayer, \"otherPlayer parameter cannot be null.\");\n\n        // Players can hit themselves\n        if (equals(otherPlayer))\n            return HitActionResult.SUCCESS;\n\n        World world = getWorld();\n\n        // Checks for island teammates pvp\n        Island island = getIsland();\n        if (island != null && island == otherPlayer.getIsland() && (world == null || !isPvPWorldInternal(world.getName())))\n            return HitActionResult.ISLAND_TEAM_PVP;\n\n        // Checks if this player can bypass all pvp restrictions\n        {\n            HitActionResult selfResult = checkPvPAllow(this, false);\n            if (selfResult != HitActionResult.SUCCESS)\n                return selfResult;\n        }\n\n        // Checks if target player can bypass all pvp restrictions\n        {\n            HitActionResult targetResult = checkPvPAllow(otherPlayer, true);\n            if (targetResult != HitActionResult.SUCCESS)\n                return targetResult;\n        }\n\n        return HitActionResult.SUCCESS;\n    }\n\n    @Override\n    public World getWorld() {\n        Player player = asPlayer();\n        return player == null ? null : player.getWorld();\n    }\n\n    @Override\n    public Location getLocation() {\n        Player player = asPlayer();\n        return player == null ? null : player.getLocation();\n    }\n\n    @Override\n    public Location getLocation(@Nullable Location location) {\n        if (location != null) {\n            Player player = asPlayer();\n            if (player != null)\n                player.getLocation(location);\n        }\n\n        return location;\n    }\n\n    @Override\n    public void teleport(Location location) {\n        teleport(location, null);\n    }\n\n    @Override\n    public void teleport(Location location, @Nullable Consumer<Boolean> teleportResult) {\n        Player player = asPlayer();\n        if (player != null) {\n            playerTeleportAlgorithm.teleport(player, location).whenComplete((result, error) -> {\n                if (teleportResult != null)\n                    teleportResult.accept(error == null && result);\n            });\n        } else if (teleportResult != null) {\n            teleportResult.accept(false);\n        }\n    }\n\n    @Override\n    public void teleport(Island island) {\n        this.teleport(island, (Consumer<Boolean>) null);\n    }\n\n    @Override\n    public void teleport(Island island, Dimension dimension) {\n        this.teleport(island, dimension, null);\n    }\n\n    @Override\n    public void teleport(Island island, @Nullable Consumer<Boolean> teleportResult) {\n        this.teleport(island, plugin.getSettings().getWorlds().getDefaultWorldDimension(), teleportResult);\n    }\n\n    @Override\n    public void teleport(Island island, Dimension dimension, @Nullable Consumer<Boolean> teleportResult) {\n        Player player = asPlayer();\n        if (player != null) {\n            setPlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED);\n            playerTeleportAlgorithm.teleport(player, island, dimension).whenComplete((result, error) -> {\n                boolean successful = error == null && result;\n\n                player.setFallDistance(0f);\n                removePlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED);\n\n                if (teleportResult != null)\n                    teleportResult.accept(successful);\n            });\n        } else if (teleportResult != null) {\n            teleportResult.accept(false);\n        }\n    }\n\n    @Override\n    public boolean isInsideIsland() {\n        Player player = asPlayer();\n        Island island = getIsland();\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return player != null && island != null && island.isInside(player.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    /*\n     *   Island Methods\n     */\n\n    @Override\n    public SuperiorPlayer getIslandLeader() {\n        Island island = getIsland();\n        return island == null ? this : island.getOwner();\n    }\n\n    @Override\n    public void setIslandLeader(SuperiorPlayer islandLeader) {\n        setIsland(islandLeader.getIsland());\n    }\n\n    @Override\n    public Island getIsland() {\n        return playerIsland;\n    }\n\n    @Override\n    public void setIsland(Island island) {\n        Log.debug(Debug.SET_PLAYER_ISLAND, getName(), island == null ? \"null\" : island.getOwner().getName());\n\n        this.playerIsland = island;\n\n        if (this.playerIsland == null) {\n            setPlayerRoleInternal(null);\n        }\n\n    }\n\n    @Override\n    public boolean hasIsland() {\n        return getIsland() != null;\n    }\n\n    @Override\n    public void addInvite(Island island) {\n        this.pendingInvites.add(island.getUniqueId());\n    }\n\n    @Override\n    public void removeInvite(Island island) {\n        this.pendingInvites.remove(island.getUniqueId());\n    }\n\n    @Override\n    public List<Island> getInvites() {\n        return new SequentialListBuilder<UUID>()\n                .map(this.pendingInvites, uuid -> plugin.getGrid().getIslandByUUID(uuid));\n    }\n\n    @Override\n    public void addCoop(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null\");\n        Preconditions.checkArgument(island.isCoop(this), \"player is not coop of given island\");\n        this.coopIslands.add(island);\n    }\n\n    @Override\n    public void removeCoop(Island island) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null\");\n        this.coopIslands.remove(island);\n    }\n\n    @Override\n    public List<Island> getCoopIslands() {\n        return new SequentialListBuilder<Island>().build(this.coopIslands);\n    }\n\n    @Override\n    public PlayerRole getPlayerRole() {\n        PlayerRole playerRole = this.playerRole.get();\n\n        if (playerRole == null) {\n            // Reference doesn't exist anymore, let's get it from roles manager again\n            playerRole = plugin.getRoles().getPlayerRoleFromId(this.playerRoleId);\n            this.playerRole = new WeakReference<>(playerRole);\n        }\n\n        if (this.playerIsland == null && playerRole != SPlayerRole.guestRole()) {\n            setPlayerRoleInternal(null);\n            playerRole = this.playerRole.get();\n        }\n\n        return playerRole;\n    }\n\n    @Override\n    public void setPlayerRole(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n\n        Log.debug(Debug.SET_PLAYER_ROLE, getName(), playerRole.getName());\n\n        setPlayerRoleInternal(playerRole);\n\n        Island island = getIsland();\n        if (island != null && island.getOwner() != this)\n            IslandsDatabaseBridge.saveMemberRole(island, this);\n    }\n\n    @Override\n    public int getDisbands() {\n        return disbands;\n    }\n\n    @Override\n    public void setDisbands(int disbands) {\n        Log.debug(Debug.SET_DISBANDS, getName(), disbands);\n\n        if (this.disbands == disbands)\n            return;\n\n        this.disbands = disbands;\n\n        PlayersDatabaseBridge.saveDisbands(this);\n    }\n\n    @Override\n    public boolean hasDisbands() {\n        return disbands > 0;\n    }\n\n    /*\n     *   Preferences Methods\n     */\n\n    @Override\n    public java.util.Locale getUserLocale() {\n        if (userLocale == null)\n            userLocale = PlayerLocales.getDefaultLocale();\n        return userLocale;\n    }\n\n    @Override\n    public void setUserLocale(java.util.Locale userLocale) {\n        Preconditions.checkNotNull(userLocale, \"userLocale parameter cannot be null.\");\n        Preconditions.checkArgument(PlayerLocales.isValidLocale(userLocale), \"Locale \" + userLocale + \" is not a valid locale.\");\n\n        Log.debug(Debug.SET_LANGUAGE, getName(), userLocale.getLanguage() + \"-\" + userLocale.getCountry());\n\n        if (Objects.equals(this.userLocale, userLocale))\n            return;\n\n        this.userLocale = userLocale;\n\n        PlayersDatabaseBridge.saveUserLocale(this);\n    }\n\n    @Override\n    public boolean hasWorldBorderEnabled() {\n        return worldBorderEnabled;\n    }\n\n    @Override\n    public void toggleWorldBorder() {\n        setWorldBorderEnabled(!worldBorderEnabled);\n    }\n\n    @Override\n    public void setWorldBorderEnabled(boolean enabled) {\n        Log.debug(Debug.SET_TOGGLED_BORDER, getName(), enabled);\n\n        if (this.worldBorderEnabled == enabled)\n            return;\n\n        this.worldBorderEnabled = enabled;\n        PlayersDatabaseBridge.saveToggledBorder(this);\n    }\n\n    @Override\n    public void updateWorldBorder(@Nullable Island island) {\n        plugin.getNMSWorld().setWorldBorder(this, island);\n    }\n\n    @Override\n    public boolean hasBlocksStackerEnabled() {\n        return blocksStackerEnabled;\n    }\n\n    @Override\n    public void toggleBlocksStacker() {\n        setBlocksStacker(!blocksStackerEnabled);\n    }\n\n    @Override\n    public void setBlocksStacker(boolean enabled) {\n        Log.debug(Debug.SET_TOGGLED_STACKER, getName(), enabled);\n        blocksStackerEnabled = enabled;\n    }\n\n    @Override\n    public boolean hasSchematicModeEnabled() {\n        return schematicModeEnabled;\n    }\n\n    @Override\n    public void toggleSchematicMode() {\n        setSchematicMode(!schematicModeEnabled);\n    }\n\n    @Override\n    public void setSchematicMode(boolean enabled) {\n        Log.debug(Debug.SET_TOGGLED_SCHEMATIC, getName(), enabled);\n        schematicModeEnabled = enabled;\n    }\n\n    @Override\n    public boolean hasTeamChatEnabled() {\n        return teamChatEnabled;\n    }\n\n    @Override\n    public void toggleTeamChat() {\n        setTeamChat(!teamChatEnabled);\n    }\n\n    @Override\n    public void setTeamChat(boolean enabled) {\n        Log.debug(Debug.SET_TEAM_CHAT, getName(), enabled);\n        teamChatEnabled = enabled;\n    }\n\n    @Override\n    public boolean hasBypassModeEnabled() {\n        Player player = asPlayer();\n\n        if (bypassModeEnabled && player != null && !player.hasPermission(\"superior.admin.bypass\"))\n            bypassModeEnabled = false;\n\n        return bypassModeEnabled;\n    }\n\n    @Override\n    public void toggleBypassMode() {\n        setBypassMode(!bypassModeEnabled);\n    }\n\n    @Override\n    public void setBypassMode(boolean enabled) {\n        Log.debug(Debug.SET_ADMIN_BYPASS, getName(), enabled);\n        bypassModeEnabled = enabled;\n    }\n\n    @Override\n    public boolean hasToggledPanel() {\n        return toggledPanel;\n    }\n\n    @Override\n    public void setToggledPanel(boolean toggledPanel) {\n        Log.debug(Debug.SET_TOGGLED_PANEL, getName(), toggledPanel);\n\n        if (this.toggledPanel == toggledPanel)\n            return;\n\n        this.toggledPanel = toggledPanel;\n        PlayersDatabaseBridge.saveToggledPanel(this);\n    }\n\n    @Override\n    public boolean hasIslandFlyEnabled() {\n        Player player = asPlayer();\n\n        if (islandFly && player != null && !player.hasPermission(\"superior.island.fly\")) {\n            islandFly = false;\n            if (player.getAllowFlight()) {\n                player.setFlying(false);\n                player.setAllowFlight(false);\n            }\n        }\n\n        return islandFly;\n    }\n\n    @Override\n    public void toggleIslandFly() {\n        setIslandFly(!islandFly);\n    }\n\n    @Override\n    public void setIslandFly(boolean enabled) {\n        Log.debug(Debug.SET_ISLAND_FLY, getName(), enabled);\n\n        if (this.islandFly == enabled)\n            return;\n\n        this.islandFly = enabled;\n        PlayersDatabaseBridge.saveIslandFly(this);\n    }\n\n    @Override\n    public boolean hasAdminSpyEnabled() {\n        return adminSpyEnabled;\n    }\n\n    @Override\n    public void toggleAdminSpy() {\n        setAdminSpy(!adminSpyEnabled);\n    }\n\n    @Override\n    public void setAdminSpy(boolean enabled) {\n        Log.debug(Debug.SET_ADMIN_SPY, getName(), enabled);\n        adminSpyEnabled = enabled;\n    }\n\n    @Override\n    public BorderColor getBorderColor() {\n        return borderColor;\n    }\n\n    @Override\n    public void setBorderColor(BorderColor borderColor) {\n        Preconditions.checkNotNull(borderColor, \"borderColor parameter cannot be null.\");\n\n        Log.debug(Debug.SET_BORDER_COLOR, getName(), borderColor);\n\n        if (this.borderColor == borderColor)\n            return;\n\n        this.borderColor = borderColor;\n        PlayersDatabaseBridge.saveBorderColor(this);\n    }\n\n    /*\n     *   Schematics Methods\n     */\n\n    @Override\n    public BlockPosition getSchematicPos1() {\n        return schematicPos1;\n    }\n\n    @Override\n    public void setSchematicPos1(@Nullable Block block) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? \"null\" : block.getLocation(wrapper.getHandle()));\n        }\n        this.schematicPos1 = block == null ? null : SBlockPosition.of(block);\n    }\n\n    @Override\n    public SBlockPosition getSchematicPos2() {\n        return schematicPos2;\n    }\n\n    @Override\n    public void setSchematicPos2(@Nullable Block block) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? \"null\" : block.getLocation(wrapper.getHandle()));\n        }\n        this.schematicPos2 = block == null ? null : SBlockPosition.of(block);\n    }\n\n    /*\n     *   Missions Methods\n     */\n\n    /*\n     *   Data Methods\n     */\n\n    @Override\n    @Deprecated\n    public boolean isImmunedToPvP() {\n        return this.hasPlayerStatus(PlayerStatus.PVP_IMMUNED);\n    }\n\n    @Override\n    @Deprecated\n    public void setImmunedToPvP(boolean immunedToPvP) {\n        if (immunedToPvP)\n            setPlayerStatus(PlayerStatus.PVP_IMMUNED);\n        else\n            removePlayerStatus(PlayerStatus.PVP_IMMUNED);\n    }\n\n    @Override\n    @Deprecated\n    public boolean isLeavingFlag() {\n        return this.hasPlayerStatus(PlayerStatus.LEAVING_ISLAND);\n    }\n\n    @Override\n    @Deprecated\n    public void setLeavingFlag(boolean leavingFlag) {\n        if (leavingFlag)\n            setPlayerStatus(PlayerStatus.LEAVING_ISLAND);\n        else\n            removePlayerStatus(PlayerStatus.LEAVING_ISLAND);\n    }\n\n    @Override\n    public boolean isImmunedToPortals() {\n        return this.hasPlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n    }\n\n    @Override\n    public void setImmunedToPortals(boolean immuneToTeleport) {\n        if (immuneToTeleport)\n            setPlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n        else\n            removePlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n    }\n\n    @Override\n    public BukkitTask getTeleportTask() {\n        return teleportTask;\n    }\n\n    @Override\n    public void setTeleportTask(BukkitTask teleportTask) {\n        if (this.teleportTask != null)\n            this.teleportTask.cancel();\n        this.teleportTask = teleportTask;\n    }\n\n    @Override\n    public PlayerStatus getPlayerStatus() {\n        for (PlayerStatus playerStatus : PlayerStatus.values()) {\n            if (this.playerStatuses.contains(playerStatus))\n                return playerStatus;\n        }\n\n        return PlayerStatus.NONE;\n    }\n\n    @Override\n    public void setPlayerStatus(PlayerStatus playerStatus) {\n        Preconditions.checkNotNull(playerStatus, \"playerStatus cannot be null\");\n        Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, \"Cannot set PlayerStatus.NONE\");\n\n        if (this.hasPlayerStatus(playerStatus))\n            return;\n\n        Log.debug(Debug.SET_PLAYER_STATUS, getName(), playerStatus.name());\n        this.playerStatuses.add(playerStatus);\n    }\n\n    @Override\n    public void removePlayerStatus(PlayerStatus playerStatus) {\n        Preconditions.checkNotNull(playerStatus, \"playerStatus cannot be null\");\n        Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, \"Cannot remove PlayerStatus.NONE\");\n\n        if (!this.hasPlayerStatus(playerStatus))\n            return;\n\n        Log.debug(Debug.REMOVE_PLAYER_STATUS, getName(), playerStatus.name());\n        this.playerStatuses.remove(playerStatus);\n    }\n\n    @Override\n    public boolean hasPlayerStatus(PlayerStatus playerStatus) {\n        Preconditions.checkNotNull(playerStatus, \"playerStatus cannot be null\");\n        Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, \"Cannot check PlayerStatus.NONE\");\n        return this.playerStatuses.contains(playerStatus);\n    }\n\n    @Override\n    public void merge(SuperiorPlayer otherPlayer) {\n        Preconditions.checkNotNull(otherPlayer, \"otherPlayer parameter cannot be null.\");\n\n        this.name = otherPlayer.getName();\n        this.playerIsland = otherPlayer.getIsland();\n        setPlayerRoleInternal(otherPlayer.getPlayerRole());\n        this.userLocale = otherPlayer.getUserLocale();\n        this.worldBorderEnabled |= otherPlayer.hasWorldBorderEnabled();\n        this.blocksStackerEnabled |= otherPlayer.hasBlocksStackerEnabled();\n        this.schematicModeEnabled |= otherPlayer.hasSchematicModeEnabled();\n        this.bypassModeEnabled |= otherPlayer.hasBypassModeEnabled();\n        this.teamChatEnabled |= otherPlayer.hasTeamChatEnabled();\n        this.toggledPanel |= otherPlayer.hasToggledPanel();\n        this.islandFly |= otherPlayer.hasToggledPanel();\n        this.adminSpyEnabled |= otherPlayer.hasAdminSpyEnabled();\n        this.disbands = otherPlayer.getDisbands();\n        this.borderColor = otherPlayer.getBorderColor();\n        this.lastTimeStatus = otherPlayer.getLastTimeStatus();\n        this.completedMissions.clear();\n\n        otherPlayer.getCompletedMissionsWithAmounts().forEach((mission, finishCount) ->\n                this.completedMissions.put(new MissionReference(mission), new Counter(finishCount)));\n\n        if (!otherPlayer.isPersistentDataContainerEmpty()) {\n            byte[] data = otherPlayer.getPersistentDataContainer().serialize();\n            getPersistentDataContainer().load(data);\n        }\n\n        // Convert data for missions\n        plugin.getMissions().convertPlayerData(otherPlayer, this);\n\n        // Replace player in DB.\n        PlayersDatabaseBridge.replacePlayer(otherPlayer, this);\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return databaseBridge;\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        if (persistentDataContainer == null)\n            persistentDataContainer = plugin.getFactory().createPersistentDataContainer(this);\n        return persistentDataContainer;\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return persistentDataContainer == null || persistentDataContainer.isEmpty();\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        PlayersDatabaseBridge.executeFutureSaves(this, PlayersDatabaseBridge.FutureSave.PERSISTENT_DATA);\n    }\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(!mission.getIslandMission(), \"mission parameter must be player-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1));\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(!mission.getIslandMission(), \"mission parameter must be player-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1));\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return getAmountMissionCompleted(mission) > 0;\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        if (mission.getIslandMission())\n            return false;\n\n        Optional<MissionData> missionDataOptional = plugin.getMissions().getMissionData(mission);\n\n        if (missionDataOptional.isPresent()) {\n            int resetAmount = missionDataOptional.get().getResetAmount();\n            return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount;\n        }\n\n        return false;\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Counter finishCount = mission.getIslandMission() ? null : completedMissions.get(new MissionReference(mission));\n        return finishCount == null ? 0 : finishCount.get();\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        Preconditions.checkArgument(!mission.getIslandMission(), \"mission parameter must be player-mission.\");\n        this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount));\n    }\n\n    private void changeAmountMissionsCompletedInternal(Mission<?> mission, boolean clearData, Function<Counter, Integer> action) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n\n        MissionReference missionReference = new MissionReference(mission);\n\n        Counter finishCount = completedMissions.computeIfAbsent(missionReference, r -> new Counter(0));\n        int oldFinishCount = action.apply(finishCount);\n        int newFinishCount = finishCount.get();\n\n        Log.debug(Debug.SET_PLAYER_MISSION_COMPLETED, getName(), mission.getName(), newFinishCount);\n\n        if (clearData)\n            mission.clearData(this);\n\n        if (newFinishCount > 0) {\n            if (newFinishCount == oldFinishCount)\n                return;\n\n            PlayersDatabaseBridge.saveMission(this, mission, newFinishCount);\n        } else {\n            completedMissions.remove(missionReference);\n\n            if (oldFinishCount <= 0)\n                return;\n\n            PlayersDatabaseBridge.removeMission(this, mission);\n        }\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return new SequentialListBuilder<MissionReference>()\n                .filter(MissionReference::isValid)\n                .map(completedMissions.keySet(), MissionReference::getMission);\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        Map<Mission<?>, Integer> completedMissions = new LinkedHashMap<>();\n\n        this.completedMissions.forEach((mission, finishCount) -> {\n            if (mission.isValid())\n                completedMissions.put(mission.getMission(), finishCount.get());\n        });\n\n        return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions);\n    }\n\n    /*\n     *   Other Methods\n     */\n\n    @Override\n    public int hashCode() {\n        return uuid.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        return obj instanceof SuperiorPlayer && (this == obj || uuid.equals(((SuperiorPlayer) obj).getUniqueId()));\n    }\n\n    @Override\n    public String toString() {\n        return \"SSuperiorPlayer{\" +\n                \"uuid=[\" + uuid + \"],\" +\n                \"name=[\" + name + \"]\" +\n                \"}\";\n    }\n\n    private void setPlayerRoleInternal(@Nullable PlayerRole playerRole) {\n        PlayerRole newRole = playerRole == null ? SPlayerRole.guestRole() : playerRole;\n        this.playerRole = new WeakReference<>(newRole);\n        this.playerRoleId = newRole.getId();\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SSuperiorPlayer::onSettingsUpdate);\n    }\n\n    private static String removeTextureValueTimeStamp(@Nullable String textureValue) {\n        // The texture value string is a json containing a timestamp value.\n        // However, when we compare texture values, we want to emit the timestamp value.\n        // This value is found at index 35->41 (6 chars in length).\n        return textureValue == null || textureValue.length() <= 42 ? null : textureValue.substring(0, 35) + textureValue.substring(42);\n    }\n\n    private static boolean isPvPWorldInternal(String worldName) {\n        if (pvpWorldsCache == null)\n            pvpWorldsCache = new PvPWorldsCache(plugin.getSettings().getPvPWorlds());\n\n        return pvpWorldsCache.isPvPWorld(worldName);\n    }\n\n    private static void onSettingsUpdate() {\n        pvpWorldsCache = null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java",
    "content": "package com.bgsoftware.superiorskyblock.player;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.data.DatabaseBridge;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.enums.HitActionResult;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.menu.view.MenuView;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPool;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\npublic class SuperiorNPCPlayer implements SuperiorPlayer, ObjectsPool.Releasable {\n\n    private static final ObjectsPool<SuperiorNPCPlayer> POOL = new ObjectsPool<>(SuperiorNPCPlayer::new);\n\n    public static SuperiorNPCPlayer obtain(Player npc) {\n        return POOL.obtain().initialize(npc);\n    }\n\n    private Player npc;\n\n    private SuperiorNPCPlayer() {\n\n    }\n\n    private SuperiorNPCPlayer initialize(Player npc) {\n        this.npc = npc;\n        return this;\n    }\n\n    @Override\n    public void release() {\n        this.npc = null;\n\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return npc.getUniqueId();\n    }\n\n    @Override\n    public String getName() {\n        return \"NPC-Citizens\";\n    }\n\n    @Override\n    public PlayerCache getCache() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getTextureValue() {\n        return \"\";\n    }\n\n    @Override\n    public void setTextureValue(String textureValue) {\n        // Do nothing.\n    }\n\n    @Override\n    public void updateLastTimeStatus() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setLastTimeStatus(long lastTimeStatus) {\n        // Do nothing.\n    }\n\n    @Override\n    public long getLastTimeStatus() {\n        return System.currentTimeMillis() / 1000;\n    }\n\n    @Override\n    public void updateName() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setName(String name) {\n        // Do nothing.\n    }\n\n    @Override\n    public Player asPlayer() {\n        return null;\n    }\n\n    @Override\n    public OfflinePlayer asOfflinePlayer() {\n        return null;\n    }\n\n    @Override\n    public boolean isOnline() {\n        return false;\n    }\n\n    @Override\n    public void runIfOnline(Consumer<Player> toRun) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasFlyGamemode() {\n        return false;\n    }\n\n    @Nullable\n    @Override\n    public MenuView<?, ?> getOpenedView() {\n        return null;\n    }\n\n    @Override\n    public boolean isAFK() {\n        return false;\n    }\n\n    @Override\n    public boolean isVanished() {\n        return false;\n    }\n\n    @Override\n    public boolean isShownAsOnline() {\n        return false;\n    }\n\n    @Override\n    public boolean hasPermission(String permission) {\n        return false;\n    }\n\n    @Override\n    public boolean hasPermissionWithoutOP(String permission) {\n        return false;\n    }\n\n    @Override\n    public boolean hasPermission(IslandPrivilege permission) {\n        return false;\n    }\n\n    @Override\n    public boolean hasBypassPermission(IslandPrivilege islandPrivilege) {\n        return false;\n    }\n\n    @Override\n    public HitActionResult canHit(SuperiorPlayer other) {\n        return HitActionResult.NOT_ONLINE;\n    }\n\n    @Override\n    public World getWorld() {\n        return npc.getWorld();\n    }\n\n    @Override\n    public Location getLocation() {\n        return npc.getLocation();\n    }\n\n    @Override\n    public Location getLocation(Location location) {\n        return this.npc.getLocation(location);\n    }\n\n    @Override\n    public void teleport(Location location) {\n        // Do nothing.\n    }\n\n    @Override\n    public void teleport(Location unused, @Nullable Consumer<Boolean> teleportResult) {\n        if (teleportResult != null)\n            teleportResult.accept(false);\n    }\n\n    @Override\n    public void teleport(Island island) {\n        // Do nothing.\n    }\n\n    @Override\n    public void teleport(Island island, Dimension dimension) {\n        // Do nothing.\n    }\n\n    @Override\n    public void teleport(Island unused, Dimension unused2, @Nullable Consumer<Boolean> teleportResult) {\n        if (teleportResult != null)\n            teleportResult.accept(false);\n    }\n\n    @Override\n    public void teleport(Island unused, @Nullable Consumer<Boolean> teleportResult) {\n        if (teleportResult != null)\n            teleportResult.accept(false);\n    }\n\n    @Override\n    public boolean isInsideIsland() {\n        return false;\n    }\n\n    @Override\n    public SuperiorPlayer getIslandLeader() {\n        return this;\n    }\n\n    @Override\n    public void setIslandLeader(SuperiorPlayer superiorPlayer) {\n        // Do nothing.\n    }\n\n    @Override\n    public Island getIsland() {\n        return null;\n    }\n\n    @Override\n    public void setIsland(Island island) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasIsland() {\n        return false;\n    }\n\n    @Override\n    public void addInvite(Island island) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removeInvite(Island island) {\n        // Do nothing.\n    }\n\n    @Override\n    public List<Island> getInvites() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public void addCoop(Island island) {\n        throw new UnsupportedOperationException(\"Cannot mark NPCs as coop players\");\n    }\n\n    @Override\n    public void removeCoop(Island island) {\n        throw new UnsupportedOperationException(\"Cannot mark NPCs as coop players\");\n    }\n\n    @Override\n    public List<Island> getCoopIslands() {\n        throw new UnsupportedOperationException(\"Cannot mark NPCs as coop players\");\n    }\n\n    @Override\n    public PlayerRole getPlayerRole() {\n        return SPlayerRole.guestRole();\n    }\n\n    @Override\n    public void setPlayerRole(PlayerRole playerRole) {\n        // Do nothing.\n    }\n\n    @Override\n    public int getDisbands() {\n        return 0;\n    }\n\n    @Override\n    public void setDisbands(int disbands) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasDisbands() {\n        return false;\n    }\n\n    @Override\n    public Locale getUserLocale() {\n        return PlayerLocales.getDefaultLocale();\n    }\n\n    @Override\n    public void setUserLocale(Locale locale) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasWorldBorderEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleWorldBorder() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setWorldBorderEnabled(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public void updateWorldBorder(@Nullable Island island) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasBlocksStackerEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleBlocksStacker() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setBlocksStacker(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasSchematicModeEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleSchematicMode() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setSchematicMode(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasTeamChatEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleTeamChat() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setTeamChat(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasBypassModeEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleBypassMode() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setBypassMode(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasToggledPanel() {\n        return false;\n    }\n\n    @Override\n    public void setToggledPanel(boolean toggledPanel) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasIslandFlyEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleIslandFly() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setIslandFly(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasAdminSpyEnabled() {\n        return false;\n    }\n\n    @Override\n    public void toggleAdminSpy() {\n        // Do nothing.\n    }\n\n    @Override\n    public void setAdminSpy(boolean enabled) {\n        // Do nothing.\n    }\n\n    @Override\n    public BorderColor getBorderColor() {\n        return BorderColor.BLUE;\n    }\n\n    @Override\n    public void setBorderColor(BorderColor borderColor) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockPosition getSchematicPos1() {\n        return null;\n    }\n\n    @Override\n    public void setSchematicPos1(Block block) {\n        // Do nothing.\n    }\n\n    @Override\n    public BlockPosition getSchematicPos2() {\n        return null;\n    }\n\n    @Override\n    public void setSchematicPos2(Block block) {\n        // Do nothing.\n    }\n\n    @Nullable\n    @Override\n    public BukkitTask getTeleportTask() {\n        return null;\n    }\n\n    @Override\n    public void setTeleportTask(@Nullable BukkitTask teleportTask) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isImmunedToPvP() {\n        return false;\n    }\n\n    @Override\n    public void setImmunedToPvP(boolean immunedToPvP) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isLeavingFlag() {\n        return false;\n    }\n\n    @Override\n    public void setLeavingFlag(boolean leavingFlag) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean isImmunedToPortals() {\n        return false;\n    }\n\n    @Override\n    public void setImmunedToPortals(boolean immuneToPortals) {\n        // Do nothing.\n    }\n\n    @Override\n    @Deprecated\n    public PlayerStatus getPlayerStatus() {\n        return PlayerStatus.NONE;\n    }\n\n    @Override\n    public void setPlayerStatus(PlayerStatus playerStatus) {\n        // Do nothing.\n    }\n\n    @Override\n    public void removePlayerStatus(PlayerStatus playerStatus) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasPlayerStatus(PlayerStatus playerStatus) {\n        return false;\n    }\n\n    @Override\n    public void merge(SuperiorPlayer other) {\n        // Do nothing.\n    }\n\n    @Override\n    public DatabaseBridge getDatabaseBridge() {\n        return EmptyDatabaseBridge.getInstance();\n    }\n\n    @Override\n    public PersistentDataContainer getPersistentDataContainer() {\n        return EmptyPersistentDataContainer.getInstance();\n    }\n\n    @Override\n    public boolean isPersistentDataContainerEmpty() {\n        return true;\n    }\n\n    @Override\n    public void savePersistentDataContainer() {\n        // Do nothing.\n    }\n\n    @Override\n    public void completeMission(Mission<?> mission) {\n        // Do nothing.\n    }\n\n    @Override\n    public void resetMission(Mission<?> mission) {\n        // Do nothing.\n    }\n\n    @Override\n    public boolean hasCompletedMission(Mission<?> mission) {\n        return false;\n    }\n\n    @Override\n    public boolean canCompleteMissionAgain(Mission<?> mission) {\n        return false;\n    }\n\n    @Override\n    public int getAmountMissionCompleted(Mission<?> mission) {\n        return 0;\n    }\n\n    @Override\n    public void setAmountMissionCompleted(Mission<?> mission, int finishCount) {\n        // Do nothing.\n    }\n\n    @Override\n    public List<Mission<?>> getCompletedMissions() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissionsWithAmounts() {\n        return Collections.emptyMap();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java",
    "content": "package com.bgsoftware.superiorskyblock.player.algorithm;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Player;\n\nimport java.util.concurrent.CompletableFuture;\n\npublic class DefaultPlayerTeleportAlgorithm implements PlayerTeleportAlgorithm {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final DefaultPlayerTeleportAlgorithm INSTANCE = new DefaultPlayerTeleportAlgorithm();\n\n    private DefaultPlayerTeleportAlgorithm() {\n\n    }\n\n    public static DefaultPlayerTeleportAlgorithm getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Location location) {\n        CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();\n        EntityTeleports.teleport(player, location, completableFuture::complete);\n        return completableFuture;\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Island island) {\n        return this.teleport(player, island, plugin.getSettings().getWorlds().getDefaultWorldDimension());\n    }\n\n    @Override\n    public CompletableFuture<Boolean> teleport(Player player, Island island, Dimension dimension) {\n        CompletableFuture<Boolean> result = new CompletableFuture<>();\n        IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n            islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world ->\n                    teleportInternal(player, island, dimension, result));\n        });\n        return result;\n    }\n\n    public void teleportInternal(Player player, Island island, Dimension dimension, CompletableFuture<Boolean> result) {\n        Location homeLocation = island.getIslandHome(dimension);\n\n        Preconditions.checkNotNull(homeLocation, \"Cannot find a suitable home location for island \" +\n                island.getUniqueId());\n\n        Log.debug(Debug.TELEPORT_PLAYER, player.getName(), island.getOwner().getName(), dimension);\n\n        EntityTeleports.findIslandSafeLocation(island, dimension).whenComplete((safeSpot, error) -> {\n            if (error != null) {\n                Log.debugResult(Debug.TELEPORT_PLAYER, \"Teleport Location\", null);\n                result.completeExceptionally(error);\n            } else if (safeSpot == null) {\n                Log.debugResult(Debug.TELEPORT_PLAYER, \"Teleport Location\", null);\n                result.complete(false);\n            } else {\n                Log.debugResult(Debug.TELEPORT_PLAYER, \"Teleport Location\", safeSpot);\n                teleport(player, safeSpot).whenComplete((teleport, teleportError) -> {\n                    if (teleportError != null) {\n                        Log.debugResult(Debug.TELEPORT_PLAYER, \"Teleport Result\", false);\n                        result.completeExceptionally(teleportError);\n                    } else {\n                        Log.debugResult(Debug.TELEPORT_PLAYER, \"Teleport Result\", true);\n                        result.complete(teleport);\n                    }\n                });\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.player.builder;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.enums.BorderColor;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Counter;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.mission.MissionReference;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport com.google.common.base.Preconditions;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class SuperiorPlayerBuilderImpl implements SuperiorPlayer.Builder {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public UUID uuid = null;\n    public String name = \"null\";\n    public PlayerRole playerRole = SPlayerRole.guestRole();\n    public int disbands = plugin.getSettings().getDisbandCount();\n    public Locale locale = PlayerLocales.getDefaultLocale();\n    public String textureValue = \"\";\n    public long lastTimeUpdated = -1;\n    public boolean toggledPanel = plugin.getSettings().isDefaultToggledPanel();\n    public boolean islandFly = plugin.getSettings().isDefaultIslandFly();\n    public BorderColor borderColor = BorderColor.safeValue(plugin.getSettings().getDefaultBorderColor(), BorderColor.BLUE);\n    public boolean worldBorderEnabled = plugin.getSettings().isDefaultWorldBorder();\n    public Map<MissionReference, Counter> completedMissions = new LinkedHashMap<>();\n    public byte[] persistentData = new byte[0];\n\n    public SuperiorPlayerBuilderImpl() {\n\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setUniqueId(UUID uuid) {\n        Preconditions.checkNotNull(uuid, \"uuid parameter cannot be null.\");\n        Preconditions.checkState(plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid) == null,\n                \"The provided uuid is not unique.\");\n        this.uuid = uuid;\n        return this;\n    }\n\n    @Override\n    public UUID getUniqueId() {\n        return this.uuid;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setName(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        this.name = name;\n        return this;\n    }\n\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setPlayerRole(PlayerRole playerRole) {\n        Preconditions.checkNotNull(playerRole, \"playerRole parameter cannot be null.\");\n        this.playerRole = playerRole;\n        return this;\n    }\n\n    @Override\n    public PlayerRole getPlayerRole() {\n        return this.playerRole;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setDisbands(int disbands) {\n        this.disbands = disbands;\n        return this;\n    }\n\n    @Override\n    public int getDisbands() {\n        return this.disbands;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setLocale(Locale locale) {\n        Preconditions.checkNotNull(locale, \"locale parameter cannot be null.\");\n        Preconditions.checkArgument(PlayerLocales.isValidLocale(locale), \"Locale \" + locale + \" is not a valid locale.\");\n        this.locale = locale;\n        return this;\n    }\n\n    @Override\n    public Locale getLocale() {\n        return this.locale;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setTextureValue(String textureValue) {\n        Preconditions.checkNotNull(textureValue, \"textureValue parameter cannot be null.\");\n        this.textureValue = textureValue;\n        return this;\n    }\n\n    @Override\n    public String getTextureValue() {\n        return this.textureValue;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setLastTimeUpdated(long lastTimeUpdated) {\n        this.lastTimeUpdated = lastTimeUpdated;\n        return this;\n    }\n\n    @Override\n    public long getLastTimeUpdated() {\n        return this.lastTimeUpdated;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setToggledPanel(boolean toggledPanel) {\n        this.toggledPanel = toggledPanel;\n        return this;\n    }\n\n    @Override\n    public boolean hasToggledPanel() {\n        return this.toggledPanel;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setIslandFly(boolean islandFly) {\n        this.islandFly = islandFly;\n        return this;\n    }\n\n    @Override\n    public boolean hasIslandFly() {\n        return this.islandFly;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setBorderColor(BorderColor borderColor) {\n        Preconditions.checkNotNull(borderColor, \"borderColor parameter cannot be null.\");\n        this.borderColor = borderColor;\n        return this;\n    }\n\n    @Override\n    public BorderColor getBorderColor() {\n        return this.borderColor;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setWorldBorderEnabled(boolean worldBorderEnabled) {\n        this.worldBorderEnabled = worldBorderEnabled;\n        return this;\n    }\n\n    @Override\n    public boolean hasWorldBorderEnabled() {\n        return this.worldBorderEnabled;\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setCompletedMission(Mission<?> mission, int finishCount) {\n        Preconditions.checkNotNull(mission, \"mission parameter cannot be null.\");\n        this.completedMissions.put(new MissionReference(mission), new Counter(finishCount));\n        return this;\n    }\n\n    @Override\n    public Map<Mission<?>, Integer> getCompletedMissions() {\n        Map<Mission<?>, Integer> completedMissions = new LinkedHashMap<>();\n\n        this.completedMissions.forEach((mission, finishCount) -> {\n            if (mission.isValid())\n                completedMissions.put(mission.getMission(), finishCount.get());\n        });\n\n        return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions);\n    }\n\n    @Override\n    public SuperiorPlayer.Builder setPersistentData(byte[] persistentData) {\n        Preconditions.checkNotNull(persistentData, \"persistentData parameter cannot be null.\");\n        this.persistentData = persistentData;\n        return this;\n    }\n\n    @Override\n    public byte[] getPersistentData() {\n        return this.persistentData;\n    }\n\n    @Override\n    public SuperiorPlayer build() {\n        if (this.uuid == null)\n            throw new IllegalStateException(\"Cannot create a player with invalid uuid.\");\n\n        return plugin.getFactory().createPlayer(this);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.player.cache;\n\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache;\nimport com.bgsoftware.superiorskyblock.api.player.cache.PlayerCacheKey;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.BaseCacheImpl;\n\nimport java.util.function.Function;\n\npublic class PlayerCacheImpl implements PlayerCache {\n\n    private final BaseCacheImpl<PlayerCacheKey<?>> cache = new BaseCacheImpl<>(PlayerCacheKey.values());\n\n    private final SuperiorPlayer superiorPlayer;\n\n    public PlayerCacheImpl(SuperiorPlayer superiorPlayer) {\n        this.superiorPlayer = superiorPlayer;\n    }\n\n    @Override\n    public SuperiorPlayer getPlayer() {\n        return this.superiorPlayer;\n    }\n\n    @Override\n    public <T> T store(PlayerCacheKey<T> key, T value) {\n        return this.cache.store(key, value);\n    }\n\n    @Override\n    public <T> T remove(PlayerCacheKey<T> key) {\n        return this.cache.remove(key);\n    }\n\n    @Override\n    public <T> T get(PlayerCacheKey<T> key) {\n        return this.cache.get(key);\n    }\n\n    @Override\n    public <T> T getOrDefault(PlayerCacheKey<T> key, T def) {\n        return this.cache.getOrDefault(key, def);\n    }\n\n    @Override\n    public <T> T computeIfAbsent(PlayerCacheKey<T> key, Function<PlayerCacheKey<T>, T> mappingFunction) {\n        return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/chat/PlayerChat.java",
    "content": "package com.bgsoftware.superiorskyblock.player.chat;\n\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport org.bukkit.entity.Player;\n\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Function;\n\npublic class PlayerChat {\n\n    private static final Map<UUID, PlayerChat> playerChatListeners = new ArrayMap<>();\n    private final Function<String, Boolean> chatConsumer;\n\n    private PlayerChat(Function<String, Boolean> chatConsumer) {\n        this.chatConsumer = chatConsumer;\n    }\n\n    public static PlayerChat getChatListener(Player player) {\n        return playerChatListeners.get(player.getUniqueId());\n    }\n\n    public static void listen(Player player, Function<String, Boolean> onChat) {\n        playerChatListeners.put(player.getUniqueId(), new PlayerChat(onChat));\n    }\n\n    public static void remove(Player player) {\n        playerChatListeners.remove(player.getUniqueId());\n    }\n\n    public boolean supply(String message) {\n        return chatConsumer.apply(message);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/container/DefaultPlayersContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.player.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class DefaultPlayersContainer implements PlayersContainer {\n\n    private final Map<UUID, SuperiorPlayer> players = new ConcurrentHashMap<>();\n    private final Map<String, SuperiorPlayer> playersByNames = new ConcurrentHashMap<>();\n\n    @Nullable\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(String name) {\n        SuperiorPlayer superiorPlayer = this.playersByNames.get(name.toLowerCase(Locale.ENGLISH));\n\n        if (superiorPlayer == null) {\n            superiorPlayer = players.values().stream()\n                    .filter(player -> player.getName().equalsIgnoreCase(name))\n                    .findFirst().orElse(null);\n            if (superiorPlayer != null)\n                this.playersByNames.put(name.toLowerCase(Locale.ENGLISH), superiorPlayer);\n        }\n\n        return superiorPlayer;\n    }\n\n    @Nullable\n    @Override\n    public SuperiorPlayer getSuperiorPlayer(UUID uuid) {\n        return this.players.get(uuid);\n    }\n\n    @Override\n    public List<SuperiorPlayer> getAllPlayers() {\n        return new SequentialListBuilder<SuperiorPlayer>().build(this.players.values());\n    }\n\n    @Override\n    public void addPlayer(SuperiorPlayer superiorPlayer) {\n        this.players.put(superiorPlayer.getUniqueId(), superiorPlayer);\n        String playerName = superiorPlayer.getName();\n        if (!playerName.equals(\"null\"))\n            this.playersByNames.put(playerName.toLowerCase(Locale.ENGLISH), superiorPlayer);\n    }\n\n    @Override\n    public void removePlayer(SuperiorPlayer superiorPlayer) {\n        this.players.remove(superiorPlayer.getUniqueId());\n        this.playersByNames.remove(superiorPlayer.getName().toLowerCase(Locale.ENGLISH));\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java",
    "content": "package com.bgsoftware.superiorskyblock.player.inventory;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.entity.Player;\nimport org.bukkit.potion.PotionEffect;\n\nimport java.util.Collection;\n\npublic class ClearActions {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static final ClearAction EFFECTS = register(new ClearAction(\"EFFECTS\") {\n\n        @Override\n        public void doClear(Player player) {\n            for (PotionEffect potionEffect : player.getActivePotionEffects())\n                player.removePotionEffect(potionEffect.getType());\n        }\n\n    });\n\n    public static final ClearAction ENDER_CHEST = register(new ClearAction(\"ENDER_CHEST\") {\n\n        @Override\n        public void doClear(Player player) {\n            player.getEnderChest().clear();\n        }\n\n    });\n\n    public static final ClearAction EXPERIENCE = register(new ClearAction(\"EXPERIENCE\") {\n\n        @Override\n        public void doClear(Player player) {\n            player.setExp(0);\n            player.setLevel(0);\n            player.setTotalExperience(0);\n        }\n\n    });\n\n    public static final ClearAction HEALTH = register(new ClearAction(\"HEALTH\") {\n\n        @Override\n        public void doClear(Player player) {\n            player.setHealth(player.getMaxHealth());\n        }\n\n    });\n\n    public static final ClearAction HUNGER = register(new ClearAction(\"HUNGER\") {\n\n        @Override\n        public void doClear(Player player) {\n            player.setFoodLevel(20);\n        }\n\n    });\n\n    public static final ClearAction INVENTORY = register(new ClearAction(\"INVENTORY\") {\n\n        @Override\n        public void doClear(Player player) {\n            player.getInventory().clear();\n        }\n\n    });\n\n    private ClearActions() {\n\n    }\n\n    public static void registerActions() {\n        // Do nothing, only trigger all the register calls\n    }\n\n    public static void runClearActions(SuperiorPlayer superiorPlayer, Collection<ClearAction> clearActions,\n                                       @Nullable Island islandToTeleport) {\n        if (clearActions.isEmpty() && islandToTeleport == null)\n            return;\n\n        OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer();\n        OfflinePlayerData offlinePlayerData;\n        Player onlinePlayer;\n\n        if (offlinePlayer.isOnline()) {\n            offlinePlayerData = null;\n            onlinePlayer = offlinePlayer.getPlayer();\n        } else {\n            offlinePlayerData = plugin.getNMSPlayers().createOfflinePlayerData(offlinePlayer);\n            onlinePlayer = offlinePlayerData.getFakeOnlinePlayer();\n        }\n\n        try {\n            clearActions.forEach(clearAction -> clearAction.doClear(onlinePlayer));\n\n            if (offlinePlayerData != null) {\n                if (islandToTeleport != null)\n                    offlinePlayerData.setLocation(islandToTeleport.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()));\n                offlinePlayerData.applyChanges();\n            } else if (islandToTeleport != null) {\n                superiorPlayer.teleport(islandToTeleport);\n            }\n        } finally {\n            if (offlinePlayerData != null)\n                offlinePlayerData.release();\n        }\n    }\n\n    private static ClearAction register(ClearAction clearAction) {\n        ClearAction.register(clearAction);\n        return clearAction;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java",
    "content": "package com.bgsoftware.superiorskyblock.player.permissions;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport org.bukkit.entity.Player;\n\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.StampedLock;\n\npublic class PlayerPermissionsStore {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final Map<UUID, PlayerPermissionsStore> PERMISSIONS_STORE_MAP = new ConcurrentHashMap<>();\n\n    private final EnumerateMap<IslandPrivilege, Boolean> bypassPermissionsStore = new EnumerateMap<>(IslandPrivilege.values());\n    private final Map<String, Boolean> customPermissionsStore = new ConcurrentHashMap<>();\n    private final StampedLock lock = new StampedLock();\n\n    private final AtomicBoolean dirty = new AtomicBoolean(true);\n\n    @Nullable\n    public static PlayerPermissionsStore getPermissionsStore(UUID uuid) {\n        return PERMISSIONS_STORE_MAP.get(uuid);\n    }\n\n    public PlayerPermissionsStore(SuperiorPlayer superiorPlayer) {\n        PERMISSIONS_STORE_MAP.put(superiorPlayer.getUniqueId(), this);\n    }\n\n    public void markDirty() {\n        this.dirty.set(true);\n    }\n\n    public void refreshCache(Player player) {\n        // We want to refresh cache for common permissions\n        hasBypassPermission(player, IslandPrivileges.BUILD);\n        hasBypassPermission(player, IslandPrivileges.BREAK);\n        hasCustomPermission(player, \"superior.admin.bypass.*\");\n    }\n\n    public PermissionResult hasBypassPermission(@Nullable Player player, IslandPrivilege islandPrivilege) {\n        if (this.dirty.get()) {\n            checkDirty();\n        }\n\n        long stamp = this.lock.readLock();\n        Boolean value;\n        try {\n            value = this.bypassPermissionsStore.get(islandPrivilege);\n        } finally {\n            this.lock.unlockRead(stamp);\n        }\n\n        if (value == null) {\n            if (player == null) return PermissionResult.NOT_ONLINE;\n\n            value = checkPermission(player, \"superior.admin.bypass.\" + islandPrivilege.getName());\n\n            stamp = this.lock.writeLock();\n            try {\n                this.bypassPermissionsStore.put(islandPrivilege, value);\n            } finally {\n                this.lock.unlockWrite(stamp);\n            }\n        }\n\n        return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED;\n    }\n\n    public PermissionResult hasCustomPermission(@Nullable Player player, String permission) {\n        long stamp = this.lock.tryOptimisticRead();\n        Boolean value = this.customPermissionsStore.get(permission);\n        boolean isDirty = this.dirty.get();\n\n        if (!this.lock.validate(stamp) || isDirty) {\n            if (isDirty) {\n                checkDirty();\n            }\n\n            stamp = this.lock.readLock();\n            try {\n                value = this.customPermissionsStore.get(permission);\n            } finally {\n                this.lock.unlockRead(stamp);\n            }\n        }\n\n        if (value == null) {\n            if (player == null) return PermissionResult.NOT_ONLINE;\n\n            value = checkPermission(player, permission);\n\n            stamp = this.lock.writeLock();\n            try {\n                this.customPermissionsStore.put(permission, value);\n            } finally {\n                this.lock.unlockWrite(stamp);\n            }\n        }\n\n        return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED;\n    }\n\n    private void checkDirty() {\n        if (dirty.compareAndSet(true, false)) {\n            long stamp = this.lock.writeLock();\n            try {\n                this.bypassPermissionsStore.clear();\n                this.customPermissionsStore.clear();\n            } finally {\n                this.lock.unlockWrite(stamp);\n            }\n        }\n    }\n\n    private static boolean checkPermission(Player player, String permission) {\n        return plugin.getProviders().getPermissionsProvider().hasPermission(player, permission);\n    }\n\n    public enum PermissionResult {\n\n        PRIVILEGED,\n        RESTRICTED,\n        NOT_ONLINE\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java",
    "content": "package com.bgsoftware.superiorskyblock.player.respawn;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.player.PlayerRespawnEvent;\n\npublic class RespawnActions {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    public static final RespawnAction BED_TELEPORT = register(new RespawnAction(\"BED_TELEPORT\") {\n\n        @Override\n        public boolean canPerform(PlayerRespawnEvent event) {\n            Player player = event.getPlayer();\n            return player.getBedSpawnLocation() != null;\n        }\n\n        @Override\n        public void perform(PlayerRespawnEvent event) {\n            event.setRespawnLocation(event.getPlayer().getBedSpawnLocation());\n        }\n\n    });\n\n    public static final RespawnAction ISLAND_TELEPORT = register(new RespawnAction(\"ISLAND_TELEPORT\") {\n\n        @Override\n        public boolean canPerform(PlayerRespawnEvent event) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer());\n            return superiorPlayer.getIsland() != null;\n        }\n\n        @Override\n        public void perform(PlayerRespawnEvent event) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer());\n            assert superiorPlayer.getIsland() != null;\n            superiorPlayer.teleport(superiorPlayer.getIsland(),\n                    result -> onTeleportCallback(superiorPlayer, result));\n        }\n\n    });\n\n    public static final RespawnAction SPAWN_TELEPORT = register(new RespawnAction(\"SPAWN_TELEPORT\") {\n\n        @Override\n        public boolean canPerform(PlayerRespawnEvent event) {\n            return true;\n        }\n\n        @Override\n        public void perform(PlayerRespawnEvent event) {\n            SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer());\n            superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(),\n                    result -> onTeleportCallback(superiorPlayer, result));\n        }\n\n    });\n\n    public static final RespawnAction VANILLA = register(new RespawnAction(\"VANILLA\") {\n\n        @Override\n        public boolean canPerform(PlayerRespawnEvent event) {\n            return true;\n        }\n\n        @Override\n        public void perform(PlayerRespawnEvent event) {\n            // Do nothing, let vanilla do its thing.\n        }\n\n    });\n\n    private RespawnActions() {\n\n    }\n\n    public static void registerActions() {\n        // Do nothing, only trigger all the register calls\n    }\n\n    private static RespawnAction register(RespawnAction respawnAction) {\n        RespawnAction.register(respawnAction);\n        return respawnAction;\n    }\n\n    private static void onTeleportCallback(SuperiorPlayer superiorPlayer, boolean result) {\n        if (result) {\n            BukkitExecutor.sync(() -> {\n                if (superiorPlayer.isOnline())\n                    superiorPlayer.updateWorldBorder(superiorPlayer.getIsland());\n            }, 2L);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/IService.java",
    "content": "package com.bgsoftware.superiorskyblock.service;\n\npublic interface IService {\n\n    Class<?> getAPIClass();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/ServicesHandler.java",
    "content": "package com.bgsoftware.superiorskyblock.service;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.service.bossbar.BossBarsServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.dragon.DragonBattleServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.hologram.HologramsServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.portals.PortalsManagerServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksInteractionServiceImpl;\nimport com.bgsoftware.superiorskyblock.service.world.WorldRecordServiceImpl;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Bukkit;\nimport org.bukkit.plugin.ServicePriority;\n\nimport java.util.IdentityHashMap;\nimport java.util.Map;\n\npublic class ServicesHandler {\n\n    private final Map<Class<?>, IService> services = new IdentityHashMap<>();\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public ServicesHandler(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public <T> T getService(Class<T> serviceClass) {\n        Object service = services.get(serviceClass);\n        if (service == null)\n            throw new RuntimeException(\"Tried to get service of invalid class: \" + serviceClass);\n\n        return serviceClass.cast(service);\n    }\n\n    public void loadDefaultServices(SuperiorSkyblockPlugin plugin) {\n        registerService(new PlaceholdersServiceImpl());\n        registerService(new HologramsServiceImpl(plugin));\n        registerService(new DragonBattleServiceImpl(plugin));\n        registerService(new BossBarsServiceImpl(plugin));\n        registerService(new MessagesServiceImpl());\n        registerService(new PortalsManagerServiceImpl(plugin));\n        registerService(new RegionManagerServiceImpl(plugin));\n        registerService(new StackedBlocksInteractionServiceImpl(plugin));\n        registerService(new WorldRecordServiceImpl(plugin));\n    }\n\n    private <T extends IService> void registerService(T serviceImpl) {\n        Class apiClass = serviceImpl.getAPIClass();\n\n        Preconditions.checkArgument(!services.containsKey(apiClass), \"Service for class \" + apiClass + \" already exists.\");\n\n        services.put(apiClass, serviceImpl);\n        Bukkit.getServicesManager().register(apiClass, serviceImpl, plugin, ServicePriority.Normal);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/BossBarTask.java",
    "content": "package com.bgsoftware.superiorskyblock.service.bossbar;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.core.collections.ArrayMap;\nimport org.bukkit.entity.Player;\nimport org.bukkit.scheduler.BukkitRunnable;\n\nimport java.util.LinkedList;\nimport java.util.Map;\nimport java.util.Queue;\nimport java.util.UUID;\n\npublic class BossBarTask extends BukkitRunnable {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final BossBarTask EMPTY_TASK = new BossBarTask(EmptyBossBar.getInstance(), 0);\n\n    private static final Map<UUID, Queue<BossBarTask>> PLAYERS_RUNNING_TASKS = new ArrayMap<>();\n\n    private final BossBar bossBar;\n    private final double progressToRemovePerTick;\n    private boolean reachedEndTask = false;\n\n    public static BossBarTask create(BossBar bossBar, double ticksToRun) {\n        return ticksToRun <= 0 ? EMPTY_TASK : new BossBarTask(bossBar, ticksToRun);\n    }\n\n    private BossBarTask(BossBar bossBar, double ticksToRun) {\n        this.bossBar = bossBar;\n        this.progressToRemovePerTick = this.bossBar.getProgress() / ticksToRun;\n        if (progressToRemovePerTick > 0) {\n            runTaskTimer(plugin, 1L, 1L);\n        }\n    }\n\n    @Override\n    public void run() {\n        if (reachedEndTask) {\n            cancel();\n        } else {\n            this.bossBar.setProgress(Math.max(0D, this.bossBar.getProgress() - progressToRemovePerTick));\n            reachedEndTask = this.bossBar.getProgress() == 0D;\n        }\n    }\n\n    @Override\n    public synchronized void cancel() throws IllegalStateException {\n        this.bossBar.removeAll();\n        super.cancel();\n    }\n\n    public void registerTask(Player player) {\n        Queue<BossBarTask> bossBarTasks = PLAYERS_RUNNING_TASKS.computeIfAbsent(player.getUniqueId(), s -> new LinkedList<>());\n\n        if (bossBarTasks.size() >= plugin.getSettings().getBossbarLimit()) {\n            BossBarTask lastRunningTask = bossBarTasks.poll();\n            if (lastRunningTask != null)\n                lastRunningTask.cancel();\n        }\n\n        bossBarTasks.add(this);\n    }\n\n    public void unregisterTask(Player player) {\n        Queue<BossBarTask> bossBarTasks = PLAYERS_RUNNING_TASKS.get(player.getUniqueId());\n\n        if (bossBarTasks == null)\n            return;\n\n        bossBarTasks.remove(this);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/BossBarsServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.bossbar;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBarsService;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport org.bukkit.entity.Player;\n\npublic class BossBarsServiceImpl implements BossBarsService, IService {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public BossBarsServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return BossBarsService.class;\n    }\n\n    @Override\n    public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) {\n        return plugin.getNMSPlayers().createBossBar(player, message, color, ticksToRun);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/EmptyBossBar.java",
    "content": "package com.bgsoftware.superiorskyblock.service.bossbar;\n\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport org.bukkit.entity.Player;\n\npublic class EmptyBossBar implements BossBar {\n\n    private static final EmptyBossBar INSTANCE = new EmptyBossBar();\n\n    public static EmptyBossBar getInstance() {\n        return INSTANCE;\n    }\n\n    private EmptyBossBar() {\n\n    }\n\n    @Override\n    public void addPlayer(Player player) {\n\n    }\n\n    @Override\n    public void removeAll() {\n\n    }\n\n    @Override\n    public void setProgress(double progress) {\n\n    }\n\n    @Override\n    public double getProgress() {\n        return 0;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.dragon;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleResetResult;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.entity.EnderDragon;\n\npublic class DragonBattleServiceImpl implements DragonBattleService, IService {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public DragonBattleServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return DragonBattleService.class;\n    }\n\n    @Override\n    public void prepareEndWorld(World bukkitWorld) {\n        Preconditions.checkNotNull(bukkitWorld, \"world parameter cannot be null\");\n        Preconditions.checkArgument(bukkitWorld.getEnvironment() == World.Environment.THE_END, \"world must be the_end environment\");\n        plugin.getNMSDragonFight().prepareEndWorld(bukkitWorld);\n    }\n\n    @Nullable\n    @Override\n    public EnderDragon getEnderDragon(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n        Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, \"dimension must be the_end environment\");\n\n        return plugin.getNMSDragonFight().getEnderDragon(island, dimension);\n    }\n\n    @Override\n    public void stopEnderDragonBattle(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n        Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, \"dimension must be the_end environment\");\n\n        plugin.getNMSDragonFight().removeDragonBattle(island, dimension);\n    }\n\n    @Override\n    public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension) {\n        Preconditions.checkNotNull(island, \"island parameter cannot be null\");\n        Preconditions.checkNotNull(dimension, \"dimension parameter cannot be null\");\n        Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, \"dimension must be the_end environment\");\n\n        SettingsManager.Worlds.End dimensionConfig = (SettingsManager.Worlds.End) plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n\n        if (dimensionConfig == null || !dimensionConfig.isEnabled() || !dimensionConfig.isDragonFight())\n            return DragonBattleResetResult.DRAGON_BATTLES_DISABLED;\n\n        if (!island.isDimensionEnabled(dimension))\n            return DragonBattleResetResult.WORLD_NOT_UNLOCKED;\n\n        if (!island.wasSchematicGenerated(dimension))\n            return DragonBattleResetResult.WORLD_NOT_GENERATED;\n\n        stopEnderDragonBattle(island, dimension);\n\n        IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n            islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> {\n                Location islandCenter = island.getCenter(dimension);\n                plugin.getNMSDragonFight().startDragonBattle(island,\n                        dimensionConfig.getPortalOffset().applyToLocation(islandCenter));\n            });\n        });\n\n        return DragonBattleResetResult.SUCCESS;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/hologram/HologramsServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.hologram;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.Hologram;\nimport com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport org.bukkit.Location;\nimport org.bukkit.entity.Entity;\n\npublic class HologramsServiceImpl implements HologramsService, IService {\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public HologramsServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return HologramsService.class;\n    }\n\n    @Override\n    public Hologram createHologram(Location location) {\n        return plugin.getNMSHolograms().createHologram(location);\n    }\n\n    @Override\n    public boolean isHologram(Entity entity) {\n        return plugin.getNMSHolograms().isHologram(entity);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.message;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar;\nimport com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent;\nimport com.bgsoftware.superiorskyblock.api.service.message.MessagesService;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.GameSoundImpl;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.messages.component.MultipleComponents;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.ActionBarComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.BossBarComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.RawMessageComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.SoundComponent;\nimport com.bgsoftware.superiorskyblock.core.messages.component.impl.TitleComponent;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.google.common.base.Preconditions;\nimport net.md_5.bungee.api.chat.BaseComponent;\nimport net.md_5.bungee.api.chat.TextComponent;\nimport org.bukkit.Sound;\nimport org.bukkit.configuration.file.YamlConfiguration;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\n\npublic class MessagesServiceImpl implements MessagesService, IService {\n\n    private final List<CustomComponentParser> customComponentParsers = new LinkedList<>();\n\n    public MessagesServiceImpl() {\n\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return MessagesService.class;\n    }\n\n    @Nullable\n    @Override\n    public IMessageComponent parseComponent(YamlConfiguration config, String path) {\n        if (config.isConfigurationSection(path)) {\n            return MultipleComponents.parseSection(config.getConfigurationSection(path), this.customComponentParsers);\n        } else {\n            for (CustomComponentParser parser : this.customComponentParsers) {\n                Optional<IMessageComponent> res = parser.parse(config, path);\n                if (res.isPresent())\n                    return res.get();\n            }\n            return RawMessageComponent.of(Formatters.COLOR_FORMATTER.format(config.getString(path, \"\")));\n        }\n    }\n\n    @Nullable\n    @Override\n    public IMessageComponent getComponent(String messageName, Locale locale) {\n        Message message = EnumHelper.getEnum(Message.class, messageName.toUpperCase(Locale.ENGLISH));\n        return message == null || message.isCustom() ? null : message.getComponent(locale);\n    }\n\n    @Override\n    public Builder newBuilder() {\n        return new BuilderImpl();\n    }\n\n    public void registerCustomComponentParser(CustomComponentParser parser) {\n        this.customComponentParsers.add(parser);\n    }\n\n    public List<CustomComponentParser> getCustomComponentParsers() {\n        return customComponentParsers;\n    }\n\n    public interface CustomComponentParser {\n\n        Optional<IMessageComponent> parse(YamlConfiguration config, String path);\n\n        Optional<IMessageComponent> parse(String raw);\n\n    }\n\n    private static class BuilderImpl implements Builder {\n\n        private final List<IMessageComponent> messageComponents = new LinkedList<>();\n\n        @Override\n        public boolean addActionBar(@Nullable String message) {\n            return addMessageComponent(ActionBarComponent.of(message));\n        }\n\n        @Override\n        public boolean addBossBar(@Nullable String message, BossBar.Color color, int ticks) {\n            return addMessageComponent(BossBarComponent.of(message, color, ticks));\n        }\n\n        @Override\n        public boolean addComplexMessage(@Nullable TextComponent textComponent) {\n            return addComplexMessage(new BaseComponent[]{textComponent});\n        }\n\n        @Override\n        public boolean addComplexMessage(@Nullable BaseComponent[] baseComponents) {\n            return addMessageComponent(ComplexMessageComponent.of(baseComponents));\n        }\n\n        @Override\n        public boolean addRawMessage(@Nullable String message) {\n            return addMessageComponent(RawMessageComponent.of(message));\n        }\n\n        @Override\n        public boolean addSound(Sound sound, float volume, float pitch) {\n            return addMessageComponent(SoundComponent.of(new GameSoundImpl(sound, volume, pitch)));\n        }\n\n        @Override\n        public boolean addTitle(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) {\n            return addMessageComponent(TitleComponent.of(titleMessage, subtitleMessage, fadeIn, duration, fadeOut));\n        }\n\n        @Override\n        public boolean addMessageComponent(IMessageComponent messageComponent) {\n            Preconditions.checkNotNull(messageComponent, \"Cannot add null message components.\");\n\n            if (messageComponent.getType() != IMessageComponent.Type.EMPTY) {\n                messageComponents.add(messageComponent);\n                return true;\n            }\n\n            return false;\n        }\n\n        @Override\n        public IMessageComponent build() {\n            return MultipleComponents.of(messageComponents);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.placeholders;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.island.PlayerRole;\nimport com.bgsoftware.superiorskyblock.api.island.SortingType;\nimport com.bgsoftware.superiorskyblock.api.missions.Mission;\nimport com.bgsoftware.superiorskyblock.api.objects.Pair;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.IslandPlaceholderParser;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService;\nimport com.bgsoftware.superiorskyblock.api.service.placeholders.PlayerPlaceholderParser;\nimport com.bgsoftware.superiorskyblock.api.upgrades.Upgrade;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.values.BlockValue;\nimport com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.island.role.SPlayerRole;\nimport com.bgsoftware.superiorskyblock.island.top.SortingTypes;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.google.common.collect.ImmutableMap;\nimport org.bukkit.Location;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.potion.PotionEffectType;\n\nimport java.math.BigDecimal;\nimport java.time.Duration;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class PlaceholdersServiceImpl implements PlaceholdersService, IService {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final Pattern ISLAND_PLACEHOLDER_PATTERN = Pattern.compile(\"island_(.+)\");\n    private static final Pattern PLAYER_PLACEHOLDER_PATTERN = Pattern.compile(\"player_(.+)\");\n\n    private static final Pattern BLOCK_COUNT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_count_(.+)\");\n    private static final Pattern BLOCK_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_level_(.+)\");\n    private static final Pattern BLOCK_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_limit_(.+)\");\n    private static final Pattern BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_total_level_(.+)\");\n    private static final Pattern BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_total_worth_(.+)\");\n    private static final Pattern BLOCK_WORTH_PLACEHOLDER_PATTERN = Pattern.compile(\"island_block_worth_(.+)\");\n    private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_count_(.+)\");\n    private static final Pattern DATA_PLACEHOLDER_PATTERN = Pattern.compile(\"island_data_(.+)\");\n    private static final Pattern EFFECT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_effect_(.+)\");\n    private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_entity_count_(.+)\");\n    private static final Pattern ENTITY_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_entity_limit_(.+)\");\n    private static final Pattern FLAG_PLACEHOLDER_PATTERN = Pattern.compile(\"flag_(.+)\");\n    private static final Pattern GENERATOR_AMOUNT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_generator_amount_(.+)\");\n    private static final Pattern GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN = Pattern.compile(\"island_generator_percentage_(.+)\");\n    private static final Pattern WORLD_UNLOCKED_PLACEHOLDER_PATTERN = Pattern.compile(\"island_world_unlocked_(.+)\");\n    private static final Pattern WORLD_ENABLED_PLACEHOLDER_PATTERN = Pattern.compile(\"island_world_enabled_(.+)\");\n    private static final Pattern WORLD_GENERATED_PLACEHOLDER_PATTERN = Pattern.compile(\"island_world_generated_(.+)\");\n    private static final Pattern MEMBER_PLACEHOLDER_PATTERN = Pattern.compile(\"member_(.+)\");\n    private static final Pattern MISSIONS_COMPLETED_PATTERN = Pattern.compile(\"missions_completed_(.+)\");\n    private static final Pattern MISSION_STATUS_PATTERN = Pattern.compile(\"mission_status_(.+)\");\n    private static final Pattern PERMISSION_PLACEHOLDER_PATTERN = Pattern.compile(\"island_permission_(.+)\");\n    private static final Pattern PERMISSION_ROLE_PLACEHOLDER_PATTERN = Pattern.compile(\"island_permission_role_(.+)\");\n    private static final Pattern ROLE_COUNT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_role_count_(.+)\");\n    private static final Pattern ROLE_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile(\"island_role_limit_(.+)\");\n    private static final Pattern UPGRADE_PLACEHOLDER_PATTERN = Pattern.compile(\"island_upgrade_(.+)\");\n    private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile(\"island_top_(.+)\");\n    private static final Pattern TOP_WORTH_PLACEHOLDER_PATTERN = Pattern.compile(\"worth_(.+)\");\n    private static final Pattern TOP_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile(\"level_(.+)\");\n    private static final Pattern TOP_RATING_PLACEHOLDER_PATTERN = Pattern.compile(\"rating_(.+)\");\n    private static final Pattern TOP_PLAYERS_PLACEHOLDER_PATTERN = Pattern.compile(\"players_(.+)\");\n    private static final Pattern TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN = Pattern.compile(\"value_format_(.+)\");\n    private static final Pattern TOP_VALUE_RAW_PLACEHOLDER_PATTERN = Pattern.compile(\"value_raw_(.+)\");\n    private static final Pattern TOP_VALUE_PLACEHOLDER_PATTERN = Pattern.compile(\"value_(.+)\");\n    private static final Pattern TOP_LEADER_PLACEHOLDER_PATTERN = Pattern.compile(\"leader_(.+)\");\n    private static final Pattern TOP_CUSTOM_PLACEHOLDER_PATTERN = Pattern.compile(\"(\\\\d+)_(.+)\");\n    private static final Pattern VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN = Pattern.compile(\"visitor_last_join_(.+)\");\n\n    private static final Map<String, PlayerPlaceholderParser> PLAYER_PARSES =\n            new ImmutableMap.Builder<String, PlayerPlaceholderParser>()\n                    .put(\"blocks_stacker\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBlocksStackerEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"border_color\", superiorPlayer ->\n                            Formatters.BORDER_COLOR_FORMATTER.format(superiorPlayer.getBorderColor(), superiorPlayer.getUserLocale()))\n                    .put(\"bypass\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBypassModeEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"chat_spy\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasAdminSpyEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"disbands\", superiorPlayer ->\n                            superiorPlayer.getDisbands() + \"\")\n                    .put(\"fly\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasIslandFlyEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"locale\", superiorPlayer ->\n                            Formatters.LOCALE_FORMATTER.format(superiorPlayer.getUserLocale()))\n                    .put(\"missions_completed\", superiorPlayer ->\n                            superiorPlayer.getCompletedMissions().size() + \"\")\n                    .put(\"panel\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasToggledPanel(), superiorPlayer.getUserLocale()))\n                    .put(\"role\", superiorPlayer ->\n                            superiorPlayer.getPlayerRole().toString())\n                    .put(\"role_display\", superiorPlayer ->\n                            superiorPlayer.getPlayerRole().getDisplayName())\n                    .put(\"schematics\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasSchematicModeEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"team_chat\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasTeamChatEnabled(), superiorPlayer.getUserLocale()))\n                    .put(\"texture\", SuperiorPlayer::getTextureValue)\n                    .put(\"world_border\", superiorPlayer ->\n                            Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasWorldBorderEnabled(), superiorPlayer.getUserLocale()))\n                    .build();\n\n    @SuppressWarnings(\"ConstantConditions\")\n    private static final Map<String, IslandPlaceholderParser> ISLAND_PARSES =\n            new ImmutableMap.Builder<String, IslandPlaceholderParser>()\n                    // Island Placeholders\n                    .put(\"bank\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance()))\n                    .put(\"bank_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), superiorPlayer.getUserLocale()))\n                    .put(\"bank_int\", (island, superiorPlayer) ->\n                            island.getIslandBank().getBalance().toBigInteger().toString())\n                    .put(\"bank_raw\", (island, superiorPlayer) ->\n                            island.getIslandBank().getBalance().toString())\n                    .put(\"bank_limit\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getBankLimit()))\n                    .put(\"bank_limit_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), superiorPlayer.getUserLocale()))\n                    .put(\"bank_limit_int\", (island, superiorPlayer) ->\n                            island.getBankLimit().toBigInteger().toString())\n                    .put(\"bank_limit_raw\", (island, superiorPlayer) ->\n                            island.getBankLimit().toString())\n                    .put(\"bank_last_interest\", (island, superiorPlayer) ->\n                            Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastInterestTime()), superiorPlayer.getUserLocale()))\n                    .put(\"bank_next_interest\", (island, superiorPlayer) ->\n                            Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getNextInterest()), superiorPlayer.getUserLocale()))\n                    .put(\"bans_count\", (island, superiorPlayer) ->\n                            island.getBannedPlayers().size() + \"\")\n                    .put(\"bans_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getBannedPlayers();\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"biome\", (island, superiorPlayer) ->\n                            Formatters.CAPITALIZED_FORMATTER.format(island.getBiome().name()))\n                    .put(\"bonus_level\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getBonusLevel()))\n                    .put(\"bonus_level_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusLevel(), superiorPlayer.getUserLocale()))\n                    .put(\"bonus_level_int\", (island, superiorPlayer) ->\n                            island.getBonusLevel().toBigInteger().toString())\n                    .put(\"bonus_level_raw\", (island, superiorPlayer) ->\n                            island.getBonusLevel().toString())\n                    .put(\"bonus_worth\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getBonusWorth()))\n                    .put(\"bonus_worth_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusWorth(), superiorPlayer.getUserLocale()))\n                    .put(\"bonus_worth_int\", (island, superiorPlayer) ->\n                            island.getBonusWorth().toBigInteger().toString())\n                    .put(\"bonus_worth_raw\", (island, superiorPlayer) ->\n                            island.getBonusWorth().toString())\n                    .put(\"center\", (island, superiorPlayer) ->\n                            Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), getDefaultWorldInfo(island)))\n                    .put(\"center_x\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getX() + \"\")\n                    .put(\"center_y\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getY() + \"\")\n                    .put(\"center_z\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getZ() + \"\")\n                    .put(\"chest_size\", (island, superiorPlayer) ->\n                            island.getChestSize() + \"\")\n                    .put(\"coop_limit\", (island, superiorPlayer) ->\n                            island.getCoopLimit() + \"\")\n                    .put(\"coop_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getCoopPlayers();\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"coop_size\", (island, superiorPlayer) ->\n                            island.getCoopPlayers().size() + \"\")\n                    .put(\"creation_time\", (island, superiorPlayer) ->\n                            island.getCreationTimeDate())\n                    .put(\"crops_multiplier\", (island, superiorPlayer) ->\n                            island.getCropGrowthMultiplier() + \"\")\n                    .put(\"description\", (island, superiorPlayer) ->\n                            island.getDescription())\n                    .put(\"discord\", (island, superiorPlayer) ->\n                            island.hasPermission(superiorPlayer, IslandPrivileges.DISCORD_SHOW) ? island.getDiscord() : \"None\")\n                    .put(\"discord_all\", (island, superiorPlayer) ->\n                            island.getDiscord())\n                    .put(\"drops_multiplier\", (island, superiorPlayer) ->\n                            island.getMobDropsMultiplier() + \"\")\n                    .put(\"exists\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale()))\n                    .put(\"home\", (island, superiorPlayer) -> {\n                        WorldInfo worldInfo = getDefaultWorldInfo(island);\n                        return Formatters.LOCATION_FORMATTER.format(island.getIslandHomePosition(worldInfo.getDimension()).toLocation(worldInfo));\n                    })\n                    .put(\"home_x\", (island, superiorPlayer) ->\n                            island.getIslandHomePosition(getDefaultWorldDimension()).getX() + \"\")\n                    .put(\"home_y\", (island, superiorPlayer) ->\n                            island.getIslandHomePosition(getDefaultWorldDimension()).getY() + \"\")\n                    .put(\"home_z\", (island, superiorPlayer) ->\n                            island.getIslandHomePosition(getDefaultWorldDimension()).getZ() + \"\")\n                    .put(\"is_coop\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island.isCoop(superiorPlayer), superiorPlayer.getUserLocale()))\n                    .put(\"is_leader\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island.getOwner().equals(superiorPlayer), superiorPlayer.getUserLocale()))\n                    .put(\"is_member\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island.isMember(superiorPlayer), superiorPlayer.getUserLocale()))\n                    .put(\"is_visitor\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island.isVisitor(superiorPlayer, true), superiorPlayer.getUserLocale()))\n                    .put(\"last_time_updated\", (island, superiorPlayer) ->\n                            Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastTimeUpdate()), superiorPlayer.getUserLocale()))\n                    .put(\"leader\", (island, superiorPlayer) ->\n                            island.getOwner().getName())\n                    .put(\"level\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getIslandLevel()))\n                    .put(\"level_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), superiorPlayer.getUserLocale()))\n                    .put(\"level_int\", (island, superiorPlayer) ->\n                            island.getIslandLevel().toBigInteger().toString())\n                    .put(\"level_raw\", (island, superiorPlayer) ->\n                            island.getIslandLevel().toString())\n                    .put(\"locked\", (island, superiorPlayer) ->\n                            Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale()))\n                    .put(\"missions_completed\", (island, superiorPlayer) ->\n                            island.getCompletedMissions().size() + \"\")\n                    .put(\"name\", (island, superiorPlayer) -> island.getName())\n                    .put(\"name_formatted\", (island, superiorPlayer) -> island.getFormattedName())\n                    .put(\"name_leader\", (island, superiorPlayer) ->\n                            island.getName().isEmpty() ? island.getOwner().getName() : island.getName())\n                    .put(\"name_stripped\", (island, superiorPlayer) -> island.getStrippedName())\n                    .put(\"paypal\", (island, superiorPlayer) ->\n                            island.hasPermission(superiorPlayer, IslandPrivileges.PAYPAL_SHOW) ? island.getPaypal() : \"None\")\n                    .put(\"paypal_all\", (island, superiorPlayer) ->\n                            island.getPaypal())\n                    .put(\"players_count\", (island, superiorPlayer) ->\n                            island.getAllPlayersInside().size() + \"\")\n                    .put(\"players_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getAllPlayersInside();\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"radius\", (island, superiorPlayer) ->\n                            island.getIslandSize() + \"\")\n                    .put(\"rating\", (island, superiorPlayer) ->\n                            island.getTotalRating() + \"\")\n                    .put(\"rating_amount\", (island, superiorPlayer) ->\n                            island.getRatingAmount() + \"\")\n                    .put(\"rating_stars\", (island, superiorPlayer) ->\n                            Formatters.RATING_FORMATTER.format(island.getTotalRating(), superiorPlayer.getUserLocale()))\n                    .put(\"raw_bank_limit\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getBankLimitRaw()))\n                    .put(\"raw_bank_limit_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimitRaw(), superiorPlayer.getUserLocale()))\n                    .put(\"raw_bank_limit_int\", (island, superiorPlayer) ->\n                            island.getBankLimitRaw().toBigInteger().toString())\n                    .put(\"raw_bank_limit_raw\", (island, superiorPlayer) ->\n                            island.getBankLimitRaw().toString())\n                    .put(\"raw_coop_limit\", (island, superiorPlayer) ->\n                            island.getCoopLimitRaw() + \"\")\n                    .put(\"raw_crops_multiplier\", (island, superiorPlayer) ->\n                            island.getCropGrowthRaw() + \"\")\n                    .put(\"raw_drops_multiplier\", (island, superiorPlayer) ->\n                            island.getMobDropsRaw() + \"\")\n                    .put(\"raw_level\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getRawLevel()))\n                    .put(\"raw_level_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawLevel(), superiorPlayer.getUserLocale()))\n                    .put(\"raw_level_int\", (island, superiorPlayer) ->\n                            island.getRawLevel().toBigInteger().toString())\n                    .put(\"raw_level_raw\", (island, superiorPlayer) ->\n                            island.getRawLevel().toString())\n                    .put(\"raw_radius\", (island, superiorPlayer) ->\n                            island.getIslandSizeRaw() + \"\")\n                    .put(\"raw_spawners_multiplier\", (island, superiorPlayer) ->\n                            island.getSpawnerRatesRaw() + \"\")\n                    .put(\"raw_team_limit\", (island, superiorPlayer) ->\n                            island.getTeamLimitRaw() + \"\")\n                    .put(\"raw_warps_limit\", (island, superiorPlayer) ->\n                            island.getWarpsLimitRaw() + \"\")\n                    .put(\"raw_worth\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getRawWorth()))\n                    .put(\"raw_worth_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawWorth(), superiorPlayer.getUserLocale()))\n                    .put(\"raw_worth_int\", (island, superiorPlayer) ->\n                            island.getRawWorth().toBigInteger().toString())\n                    .put(\"raw_worth_raw\", (island, superiorPlayer) ->\n                            island.getRawWorth().toString())\n                    .put(\"schematic\", (island, superiorPlayer) ->\n                            island.getSchematicName())\n                    .put(\"size\", (island, superiorPlayer) -> {\n                        int size = island.getIslandSize() * 2 + 1;\n                        return size + \" x \" + size;\n                    })\n                    .put(\"size_format\", (island, superiorPlayer) -> {\n                        int size = island.getIslandSize() * 2 + 1;\n                        int rounded = 5 * (Math.round(size / 5.0F));\n                        if (Math.abs(size - rounded) == 1)\n                            size = rounded;\n                        return size + \" x \" + size;\n                    })\n                    .put(\"spawners_multiplier\", (island, superiorPlayer) ->\n                            island.getSpawnerRatesMultiplier() + \"\")\n                    .put(\"team_limit\", (island, superiorPlayer) ->\n                            island.getTeamLimit() + \"\")\n                    .put(\"team_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getIslandMembers(true);\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"team_size\", (island, superiorPlayer) ->\n                            island.getIslandMembers(true).size() + \"\")\n                    .put(\"team_size_online\", (island, superiorPlayer) ->\n                            island.getIslandMembers(true).stream().filter(SuperiorPlayer::isShownAsOnline).count() + \"\")\n                    .put(\"unique_visitors_count\", (island, superiorPlayer) ->\n                            island.getUniqueVisitors().size() + \"\")\n                    .put(\"unique_visitors_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getUniqueVisitors();\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"uuid\", (island, superiorPlayer) ->\n                            island.getUniqueId() + \"\")\n                    .put(\"visitors_count\", (island, superiorPlayer) ->\n                            island.getIslandVisitors(false).size() + \"\")\n                    .put(\"visitors_list\", (island, superiorPlayer) -> {\n                        StringBuilder teamBuilder = new StringBuilder();\n                        List<SuperiorPlayer> players = island.getIslandVisitors();\n                        if (players.isEmpty()) {\n                            return \"\";\n                        }\n                        for (SuperiorPlayer player : players) {\n                            teamBuilder.append(\", \").append(player.getName());\n                        }\n                        return teamBuilder.substring(2);\n                    })\n                    .put(\"visitors_location\", (island, superiorPlayer) -> {\n                        WorldInfo worldInfo = getDefaultWorldInfo(island);\n                        return Formatters.LOCATION_FORMATTER.format(island.getVisitorsPosition(null /*unused*/).toLocation(worldInfo));\n                    })\n                    .put(\"visitors_location_x\", (island, superiorPlayer) ->\n                            island.getVisitorsPosition(getDefaultWorldDimension()).getX() + \"\")\n                    .put(\"visitors_location_y\", (island, superiorPlayer) ->\n                            island.getVisitorsPosition(getDefaultWorldDimension()).getY() + \"\")\n                    .put(\"visitors_location_z\", (island, superiorPlayer) ->\n                            island.getVisitorsPosition(getDefaultWorldDimension()).getZ() + \"\")\n                    .put(\"warps\", (island, superiorPlayer) ->\n                            island.getIslandWarps().size() + \"\")\n                    .put(\"warps_limit\", (island, superiorPlayer) ->\n                            island.getWarpsLimit() + \"\")\n                    .put(\"world\", (island, superiorPlayer) ->\n                            getDefaultWorldInfo(island).getName())\n                    .put(\"worth\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(island.getWorth()))\n                    .put(\"worth_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), superiorPlayer.getUserLocale()))\n                    .put(\"worth_int\", (island, superiorPlayer) ->\n                            island.getWorth().toBigInteger().toString())\n                    .put(\"worth_raw\", (island, superiorPlayer) ->\n                            island.getWorth().toString())\n                    // Renamed Island Placeholders\n                    .put(\"hoppers_limit\", (island, superiorPlayer) ->\n                            island.getBlockLimit(ConstantKeys.HOPPER) + \"\")\n                    .put(\"x\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getX() + \"\")\n                    .put(\"y\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getY() + \"\")\n                    .put(\"z\", (island, superiorPlayer) ->\n                            island.getCenterPosition().getZ() + \"\")\n                    // Global Placeholders\n                    .put(\"total_count\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size()))\n                    .put(\"total_count_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size(), superiorPlayer.getUserLocale()))\n                    .put(\"total_count_raw\", (island, superiorPlayer) ->\n                            plugin.getGrid().getIslands().size() + \"\")\n                    .put(\"total_level\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel()))\n                    .put(\"total_level_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel(), superiorPlayer.getUserLocale()))\n                    .put(\"total_level_int\", (island, superiorPlayer) ->\n                            plugin.getGrid().getTotalLevel().toBigInteger().toString())\n                    .put(\"total_level_raw\", (island, superiorPlayer) ->\n                            plugin.getGrid().getTotalLevel().toString())\n                    .put(\"total_worth\", (island, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth()))\n                    .put(\"total_worth_format\", (island, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth(), superiorPlayer.getUserLocale()))\n                    .put(\"total_worth_int\", (island, superiorPlayer) ->\n                            plugin.getGrid().getTotalWorth().toBigInteger().toString())\n                    .put(\"total_worth_raw\", (island, superiorPlayer) ->\n                            plugin.getGrid().getTotalWorth().toString())\n                    .build();\n\n    private static final Map<SortingType, BiFunction<Island, SuperiorPlayer, String>> TOP_VALUE_FORMAT_FUNCTIONS =\n            new ImmutableMap.Builder<SortingType, BiFunction<Island, SuperiorPlayer, String>>()\n                    .put(SortingTypes.BY_WORTH, (targetIsland, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(targetIsland.getWorth(), superiorPlayer.getUserLocale()))\n                    .put(SortingTypes.BY_LEVEL, (targetIsland, superiorPlayer) ->\n                            Formatters.FANCY_NUMBER_FORMATTER.format(targetIsland.getIslandLevel(), superiorPlayer.getUserLocale()))\n                    .put(SortingTypes.BY_RATING, (targetIsland, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(targetIsland.getTotalRating()))\n                    .put(SortingTypes.BY_PLAYERS, (targetIsland, superiorPlayer) ->\n                            Formatters.NUMBER_FORMATTER.format(targetIsland.getAllPlayersInside().size()))\n                    .build();\n\n    private static final Map<SortingType, Function<Island, String>> TOP_VALUE_RAW_FUNCTIONS =\n            new ImmutableMap.Builder<SortingType, Function<Island, String>>()\n                    .put(SortingTypes.BY_WORTH, targetIsland -> targetIsland.getWorth().toString())\n                    .put(SortingTypes.BY_LEVEL, targetIsland -> targetIsland.getIslandLevel().toString())\n                    .put(SortingTypes.BY_RATING, targetIsland -> targetIsland.getTotalRating() + \"\")\n                    .put(SortingTypes.BY_PLAYERS, targetIsland -> targetIsland.getAllPlayersInside().size() + \"\")\n                    .build();\n\n    private static final Map<SortingType, Function<Island, String>> TOP_VALUE_FUNCTIONS =\n            new ImmutableMap.Builder<SortingType, Function<Island, String>>()\n                    .put(SortingTypes.BY_WORTH, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getWorth()))\n                    .put(SortingTypes.BY_LEVEL, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getIslandLevel()))\n                    .put(SortingTypes.BY_RATING, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getTotalRating()))\n                    .put(SortingTypes.BY_PLAYERS, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getAllPlayersInside().size()))\n                    .build();\n\n    private final Map<String, IslandPlaceholderParser> CUSTOM_ISLAND_PARSERS = new HashMap<>();\n    private final Map<String, PlayerPlaceholderParser> CUSTOM_PLAYER_PARSERS = new HashMap<>();\n\n    private final List<PlaceholdersProvider> placeholdersProviders = new LinkedList<>();\n\n    public PlaceholdersServiceImpl() {\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return PlaceholdersService.class;\n    }\n\n    public void register(List<PlaceholdersProvider> placeholdersProviders) {\n        this.placeholdersProviders.addAll(placeholdersProviders);\n    }\n\n    public String parsePlaceholders(@Nullable OfflinePlayer offlinePlayer, String str) {\n        for (PlaceholdersProvider placeholdersProvider : placeholdersProviders)\n            str = placeholdersProvider.parsePlaceholders(offlinePlayer, str);\n\n        return str;\n    }\n\n    public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, String placeholder) {\n        SuperiorPlayer superiorPlayer = offlinePlayer == null ? null :\n                plugin.getPlayers().getSuperiorPlayer(offlinePlayer.getUniqueId());\n\n        Optional<String> placeholderResult = Optional.empty();\n\n        Matcher matcher;\n\n        if (superiorPlayer != null) {\n            PlayerPlaceholderParser customPlayerParser = CUSTOM_PLAYER_PARSERS.get(placeholder);\n            if (customPlayerParser != null) {\n                placeholderResult = Optional.ofNullable(customPlayerParser.apply(superiorPlayer));\n            } else {\n                boolean isLocationPlaceholder = placeholder.startsWith(\"location_\");\n                IslandPlaceholderParser customIslandParser = CUSTOM_ISLAND_PARSERS.get(\n                        isLocationPlaceholder ? placeholder.substring(9) : placeholder);\n                if (customIslandParser != null) {\n                    Island island;\n                    if (isLocationPlaceholder) {\n                        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                            island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle()));\n                        }\n                    } else {\n                        island = superiorPlayer.getIsland();\n                    }\n                    placeholderResult = Optional.ofNullable(customIslandParser.apply(island, superiorPlayer));\n                }\n            }\n        }\n\n        if (!placeholderResult.isPresent()) {\n            if ((matcher = PLAYER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH);\n                placeholderResult = parsePlaceholdersForPlayer(superiorPlayer, subPlaceholder);\n            } else if ((matcher = ISLAND_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH);\n                Island island;\n                boolean isLocationPlaceholder = false;\n                if (superiorPlayer == null) {\n                    island = null;\n                } else if (subPlaceholder.startsWith(\"location_\")) {\n                    isLocationPlaceholder = true;\n                    try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                        island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle()));\n                    }\n                } else {\n                    island = superiorPlayer.getIsland();\n                }\n                placeholderResult = parsePlaceholdersForIsland(island, superiorPlayer,\n                        isLocationPlaceholder ? placeholder.substring(9) : placeholder,\n                        isLocationPlaceholder ? subPlaceholder.substring(9) : subPlaceholder);\n            }\n        }\n\n        if (placeholderResult.isPresent())\n            return placeholderResult.get();\n\n        String defaultPlaceholderValue = plugin.getSettings().getDefaultPlaceholders().get(placeholder);\n        if (defaultPlaceholderValue != null)\n            return defaultPlaceholderValue;\n\n        // We try to look for prefixes of placeholders\n        for (Map.Entry<String, String> entry : plugin.getSettings().getDefaultPlaceholders().entrySet()) {\n            if (placeholder.startsWith(entry.getKey())) {\n                return entry.getValue();\n            }\n        }\n\n        return \"\";\n    }\n\n    @Override\n    public void registerPlaceholder(String placeholderName, PlayerPlaceholderParser placeholderFunction) {\n        CUSTOM_PLAYER_PARSERS.put(placeholderName, placeholderFunction);\n    }\n\n    @Override\n    public void registerPlaceholder(String placeholderName, IslandPlaceholderParser placeholderFunction) {\n        CUSTOM_ISLAND_PARSERS.put(placeholderName, placeholderFunction);\n    }\n\n    private static Optional<String> parsePlaceholdersForPlayer(@Nullable SuperiorPlayer superiorPlayer,\n                                                               String subPlaceholder) {\n        Matcher matcher;\n\n        if (superiorPlayer != null) {\n            if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) {\n                String categoryName = matcher.group(1);\n                return Optional.of(superiorPlayer.getCompletedMissions().stream().filter(mission ->\n                        mission.getMissionCategory().getName().equalsIgnoreCase(categoryName)).count() + \"\");\n            }\n        }\n\n        return Optional.ofNullable(PLAYER_PARSES.get(subPlaceholder))\n                .map(placeholderParser -> placeholderParser.apply(superiorPlayer));\n    }\n\n    private static Optional<String> parsePlaceholdersForIsland(@Nullable Island island,\n                                                               @Nullable SuperiorPlayer superiorPlayer,\n                                                               String placeholder, String subPlaceholder) {\n        Matcher matcher;\n\n        if (island != null) {\n            if ((matcher = GENERATOR_AMOUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                return handleGeneratorAmountsPlaceholder(island, matcher.group(1));\n            }\n\n            if ((matcher = GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                return handleGeneratorPercentagesPlaceholder(island, matcher.group(1));\n            }\n\n            if ((matcher = WORLD_UNLOCKED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                boolean unlockedWorld = island.getUnlockedWorlds().contains(Dimension.getByName(matcher.group(1)));\n                return Optional.of(Formatters.BOOLEAN_FORMATTER.format(unlockedWorld, superiorPlayer.getUserLocale()));\n            }\n\n            if ((matcher = WORLD_ENABLED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                boolean enabledWorld = island.isDimensionEnabled(Dimension.getByName(matcher.group(1)));\n                return Optional.of(Formatters.BOOLEAN_FORMATTER.format(enabledWorld, superiorPlayer.getUserLocale()));\n            }\n\n            if ((matcher = WORLD_GENERATED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                boolean generatedWorld = island.getGeneratedSchematics().contains(Dimension.getByName(matcher.group(1)));\n                return Optional.of(Formatters.BOOLEAN_FORMATTER.format(generatedWorld, superiorPlayer.getUserLocale()));\n            }\n\n            if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) {\n                String categoryName = matcher.group(1);\n                return Optional.of(island.getCompletedMissions().stream().filter(mission ->\n                        mission.getMissionCategory().getName().equalsIgnoreCase(categoryName)).count() + \"\");\n            }\n\n            if ((matcher = MISSION_STATUS_PATTERN.matcher(subPlaceholder)).matches()) {\n                String missionName = matcher.group(1);\n                Mission<?> mission = plugin.getMissions().getMission(missionName);\n                if (mission == null || (!mission.getIslandMission() && superiorPlayer == null))\n                    return Optional.empty();\n                boolean completedMission = mission.getIslandMission() ? island.hasCompletedMission(mission) :\n                        superiorPlayer.hasCompletedMission(mission);\n                return Optional.of(Formatters.BOOLEAN_FORMATTER.format(completedMission, superiorPlayer.getUserLocale()));\n            }\n\n            if ((matcher = PERMISSION_ROLE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                return handlePermissionRolesPlaceholder(island, matcher.group(1));\n            }\n\n            if (superiorPlayer != null) {\n                if ((matcher = BLOCK_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches() ||\n                        (matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + \"\");\n                } else if ((matcher = BLOCK_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName));\n                    return Optional.of(blockValue.getLevel() + \"\");\n                } else if ((matcher = BLOCK_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    return Optional.of(island.getBlockLimit(Keys.ofMaterialAndData(keyName)) + \"\");\n                } else if ((matcher = BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName));\n                    BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)));\n                    return Optional.of(blockValue.getLevel().multiply(amount) + \"\");\n                } else if ((matcher = BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName));\n                    BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)));\n                    return Optional.of(blockValue.getWorth().multiply(amount) + \"\");\n                } else if ((matcher = BLOCK_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName));\n                    return Optional.of(blockValue.getWorth() + \"\");\n                } else if ((matcher = DATA_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    Object data = island.getPersistentDataContainer().get(keyName);\n                    if (data == null) {\n                        return Optional.empty();\n                    }\n                    return Optional.of(data.toString());\n                } else if ((matcher = EFFECT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String effectName = matcher.group(1);\n                    PotionEffectType potionEffectType = PotionEffectType.getByName(effectName);\n                    if (potionEffectType == null) {\n                        return Optional.empty();\n                    }\n                    return Optional.of(island.getPotionEffectLevel(potionEffectType) + \"\");\n                } else if ((matcher = ENTITY_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    return Optional.of(island.getEntitiesTracker().getEntityCount(Keys.ofEntityType(keyName)) + \"\");\n                } else if ((matcher = ENTITY_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String keyName = matcher.group(1);\n                    return Optional.of(island.getEntityLimit(Keys.ofEntityType(keyName)) + \"\");\n                } else if ((matcher = FLAG_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n                    return handleFlagsPlaceholder(island, superiorPlayer, matcher.group(1));\n                } else if ((matcher = MEMBER_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n                    return handleMembersPlaceholder(island, matcher.group(1));\n                } else if ((matcher = PERMISSION_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    return handlePermissionsPlaceholder(island, superiorPlayer, matcher.group(1));\n                } else if ((matcher = ROLE_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String roleName = matcher.group(1);\n                    PlayerRole playerRole;\n                    try {\n                        playerRole = SPlayerRole.of(roleName);\n                    } catch (IllegalArgumentException error) {\n                        return Optional.empty();\n                    }\n                    return Optional.of(island.getIslandMembers(playerRole).size() + \"\");\n                } else if ((matcher = ROLE_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String roleName = matcher.group(1);\n                    PlayerRole playerRole;\n                    try {\n                        playerRole = SPlayerRole.of(roleName);\n                    } catch (IllegalArgumentException error) {\n                        return Optional.empty();\n                    }\n                    return Optional.of(island.getRoleLimit(playerRole) + \"\");\n                } else if ((matcher = UPGRADE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n                    String upgradeName = matcher.group(1);\n                    Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName);\n                    if (upgrade == null) {\n                        return Optional.empty();\n                    }\n                    return Optional.of(island.getUpgradeLevel(upgrade).getLevel() + \"\");\n                } else if ((matcher = VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n                    String visitorName = matcher.group(1);\n                    return Optional.of(island.getUniqueVisitorsWithTimes().stream()\n                            .filter(uniqueVisitor -> uniqueVisitor.getKey().getName().equalsIgnoreCase(visitorName))\n                            .findFirst()\n                            .map(Pair::getValue).map(value -> Formatters.DATE_FORMATTER.format(new Date(value)))\n                            .orElse(\"Haven't Joined\"));\n                }\n            }\n        }\n\n        if ((matcher = TOP_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {\n            return handleTopIslandsPlaceholder(island, superiorPlayer, matcher.group(1));\n        } else {\n            try {\n                return Optional.ofNullable(ISLAND_PARSES.get(subPlaceholder))\n                        .map(placeholderParser -> placeholderParser.apply(island, superiorPlayer));\n            } catch (NullPointerException ignored) {\n                // One of the island parses failed due to invalid island being sent.\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    private static Optional<String> handleFlagsPlaceholder(@NotNull Island island,\n                                                           @NotNull SuperiorPlayer superiorPlayer,\n                                                           String placeholder) {\n        try {\n            IslandFlag islandFlag = IslandFlag.getByName(placeholder);\n            return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasSettingsEnabled(islandFlag),\n                    superiorPlayer.getUserLocale()));\n        } catch (NullPointerException ex) {\n            return Optional.empty();\n        }\n    }\n\n    private static Optional<String> handleGeneratorAmountsPlaceholder(@Nullable Island island, String placeholder) {\n        String[] placeholderSections = placeholder.split(\"_\");\n\n        if (placeholderSections.length <= 1)\n            return Optional.empty();\n\n        Dimension dimension;\n        try {\n            dimension = Dimension.getByName(placeholderSections[0]);\n        } catch (NullPointerException error) {\n            return Optional.empty();\n        }\n\n        String keyName = String.join(\"_\", placeholderSections).substring(placeholderSections[0].length() + 1);\n\n        return Optional.of(island.getGeneratorAmount(Keys.ofMaterialAndData(keyName), dimension) + \"\");\n    }\n\n    private static Optional<String> handleGeneratorPercentagesPlaceholder(@Nullable Island island, String placeholder) {\n        String[] placeholderSections = placeholder.split(\"_\");\n\n        if (placeholderSections.length <= 1)\n            return Optional.empty();\n\n        Dimension dimension;\n        try {\n            dimension = Dimension.getByName(placeholderSections[0]);\n        } catch (NullPointerException error) {\n            return Optional.empty();\n        }\n\n        String keyName = String.join(\"_\", placeholderSections).substring(placeholderSections[0].length() + 1);\n\n        return Optional.of(IslandUtils.getGeneratorPercentageDecimal(island, Keys.ofMaterialAndData(keyName), dimension) + \"\");\n    }\n\n    private static Optional<String> handleMembersPlaceholder(@NotNull Island island, String placeholder) {\n        List<SuperiorPlayer> members = island.getIslandMembers(false);\n\n        int targetMemberIndex = -1;\n\n        try {\n            targetMemberIndex = Integer.parseInt(placeholder) - 1;\n        } catch (NumberFormatException ignored) {\n        }\n\n        if (targetMemberIndex < 0 || targetMemberIndex >= members.size())\n            return Optional.empty();\n\n        return Optional.of(members.get(targetMemberIndex).getName());\n    }\n\n    private static Optional<String> handlePermissionsPlaceholder(@NotNull Island island,\n                                                                 @NotNull SuperiorPlayer superiorPlayer,\n                                                                 String placeholder) {\n        try {\n            IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder);\n            return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasPermission(superiorPlayer, islandPrivilege),\n                    superiorPlayer.getUserLocale()));\n        } catch (NullPointerException ex) {\n            return Optional.empty();\n        }\n    }\n\n    private static Optional<String> handlePermissionRolesPlaceholder(@NotNull Island island, String placeholder) {\n        try {\n            IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder);\n            return Optional.of(island.getRequiredPlayerRole(islandPrivilege).getDisplayName());\n        } catch (NullPointerException ex) {\n            return Optional.empty();\n        }\n    }\n\n    private static Optional<String> handleTopIslandsPlaceholder(@Nullable Island island,\n                                                                @Nullable SuperiorPlayer superiorPlayer,\n                                                                String subPlaceholder) {\n        Matcher matcher;\n        SortingType sortingType;\n\n        if ((matcher = TOP_WORTH_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n            sortingType = SortingTypes.BY_WORTH;\n        } else if ((matcher = TOP_LEVEL_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n            sortingType = SortingTypes.BY_LEVEL;\n        } else if ((matcher = TOP_RATING_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n            sortingType = SortingTypes.BY_RATING;\n        } else if ((matcher = TOP_PLAYERS_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {\n            sortingType = SortingTypes.BY_PLAYERS;\n        } else {\n            String sortingTypeName = subPlaceholder.split(\"_\")[0];\n            sortingType = SortingType.getByName(sortingTypeName);\n        }\n\n        if (sortingType == null)\n            return Optional.empty();\n\n        String placeholderValue = matcher.group(1);\n\n        if (placeholderValue.equals(\"position\"))\n            return island == null ? Optional.empty() : Optional.of((plugin.getGrid().getIslandPosition(island, sortingType) + 1) + \"\");\n\n        Function<Island, String> getValueFunction;\n\n        if ((matcher = TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) {\n            getValueFunction = Optional.ofNullable(TOP_VALUE_FORMAT_FUNCTIONS.get(sortingType)).map(function ->\n                    (Function<Island, String>) targetIsland -> function.apply(targetIsland, superiorPlayer)).orElse(null);\n        } else if ((matcher = TOP_VALUE_RAW_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) {\n            getValueFunction = TOP_VALUE_RAW_FUNCTIONS.get(sortingType);\n        } else if ((matcher = TOP_VALUE_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) {\n            getValueFunction = TOP_VALUE_FUNCTIONS.get(sortingType);\n        } else if ((matcher = TOP_LEADER_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) {\n            getValueFunction = targetIsland -> targetIsland.getOwner().getName();\n        } else if ((matcher = TOP_CUSTOM_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) {\n            String customPlaceholder = matcher.group(2);\n            getValueFunction = targetIsland -> parsePlaceholdersForIsland(targetIsland, superiorPlayer,\n                    \"superior_island_\" + customPlaceholder,\n                    customPlaceholder).orElse(null);\n        } else {\n            getValueFunction = targetIsland -> targetIsland.getName().isEmpty() ?\n                    targetIsland.getOwner().getName() : targetIsland.getName();\n        }\n\n        if (getValueFunction == null)\n            return Optional.empty();\n\n        int targetPosition;\n\n        try {\n            targetPosition = Integer.parseInt(matcher.matches() ? matcher.group(1) : placeholderValue);\n        } catch (NumberFormatException error) {\n            return Optional.empty();\n        }\n\n        Island targetIsland = plugin.getGrid().getIsland(targetPosition - 1, sortingType);\n\n        return Optional.ofNullable(targetIsland).map(getValueFunction);\n    }\n\n    private static WorldInfo getDefaultWorldInfo(Island island) {\n        return plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension());\n    }\n\n    private static Dimension getDefaultWorldDimension() {\n        return plugin.getSettings().getWorlds().getDefaultWorldDimension();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.portals;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.config.SettingsManager;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService;\nimport com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult;\nimport com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.bgsoftware.superiorskyblock.world.EntityTeleports;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.PortalType;\nimport org.bukkit.World;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.HumanEntity;\nimport org.bukkit.entity.Player;\n\nimport java.math.BigDecimal;\nimport java.util.Locale;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\npublic class PortalsManagerServiceImpl implements PortalsManagerService, IService {\n\n    private final AutoRemovalCollection<UUID> generatingSchematicsIslands = AutoRemovalCollection.newHashSet(20, TimeUnit.SECONDS);\n\n    private final LazyReference<DragonBattleService> dragonBattleService = new LazyReference<DragonBattleService>() {\n        @Override\n        protected DragonBattleService create() {\n            return plugin.getServices().getService(DragonBattleService.class);\n        }\n    };\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public PortalsManagerServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return PortalsManagerService.class;\n    }\n\n    @Override\n    public EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Location portalLocation,\n                                                 PortalType portalType, Location destinationLocation,\n                                                 boolean checkImmunedPortalsStatus) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkNotNull(destinationLocation, \"destinationLocation cannot be null.\");\n        Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), \"superiorPlayer cannot be an NPC.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(destinationLocation.getWorld() != null, \"destinationLocation's world cannot be null\");\n\n        Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld());\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, null);\n    }\n\n    @Override\n    public EntityPortalResult handleEntityPortal(Entity entity, Location portalLocation,\n                                                 PortalType portalType, Location destinationLocation) {\n        Preconditions.checkNotNull(entity, \"entity cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkNotNull(destinationLocation, \"destinationLocation cannot be null.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(destinationLocation.getWorld() != null, \"destinationLocation's world cannot be null\");\n\n        Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld());\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, null);\n    }\n\n    @Override\n    public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island,\n                                                           Location portalLocation, PortalType portalType,\n                                                           boolean checkImmunedPortalsStatus) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null.\");\n        Preconditions.checkNotNull(island, \"island cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), \"superiorPlayer cannot be an NPC.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(portalLocation), \"portalLocation is not inside the island.\");\n\n        Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld());\n        if (portalDimension == null)\n            return EntityPortalResult.PORTAL_NOT_IN_ISLAND;\n\n        Dimension destinationDimension = getDestinationDimension(portalDimension, portalType);\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island);\n    }\n\n    @Override\n    public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island,\n                                                           Location portalLocation, PortalType portalType,\n                                                           Location destinationLocation, boolean checkImmunedPortalsStatus) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null.\");\n        Preconditions.checkNotNull(island, \"island cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkNotNull(destinationLocation, \"destinationLocation cannot be null.\");\n        Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), \"superiorPlayer cannot be an NPC.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(portalLocation), \"portalLocation is not inside the island.\");\n        Preconditions.checkArgument(destinationLocation.getWorld() != null, \"destinationLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(destinationLocation), \"destinationLocation is not inside the island.\");\n\n        Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld());\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island);\n    }\n\n    @Override\n    public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation,\n                                                           PortalType portalType) {\n        Preconditions.checkNotNull(entity, \"entity cannot be null.\");\n        Preconditions.checkNotNull(island, \"island cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkArgument(!(entity instanceof HumanEntity), \"entity cannot be a Player.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(portalLocation), \"portalLocation is not inside the island.\");\n\n        Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld());\n        if (portalDimension == null)\n            return EntityPortalResult.PORTAL_NOT_IN_ISLAND;\n\n        Dimension destinationDimension = getDestinationDimension(portalDimension, portalType);\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island);\n    }\n\n    @Override\n    public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation,\n                                                           PortalType portalType, Location destinationLocation) {\n        Preconditions.checkNotNull(entity, \"entity cannot be null.\");\n        Preconditions.checkNotNull(island, \"island cannot be null.\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null.\");\n        Preconditions.checkNotNull(portalType, \"portalType cannot be null.\");\n        Preconditions.checkNotNull(destinationLocation, \"destinationLocation cannot be null.\");\n        Preconditions.checkArgument(!(entity instanceof HumanEntity), \"entity cannot be a Player.\");\n        Preconditions.checkArgument(portalLocation.getWorld() != null, \"portalLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(portalLocation), \"portalLocation is not inside the island.\");\n        Preconditions.checkArgument(destinationLocation.getWorld() != null, \"destinationLocation's world cannot be null\");\n        Preconditions.checkArgument(island.isInside(destinationLocation), \"destinationLocation is not inside the island.\");\n\n        Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld());\n        if (destinationDimension == null)\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n\n        return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island);\n    }\n\n    private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPlayer, Location portalLocation,\n                                                          PortalType portalType, Dimension destinationDimension,\n                                                          boolean checkImmunedPortalsStatus, @Nullable Island island) {\n        if (island == null) {\n            island = plugin.getGrid().getIslandAt(portalLocation);\n\n            if (island == null)\n                return EntityPortalResult.PORTAL_NOT_IN_ISLAND;\n        }\n\n        if (checkImmunedPortalsStatus && superiorPlayer.hasPlayerStatus(PlayerStatus.PORTALS_IMMUNED))\n            return EntityPortalResult.PLAYER_IMMUNED_TO_PORTAL;\n\n        EntityPortalResult portalResult = simulateEntityPortalFromIsland(superiorPlayer.asPlayer(), island,\n                portalType, destinationDimension);\n\n        if (portalResult == EntityPortalResult.WORLD_NOT_UNLOCKED) {\n            Message.WORLD_NOT_UNLOCKED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName()));\n        } else if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED) {\n            Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName()));\n        }\n\n        return portalResult;\n    }\n\n    private EntityPortalResult handleEntityPortalInternal(Entity entity, Location portalLocation, PortalType portalType,\n                                                          Dimension destinationDimension, @Nullable Island island) {\n        if (island == null) {\n            island = plugin.getGrid().getIslandAt(portalLocation);\n\n            if (island == null)\n                return EntityPortalResult.PORTAL_NOT_IN_ISLAND;\n        }\n\n        return simulateEntityPortalFromIsland(entity, island, portalType, destinationDimension);\n    }\n\n    private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island island, PortalType portalType,\n                                                              Dimension portalDestination) {\n        {\n            SettingsManager.Worlds.DimensionConfig destinationConfig = portalDestination == null ? null :\n                    plugin.getSettings().getWorlds().getDimensionConfig(portalDestination);\n            if (portalDestination == null || destinationConfig == null || !destinationConfig.isEnabled()) {\n                return EntityPortalResult.DESTINATION_WORLD_DISABLED;\n            }\n        }\n\n        if (plugin.getGrid().getIslandsWorld(island, portalDestination) == null) {\n            return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD;\n        }\n\n        if (!island.isDimensionEnabled(portalDestination)) {\n            return EntityPortalResult.WORLD_NOT_UNLOCKED;\n        }\n\n        try {\n            // We want to prevent the players from being teleported in this time.\n            if (generatingSchematicsIslands.contains(island.getUniqueId()))\n                return EntityPortalResult.SCHEMATIC_GENERATING_COOLDOWN;\n\n            String destinationDimensionName = portalDestination.getName().toLowerCase(Locale.ENGLISH);\n            String islandSchematic = island.getSchematicName();\n\n            Schematic originalSchematic = plugin.getSchematics().getSchematic(islandSchematic.isEmpty() ?\n                    plugin.getSchematics().getDefaultSchematic(portalDestination) :\n                    islandSchematic + \"_\" + destinationDimensionName);\n\n            boolean schematicGenerated = island.wasSchematicGenerated(portalDestination);\n            SuperiorPlayer superiorPlayer = entity instanceof Player ? plugin.getPlayers().getSuperiorPlayer(entity) : null;\n\n            Dimension destination;\n            Schematic schematic;\n            boolean ignoreInvalidSchematic;\n\n            if (superiorPlayer != null) {\n                PluginEvent<PluginEventArgs.IslandEnterPortal> event = PluginEventsFactory.callIslandEnterPortalEvent(\n                        island, superiorPlayer, portalType, portalDestination, schematicGenerated ? null : originalSchematic,\n                        schematicGenerated);\n\n                if (event.isCancelled())\n                    return EntityPortalResult.PORTAL_EVENT_CANCELLED;\n\n                destination = event.getArgs().destination;\n                schematic = event.getArgs().schematic;\n                ignoreInvalidSchematic = event.getArgs().ignoreInvalidSchematic;\n            } else {\n                destination = portalDestination;\n                schematic = schematicGenerated ? null : originalSchematic;\n                ignoreInvalidSchematic = schematicGenerated;\n            }\n\n            if (schematic == null && !ignoreInvalidSchematic) {\n                if (superiorPlayer != null) {\n                    String schematicName = islandSchematic + \"_\" + destinationDimensionName;\n                    Message.SCHEMATIC_NOT_ADDED.send(superiorPlayer, destinationDimensionName, schematicName);\n                }\n                return EntityPortalResult.INVALID_SCHEMATIC;\n            }\n\n            generatingSchematicsIslands.add(island.getUniqueId());\n\n            // If schematic was already generated, or no schematic should be generated, simply\n            // teleport player to destination location.\n            if (schematic == null || island.wasSchematicGenerated(destination)) {\n                if (superiorPlayer != null) {\n                    superiorPlayer.teleport(island, destination, result -> {\n                        generatingSchematicsIslands.remove(island.getUniqueId());\n                    });\n                } else {\n                    EntityTeleports.findIslandSafeLocation(island, destination).whenComplete((safeSpot, error) -> {\n                        generatingSchematicsIslands.remove(island.getUniqueId());\n\n                        if (error == null && safeSpot != null)\n                            EntityTeleports.teleport(entity, safeSpot);\n                    });\n                }\n                return EntityPortalResult.SUCCEED;\n            }\n\n            IslandWorlds.accessIslandWorldAsync(island, destination, true, islandWorldResult -> {\n                islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> {\n                    Location centerLocation = island.getCenter(destination);\n                    Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation();\n\n                    BigDecimal originalWorth = island.getRawWorth();\n                    BigDecimal originalLevel = island.getRawLevel();\n\n                    schematic.pasteSchematic(island, schematicPlacementLocation, () -> {\n                        generatingSchematicsIslands.remove(island.getUniqueId());\n                        island.setSchematicGenerate(destination);\n\n                        SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(destination);\n                        if (destinationConfig != null && destinationConfig.isSchematicOffset()) {\n                            {\n                                BigDecimal schematicWorth = island.getRawWorth().subtract(originalWorth);\n                                PluginEvent<PluginEventArgs.IslandChangeWorthBonus> event = PluginEventsFactory.callIslandChangeWorthBonusEvent(\n                                        island, (SuperiorPlayer) null, IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth));\n                                if (!event.isCancelled())\n                                    island.setBonusWorth(event.getArgs().worthBonus);\n                            }\n                            {\n                                BigDecimal schematicLevel = island.getRawLevel().subtract(originalLevel);\n                                PluginEvent<PluginEventArgs.IslandChangeLevelBonus> event = PluginEventsFactory.callIslandChangeLevelBonusEvent(\n                                        island, (SuperiorPlayer) null, IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel));\n                                if (!event.isCancelled())\n                                    island.setBonusLevel(event.getArgs().levelBonus);\n                            }\n                        }\n\n                        Location homeLocation = schematic.adjustRotation(centerLocation);\n                        island.setIslandHome(homeLocation);\n\n                        if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) {\n                            plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity);\n                            this.dragonBattleService.get().resetEnderDragonBattle(island, destination);\n                        }\n\n                        if (superiorPlayer != null) {\n                            superiorPlayer.teleport(homeLocation);\n                        } else {\n                            EntityTeleports.teleport(entity, homeLocation);\n                        }\n                    }, error -> {\n                        generatingSchematicsIslands.remove(island.getUniqueId());\n                        error.printStackTrace();\n                        if (superiorPlayer != null)\n                            Message.CREATE_WORLD_FAILURE.send(superiorPlayer);\n                    });\n                });\n            });\n\n        } catch (NullPointerException ignored) {\n        }\n\n        return EntityPortalResult.SUCCEED;\n    }\n\n    @Nullable\n    private Dimension getDestinationDimension(Dimension dimension, PortalType portalType) {\n        SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension);\n        if (dimensionConfig == null)\n            return null;\n\n        return dimensionConfig.getPortalDestination(portalType);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java",
    "content": "package com.bgsoftware.superiorskyblock.service.region;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.commands.CommandsHelper;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.player.PlayerLocales;\nimport org.bukkit.Location;\nimport org.bukkit.command.CommandSender;\nimport org.bukkit.entity.Player;\n\nimport java.util.Locale;\n\npublic class ProtectionHelper {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private ProtectionHelper() {\n\n    }\n\n    public static boolean shouldPreventInteraction(InteractionResult interactionResult,\n                                                   @Nullable SuperiorPlayer superiorPlayer, boolean sendMessages) {\n        switch (interactionResult) {\n            case ISLAND_RECALCULATE:\n                if (sendMessages && superiorPlayer != null)\n                    Message.ISLAND_BEING_CALCULATED.send(superiorPlayer);\n                return true;\n            case MISSING_PRIVILEGE:\n                if (sendMessages && superiorPlayer != null)\n                    sendProtectionMessage(superiorPlayer.asPlayer());\n                return true;\n            case OUTSIDE_ISLAND:\n                if (sendMessages && superiorPlayer != null)\n                    Message.BUILD_OUTSIDE_ISLAND.send(superiorPlayer);\n                return true;\n            case SUCCESS:\n                return false;\n        }\n\n        throw new IllegalStateException(\"No handling for result \" + interactionResult);\n    }\n\n    public static void sendProtectionMessage(CommandSender sender) {\n        boolean isSpawnIsland;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Island island = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle()));\n            isSpawnIsland = island != null && island.isSpawn();\n        }\n\n        Locale locale = PlayerLocales.getLocale(sender);\n\n        if (!isSpawnIsland)\n            Message.ISLAND_PROTECTED.send(sender, locale);\n        else\n            Message.SPAWN_PROTECTED.send(sender, locale);\n\n        SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand(\"bypass\");\n        if (CommandsHelper.hasCommandAccess(bypassCommand, sender))\n            if (!isSpawnIsland)\n                Message.ISLAND_PROTECTED_OPPED.send(sender, locale);\n            else\n                Message.SPAWN_PROTECTED_OPPED.send(sender, locale);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.region;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent;\nimport com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPreview;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.player.PlayerStatus;\nimport com.bgsoftware.superiorskyblock.api.service.region.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.MoveResult;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.flag.IslandFlags;\nimport com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.WeatherType;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Animals;\nimport org.bukkit.entity.Arrow;\nimport org.bukkit.entity.Creeper;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Item;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.Sheep;\nimport org.bukkit.entity.Villager;\nimport org.bukkit.entity.minecart.PoweredMinecart;\nimport org.bukkit.event.block.Action;\nimport org.bukkit.event.inventory.InventoryType;\nimport org.bukkit.inventory.Inventory;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.scheduler.BukkitTask;\n\nimport java.util.List;\nimport java.util.Optional;\n\npublic class RegionManagerServiceImpl implements RegionManagerService, IService {\n\n    private static final Material FARMLAND = EnumHelper.getEnum(Material.class, \"FARMLAND\", \"SOIL\");\n    @Nullable\n    private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, \"ROOTED_DIRT\");\n    @Nullable\n    private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, \"TURTLE_EGG\");\n    @Nullable\n    private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, \"SWEET_BERRY_BUSH\");\n    @Nullable\n    private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, \"CAVE_VINES\");\n    @Nullable\n    private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, \"CAVE_VINES_PLANT\");\n    @Nullable\n    private static final Material VAULT = EnumHelper.getEnum(Material.class, \"VAULT\");\n    @Nullable\n    private static final Material TRIAL_KEY = EnumHelper.getEnum(Material.class, \"TRIAL_KEY\");\n    @Nullable\n    private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, \"OMINOUS_TRIAL_KEY\");\n    @Nullable\n    private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, \"LLAMA\");\n    @Nullable\n    private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, \"HAPPY_GHAST\");\n    @Nullable\n    private static final EntityType PARROT_TYPE = EnumHelper.getEnum(EntityType.class, \"PARROT\");\n    @Nullable\n    private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, \"GOLDEN_DANDELION\");\n\n    private static final int MAX_PICKUP_DISTANCE = 1;\n    private static EnumerateSet<IslandPrivilege> WORLD_PERMISSIONS_CACHE;\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, RegionManagerServiceImpl::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n        WORLD_PERMISSIONS_CACHE = new EnumerateSet<>(IslandPrivilege.values());\n        plugin.getSettings().getWorldPermissions().forEach(islandPrivilageName -> {\n            try {\n                WORLD_PERMISSIONS_CACHE.add(IslandPrivilege.getByName(islandPrivilageName));\n            } catch (Throwable ignored) {\n            }\n        });\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return RegionManagerService.class;\n    }\n\n    @Override\n    public InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block block) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.BUILD,\n                    0, true, true);\n        }\n    }\n\n    @Override\n    public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block block) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n            Material blockType = block.getType();\n            IslandPrivilege islandPrivilege = blockType == Materials.SPAWNER.toBukkitType() ? IslandPrivileges.SPAWNER_BREAK : IslandPrivileges.BREAK;\n\n            InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege,\n                    0, true, true, island, false);\n\n            if (interactionResult != InteractionResult.SUCCESS)\n                return interactionResult;\n\n            if (island == null)\n                return InteractionResult.SUCCESS;\n\n            if (plugin.getSettings().getValuableBlocks().contains(Keys.of(block)))\n                return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.VALUABLE_BREAK,\n                        0, false, false, island, false);\n        }\n\n        return InteractionResult.SUCCESS;\n    }\n\n    @Override\n    public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Block block, Action action, @Nullable ItemStack usedItem) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            Key blockKey = Keys.of(block);\n\n            boolean isInteractableItem = BukkitItems.isInteractableItem(usedItem);\n\n            int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation);\n\n            IslandPrivilege islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(blockKey);\n\n            if (!isInteractableItem && stackedBlockAmount <= 1 && islandPrivilege == null)\n                return InteractionResult.SUCCESS;\n\n            Material blockType = block.getType();\n            Material usedItemType = usedItem == null ? null : usedItem.getType();\n\n            EntityType spawnType = usedItem == null ? EntityType.UNKNOWN :\n                    Materials.isMinecart(usedItemType) && Materials.isRail(blockType) ? EntityType.MINECART :\n                    Materials.isBoat(blockType) ? EntityType.BOAT : BukkitItems.getEntityType(usedItem);\n\n            if (spawnType != EntityType.UNKNOWN) {\n                List<EntityCategory> entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType));\n                for (EntityCategory entityCategory : entityCategories) {\n                    if (entityCategory.getSpawnPrivilege() != null) {\n                        InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation,\n                                entityCategory.getSpawnPrivilege(), 0, true, true);\n                        if (interactionResult != InteractionResult.SUCCESS)\n                            return interactionResult;\n                    }\n                }\n                return InteractionResult.SUCCESS;\n            }\n\n            if (usedItem != null && blockType == VAULT && usedItemType != TRIAL_KEY && usedItemType != OMINOUS_TRIAL_KEY) {\n                return InteractionResult.SUCCESS;\n            } else if (action == Action.PHYSICAL && blockType == FARMLAND || blockType == ROOTED_DIRT ||\n                    (usedItem != null && Materials.isHoe(usedItemType))) {\n                islandPrivilege = IslandPrivileges.BUILD;\n            } else if (action == Action.PHYSICAL && blockType == TURTLE_EGG) {\n                islandPrivilege = IslandPrivileges.BUILD;\n            } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK &&\n                    Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) &&\n                    ((org.bukkit.block.data.Ageable) plugin.getNMSWorld().getBlockData(block)).getAge() < 3) {\n                islandPrivilege = IslandPrivileges.FERTILIZE;\n            } else if ((blockType == CAVE_VINES || blockType == CAVE_VINES_PLANT) && action == Action.RIGHT_CLICK_BLOCK &&\n                    Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) &&\n                    !plugin.getNMSWorld().hasBerries(block)) {\n                islandPrivilege = IslandPrivileges.FERTILIZE;\n            } else if (stackedBlockAmount > 1) {\n                islandPrivilege = IslandPrivileges.BREAK;\n            }\n\n            return handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege,\n                    0, true, true);\n        }\n    }\n\n    @Override\n    public InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Block block) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.FERTILIZE,\n                    0, true, true);\n        }\n    }\n\n    @Override\n    public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Entity entity, @Nullable ItemStack usedItem) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(entity, \"entity cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        InteractionResult interactionResult;\n        boolean closeInventory = false;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = entity.getLocation(wrapper.getHandle());\n\n            EntityType entityType = entity.getType();\n            Material usedItemType = usedItem == null ? Material.AIR : usedItem.getType();\n\n            if (entity instanceof Villager || BukkitEntities.isHorse(entity) || BukkitEntities.isNautilus(entityType)) {\n                closeInventory = true;\n            }\n\n            IslandPrivilege islandPrivilege = null;\n            if (usedItem != null && entity instanceof Animals && (usedItemType == GOLDEN_DANDELION_TYPE ||\n                    plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity))) {\n                islandPrivilege = IslandPrivileges.ANIMAL_BREED;\n            } else if (usedItemType == Material.NAME_TAG) {\n                islandPrivilege = IslandPrivileges.NAME_ENTITY;\n            } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType)) ||\n                    (entityType == HAPPY_GHAST_TYPE && Materials.isHarness(usedItemType)) ||\n                    (usedItemType == Material.SHEARS && plugin.getNMSEntities().canShearSaddleFromEntity(entity))) {\n                islandPrivilege = IslandPrivileges.SADDLE_ENTITY;\n            } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) {\n                islandPrivilege = IslandPrivileges.IGNITE_CREEPER;\n            } else if (usedItem != null && entity instanceof PoweredMinecart &&\n                    plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) {\n                islandPrivilege = IslandPrivileges.MINECART_OPEN;\n            } else if (entity instanceof Sheep && Materials.isDye(usedItemType)) {\n                islandPrivilege = IslandPrivileges.DYE_SHEEP;\n            }\n\n            if (islandPrivilege != null) {\n                interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege,\n                        0, true, true);\n            } else {\n                interactionResult = InteractionResult.SUCCESS;\n                List<EntityCategory> entityCategories = BukkitEntities.getCategories(entity);\n                if (entityType == PARROT_TYPE && usedItemType == Material.COOKIE) {\n                    for (EntityCategory entityCategory : entityCategories) {\n                        if (entityCategory.getDamagePrivilege() != null) {\n                            interactionResult = handleInteractionInternal(superiorPlayer, entityLocation,\n                                    entityCategory.getDamagePrivilege(), 0, true, true);\n                            if (interactionResult != InteractionResult.SUCCESS)\n                                break;\n                        }\n                    }\n                } else {\n                    for (EntityCategory entityCategory : entityCategories) {\n                        if (entityCategory.getInteractPrivilege() != null) {\n                            interactionResult = handleInteractionInternal(superiorPlayer, entityLocation,\n                                    entityCategory.getInteractPrivilege(), 0, true, true);\n                            if (interactionResult != InteractionResult.SUCCESS)\n                                break;\n                        }\n                    }\n                }\n            }\n        }\n\n        if (closeInventory && interactionResult != InteractionResult.SUCCESS) {\n            BukkitExecutor.sync(() -> {\n                Player player = superiorPlayer.asPlayer();\n                if (player != null && player.isOnline()) {\n                    Inventory openInventory = player.getOpenInventory().getTopInventory();\n                    if (openInventory != null && (openInventory.getType() == InventoryType.MERCHANT || openInventory.getType() == InventoryType.CHEST))\n                        player.closeInventory();\n                }\n            }, 1L);\n        }\n\n        return interactionResult;\n    }\n\n    @Override\n    public InteractionResult handleEntityDamage(Entity damager, Entity entity) {\n        Preconditions.checkNotNull(damager, \"damager cannot be null\");\n        Preconditions.checkNotNull(entity, \"entity cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        Optional<SuperiorPlayer> damagerSource = BukkitEntities.getPlayerSource(damager).map(plugin.getPlayers()::getSuperiorPlayer);\n\n        if (!damagerSource.isPresent())\n            return InteractionResult.SUCCESS;\n\n        List<EntityCategory> entityCategories = BukkitEntities.getCategories(entity);\n        if (!entityCategories.isEmpty()) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location entityLocation = entity.getLocation(wrapper.getHandle());\n\n                InteractionResult interactionResult;\n                for (EntityCategory entityCategory : entityCategories) {\n                    if (entityCategory.getDamagePrivilege() != null) {\n                        interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation,\n                                entityCategory.getDamagePrivilege(), 0, true, false);\n                        if (interactionResult != InteractionResult.SUCCESS) {\n                            if (damager instanceof Arrow && entity.getFireTicks() > 0)\n                                entity.setFireTicks(0);\n                            return interactionResult;\n                        }\n                    }\n                }\n            }\n        }\n\n        return InteractionResult.SUCCESS;\n    }\n\n    @Override\n    public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(vehicle, \"vehicle cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(vehicle.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        List<EntityCategory> entityCategories = BukkitEntities.getCategories(vehicle);\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = vehicle.getLocation(wrapper.getHandle());\n\n            if (!entityCategories.isEmpty()) {\n                InteractionResult interactionResult;\n                for (EntityCategory entityCategory : entityCategories) {\n                    if (entityCategory.getInteractPrivilege() != null) {\n                        interactionResult = handleInteractionInternal(superiorPlayer, entityLocation,\n                                entityCategory.getInteractPrivilege(), 0, true, false);\n                        if (interactionResult != InteractionResult.SUCCESS)\n                            return interactionResult;\n                    }\n                }\n            }\n\n            IslandPrivilege islandPrivilege = vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER;\n            return handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege,\n                    0, true, false);\n        }\n    }\n\n    @Override\n    public InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity entity) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(entity, \"entity cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = entity.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.ANIMAL_SHEAR,\n                    0, true, false);\n        }\n    }\n\n    @Override\n    public InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity entity) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(entity, \"entity cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location entityLocation = entity.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.LEASH,\n                    0, true, false);\n        }\n    }\n\n    @Override\n    public InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, Item item) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(item, \"item cannot be null\");\n\n        if (plugin.getNMSPlayers().wasThrownByPlayer(item, superiorPlayer))\n            return InteractionResult.SUCCESS;\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location itemLocation = item.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.PICKUP_DROPS,\n                    MAX_PICKUP_DISTANCE, true, false);\n        }\n    }\n\n    @Override\n    public InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Item item) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(item, \"item cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location itemLocation = item.getLocation(wrapper.getHandle());\n            return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.DROP_ITEMS,\n                    0, true, false);\n        }\n    }\n\n    @Override\n    public InteractionResult handlePlayerEnderPearl(SuperiorPlayer superiorPlayer, Location destination) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(destination, \"destination cannot be null\");\n        Preconditions.checkArgument(destination.getWorld() != null, \"destination's world cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(destination.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        return handleInteractionInternal(superiorPlayer, destination, IslandPrivileges.ENDER_PEARL,\n                0, true, false);\n    }\n\n    @Override\n    public InteractionResult handlePlayerConsumeChorusFruit(SuperiorPlayer superiorPlayer, Location location) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world cannot be null\");\n\n        if (IslandPrivileges.CHORUS_FRUIT == null) {\n            // Chorus Fruit privilege does not exist, we will just return SUCCESS in this case.\n            return InteractionResult.SUCCESS;\n        }\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.CHORUS_FRUIT,\n                0, true, true);\n    }\n\n    @Override\n    public InteractionResult handlePlayerUseWindCharge(SuperiorPlayer superiorPlayer, Location location) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world cannot be null\");\n\n        if (IslandPrivileges.WIND_CHARGE == null) {\n            // Wind Charge privilege does not exist, we will just return SUCCESS in this case.\n            return InteractionResult.SUCCESS;\n        }\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.WIND_CHARGE,\n                0, true, true);\n    }\n\n    @Override\n    public InteractionResult handleCustomInteraction(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkNotNull(islandPrivilege, \"islandPrivilege cannot be null\");\n\n        // We do not care about spawn island when spawn protection is disabled,\n        // and therefore only island worlds are relevant.\n        if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld()))\n            return InteractionResult.SUCCESS;\n\n        return handleInteractionInternal(superiorPlayer, location, islandPrivilege,\n                0, true, false);\n    }\n\n    private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location,\n                                                        IslandPrivilege islandPrivilege, int extraRadius,\n                                                        boolean checkIslandBoundaries, boolean checkRecalculation) {\n        return handleInteractionInternal(superiorPlayer, location, islandPrivilege, extraRadius, checkIslandBoundaries,\n                checkRecalculation, null, true);\n    }\n\n    private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location,\n                                                        IslandPrivilege islandPrivilege, int extraRadius,\n                                                        boolean checkIslandBoundaries, boolean checkRecalculation,\n                                                        @Nullable Island island, boolean callIslandLookup) {\n        if (superiorPlayer.hasBypassModeEnabled())\n            return InteractionResult.SUCCESS;\n\n        if (callIslandLookup) {\n            island = plugin.getGrid().getIslandAt(location);\n        }\n\n        if (checkIslandBoundaries && !WORLD_PERMISSIONS_CACHE.contains(islandPrivilege)) {\n            if (island == null && plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld()))\n                return InteractionResult.OUTSIDE_ISLAND;\n\n            if (island != null && !island.isInsideRange(location, extraRadius))\n                return InteractionResult.OUTSIDE_ISLAND;\n        }\n\n        if (island != null) {\n            if (!island.hasPermission(superiorPlayer, islandPrivilege))\n                return InteractionResult.MISSING_PRIVILEGE;\n\n            if (checkRecalculation && island.isBeingRecalculated())\n                return InteractionResult.ISLAND_RECALCULATE;\n        }\n\n        return InteractionResult.SUCCESS;\n    }\n\n    @Override\n    public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(from, \"from cannot be null\");\n        Preconditions.checkNotNull(to, \"to cannot be null\");\n\n        Island fromIsland = null;\n        boolean lookupFromIsland = true;\n\n        //Checking for out of distance from preview location.\n        IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer);\n        if (islandPreview != null) {\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                Location islandPreviewLocation = islandPreview.getLocation(wrapper.getHandle());\n                if (!islandPreviewLocation.getWorld().equals(to.getWorld()) ||\n                        islandPreviewLocation.distance(to) > plugin.getSettings().getIslandPreviews().getMaxDistance()) {\n                    islandPreview.handleEscape();\n                    return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR;\n                }\n            }\n        }\n\n        if (from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ()) {\n            // Handle moving while in teleport warmup.\n            BukkitTask teleportTask = superiorPlayer.getTeleportTask();\n            if (teleportTask != null) {\n                teleportTask.cancel();\n                superiorPlayer.setTeleportTask(null);\n                Message.TELEPORT_WARMUP_CANCEL.send(superiorPlayer);\n            }\n\n            MoveResult moveResult;\n\n            Island toIsland = plugin.getGrid().getIslandAt(to);\n            if (toIsland != null) {\n                moveResult = handlePlayerEnterIslandInternal(superiorPlayer, toIsland, from, to, IslandEnterEvent.EnterCause.PLAYER_MOVE);\n                if (moveResult != MoveResult.SUCCESS)\n                    return moveResult;\n            }\n\n            lookupFromIsland = false;\n\n            fromIsland = plugin.getGrid().getIslandAt(from);\n            if (fromIsland != null) {\n                moveResult = handlePlayerLeaveIslandInternal(superiorPlayer, fromIsland, from, to, IslandLeaveEvent.LeaveCause.PLAYER_MOVE);\n                if (moveResult != MoveResult.SUCCESS)\n                    return moveResult;\n            }\n        }\n\n        if (from.getBlockY() != to.getBlockY() && to.getBlockY() <= plugin.getNMSWorld().getMinHeight(to.getWorld()) - 5) {\n            if (lookupFromIsland) {\n                fromIsland = plugin.getGrid().getIslandAt(from);\n            }\n\n            if (fromIsland == null || (fromIsland.isVisitor(superiorPlayer, false) ?\n                    !plugin.getSettings().getVoidTeleport().isVisitors() : !plugin.getSettings().getVoidTeleport().isMembers()))\n                return MoveResult.SUCCESS;\n\n            Log.debug(Debug.VOID_TELEPORT, superiorPlayer.getName());\n\n            superiorPlayer.setPlayerStatus(PlayerStatus.VOID_TELEPORT);\n\n            superiorPlayer.teleport(fromIsland, result -> {\n                if (!result) {\n                    Message.TELEPORTED_FAILED.send(superiorPlayer);\n                    superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), result2 -> {\n                        forgetVoidTeleportPlayerStatus(superiorPlayer);\n                    });\n                } else {\n                    forgetVoidTeleportPlayerStatus(superiorPlayer);\n                }\n            });\n\n            return MoveResult.VOID_TELEPORT;\n        }\n\n        return MoveResult.SUCCESS;\n    }\n\n    private void forgetVoidTeleportPlayerStatus(SuperiorPlayer superiorPlayer) {\n        BukkitExecutor.sync(() -> {\n            superiorPlayer.removePlayerStatus(PlayerStatus.VOID_TELEPORT);\n        }, 40L);\n    }\n\n    @Override\n    public MoveResult handlePlayerTeleport(SuperiorPlayer superiorPlayer, Location from, Location to) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(from, \"from cannot be null\");\n        Preconditions.checkArgument(from.getWorld() != null, \"from world cannot be null\");\n        Preconditions.checkNotNull(to, \"to cannot be null\");\n        Preconditions.checkArgument(to.getWorld() != null, \"from world cannot be null\");\n\n        Island toIsland = plugin.getGrid().getIslandAt(to);\n        if (toIsland != null) {\n            MoveResult enterMove = handlePlayerEnterIslandInternal(superiorPlayer, toIsland, from, to, IslandEnterEvent.EnterCause.PLAYER_TELEPORT);\n            if (enterMove != MoveResult.SUCCESS)\n                return enterMove;\n        }\n\n        Island fromIsland = plugin.getGrid().getIslandAt(from);\n        if (fromIsland != null) {\n            return handlePlayerLeaveIslandInternal(superiorPlayer, fromIsland, from, to, IslandLeaveEvent.LeaveCause.PLAYER_TELEPORT);\n        }\n\n        return MoveResult.SUCCESS;\n    }\n\n    @Override\n    public MoveResult handlePlayerTeleportByPortal(SuperiorPlayer superiorPlayer, Location portalLocation, Location teleportLocation) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(portalLocation, \"portalLocation cannot be null\");\n        Preconditions.checkNotNull(portalLocation.getWorld(), \"portalLocation world cannot be null\");\n        Preconditions.checkNotNull(teleportLocation, \"teleportLocation cannot be null\");\n        Preconditions.checkNotNull(teleportLocation.getWorld(), \"teleportLocation world cannot be null\");\n\n        Island island = plugin.getGrid().getIslandAt(teleportLocation);\n        if (island != null) {\n            return handlePlayerEnterIslandInternal(superiorPlayer, island, portalLocation, teleportLocation, IslandEnterEvent.EnterCause.PORTAL);\n        }\n\n        return MoveResult.SUCCESS;\n    }\n\n    @Override\n    public MoveResult handlePlayerJoin(SuperiorPlayer superiorPlayer, Location location) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world cannot be null\");\n\n        Island island = plugin.getGrid().getIslandAt(location);\n\n        return island == null ? MoveResult.SUCCESS : handlePlayerEnterIslandInternal(superiorPlayer, island, null, location, IslandEnterEvent.EnterCause.PLAYER_JOIN);\n    }\n\n    @Override\n    public MoveResult handlePlayerQuit(SuperiorPlayer superiorPlayer, Location location) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n\n        Island island = plugin.getGrid().getIslandAt(location);\n        if (island == null)\n            return MoveResult.SUCCESS;\n\n        island.setPlayerInside(superiorPlayer, false);\n        return handlePlayerLeaveIslandInternal(superiorPlayer, island, location, null, IslandLeaveEvent.LeaveCause.PLAYER_QUIT);\n    }\n\n    private MoveResult handlePlayerEnterIslandInternal(SuperiorPlayer superiorPlayer, Island toIsland, @Nullable Location from, Location to, IslandEnterEvent.EnterCause enterCause) {\n        // This can happen after the leave event is cancelled.\n        if (superiorPlayer.hasPlayerStatus(PlayerStatus.LEAVING_ISLAND)) {\n            superiorPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND);\n            return MoveResult.SUCCESS;\n        }\n\n        // Checking if the player is banned from the island.\n        if (toIsland.isBanned(superiorPlayer) && !superiorPlayer.hasBypassModeEnabled() && !superiorPlayer.hasPermissionWithoutOP(\"superior.admin.ban.bypass\")) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.BANNED_FROM_ISLAND);\n            Message.BANNED_FROM_ISLAND.send(superiorPlayer);\n            return MoveResult.BANNED_FROM_ISLAND;\n        }\n\n        // Checking if the player is locked to visitors.\n        if (toIsland.isLocked() && !toIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LOCKED_ISLAND);\n            Message.NO_CLOSE_BYPASS.send(superiorPlayer);\n            return MoveResult.ISLAND_LOCKED;\n        }\n\n        Island fromIsland = from == null ? null : plugin.getGrid().getIslandAt(from);\n\n        boolean equalIslands = toIsland.equals(fromIsland);\n        boolean toInsideRange = toIsland.isInsideRange(to);\n        boolean fromInsideRange = from != null && fromIsland != null && fromIsland.isInsideRange(from);\n        boolean equalWorlds = from != null && to.getWorld().equals(from.getWorld());\n\n        if (toInsideRange && (!equalIslands || !fromInsideRange) && !PluginEventsFactory.callIslandEnterProtectedEvent(toIsland, superiorPlayer, enterCause)) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_PROTECTED_EVENT_CANCELLED);\n            return MoveResult.ENTER_EVENT_CANCELLED;\n        }\n\n        if (equalIslands) {\n            if (!equalWorlds) {\n                BukkitExecutor.sync(() -> plugin.getNMSWorld().setWorldBorder(superiorPlayer, toIsland), 1L);\n                superiorPlayer.setPlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n                BukkitExecutor.sync(() -> {\n                    superiorPlayer.removePlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n                }, 100L);\n            }\n\n            return MoveResult.SUCCESS;\n        }\n\n        if (!PluginEventsFactory.callIslandEnterEvent(toIsland, superiorPlayer, enterCause)) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_EVENT_CANCELLED);\n            return MoveResult.ENTER_EVENT_CANCELLED;\n        }\n\n        toIsland.setPlayerInside(superiorPlayer, true);\n\n        if (!toIsland.isMember(superiorPlayer) && toIsland.hasSettingsEnabled(IslandFlags.PVP)) {\n            Message.ENTER_PVP_ISLAND.send(superiorPlayer);\n            if (plugin.getSettings().isImmuneToPvPWhenTeleport()) {\n                superiorPlayer.setPlayerStatus(PlayerStatus.PVP_IMMUNED);\n                BukkitExecutor.sync(() -> {\n                    superiorPlayer.removePlayerStatus(PlayerStatus.PVP_IMMUNED);\n                }, 200L);\n            }\n        }\n\n        superiorPlayer.setPlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n        BukkitExecutor.sync(() -> {\n            superiorPlayer.removePlayerStatus(PlayerStatus.PORTALS_IMMUNED);\n        }, 100L);\n\n        Player player = superiorPlayer.asPlayer();\n        if (player != null && (plugin.getSettings().getSpawn().isProtected() || !toIsland.isSpawn())) {\n            BukkitExecutor.sync(() -> {\n                // Update player time and player weather with a delay.\n                // Fixes https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1260\n                if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_DAY)) {\n                    player.setPlayerTime(0, false);\n                } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_MIDDLE_DAY)) {\n                    player.setPlayerTime(6000, false);\n                } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_NIGHT)) {\n                    player.setPlayerTime(14000, false);\n                } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_MIDDLE_NIGHT)) {\n                    player.setPlayerTime(18000, false);\n                }\n\n                if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_SHINY)) {\n                    player.setPlayerWeather(WeatherType.CLEAR);\n                } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_RAIN)) {\n                    player.setPlayerWeather(WeatherType.DOWNFALL);\n                }\n            }, 1L);\n        }\n\n        if (superiorPlayer.hasIslandFlyEnabled() && !superiorPlayer.hasFlyGamemode()) {\n            BukkitExecutor.sync(() -> {\n                if (player != null) toIsland.updateIslandFly(superiorPlayer);\n            }, 5L);\n        }\n\n        BukkitExecutor.sync(() -> {\n            toIsland.applyEffects(superiorPlayer);\n            plugin.getNMSWorld().setWorldBorder(superiorPlayer, toIsland);\n        }, 1L);\n\n        return MoveResult.SUCCESS;\n    }\n\n    private MoveResult handlePlayerLeaveIslandInternal(SuperiorPlayer superiorPlayer, Island fromIsland, Location from, @Nullable Location to, IslandLeaveEvent.LeaveCause leaveCause) {\n        Island toIsland = to == null ? null : plugin.getGrid().getIslandAt(to);\n\n        boolean equalWorlds = to != null && from.getWorld().equals(to.getWorld());\n        boolean equalIslands = fromIsland.equals(toIsland);\n        boolean fromInsideRange = fromIsland.isInsideRange(from);\n        boolean toInsideRange = to != null && toIsland != null && toIsland.isInsideRange(to);\n\n        //Checking for the stop leaving feature.\n        if (plugin.getSettings().isStopLeaving() && fromInsideRange && !toInsideRange && !superiorPlayer.hasBypassModeEnabled() && !fromIsland.isSpawn() && equalWorlds) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_ISLAND_TO_OUTSIDE);\n            superiorPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND);\n            return MoveResult.LEAVE_ISLAND_TO_OUTSIDE;\n        }\n\n        // Handling the leave protected event\n        if (fromInsideRange && (!equalIslands || !toInsideRange)) {\n            if (!PluginEventsFactory.callIslandLeaveProtectedEvent(fromIsland, superiorPlayer, leaveCause, to)) {\n                PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_PROTECTED_EVENT_CANCELLED);\n                return MoveResult.ENTER_EVENT_CANCELLED;\n            }\n        }\n\n        if (equalIslands)\n            return MoveResult.SUCCESS;\n\n        if (!PluginEventsFactory.callIslandLeaveEvent(fromIsland, superiorPlayer, leaveCause, to)) {\n            PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_EVENT_CANCELLED);\n            return MoveResult.ENTER_EVENT_CANCELLED;\n        }\n\n        fromIsland.setPlayerInside(superiorPlayer, false);\n\n        Player player = superiorPlayer.asPlayer();\n        if (player != null) {\n            player.resetPlayerTime();\n            player.resetPlayerWeather();\n            fromIsland.removeEffects(superiorPlayer);\n\n            if (superiorPlayer.hasIslandFlyEnabled() && (toIsland == null || toIsland.isSpawn()) && !superiorPlayer.hasFlyGamemode()) {\n                player.setAllowFlight(false);\n                player.setFlying(false);\n                Message.ISLAND_FLY_DISABLED.send(player);\n            }\n        }\n\n        if (toIsland == null) plugin.getNMSWorld().setWorldBorder(superiorPlayer, null);\n\n        return MoveResult.SUCCESS;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.stackedblocks;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.Either;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.key.BaseKey;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.bgsoftware.superiorskyblock.service.region.ProtectionHelper;\nimport com.bgsoftware.superiorskyblock.world.BukkitItems;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.GameMode;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.OfflinePlayer;\nimport org.bukkit.block.Block;\nimport org.bukkit.entity.Player;\nimport org.bukkit.inventory.EquipmentSlot;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.math.BigInteger;\n\npublic class StackedBlocksInteractionServiceImpl implements StackedBlocksInteractionService, IService {\n\n    private static final KeyMap<Key> BLOCK_KEY_TRANSFORMER = createBlockKeyTransformer();\n\n    private final LazyReference<RegionManagerService> regionManagerService = new LazyReference<RegionManagerService>() {\n        @Override\n        protected RegionManagerService create() {\n            return plugin.getServices().getService(RegionManagerService.class);\n        }\n    };\n    private final SuperiorSkyblockPlugin plugin;\n\n    public StackedBlocksInteractionServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return StackedBlocksInteractionService.class;\n    }\n\n    @Override\n    public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, EquipmentSlot usedHand) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n        Preconditions.checkNotNull(usedHand, \"usedHand cannot be null\");\n\n        if (!plugin.getSettings().getStackedBlocks().isEnabled())\n            return InteractionResult.STACKED_BLOCKS_DISABLED;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.DISABLED_WORLD;\n\n        Player onlinePlayer = superiorPlayer.asPlayer();\n        ItemStack handItem = onlinePlayer == null ? null : BukkitItems.getHandItem(onlinePlayer, PlayerHand.of(usedHand));\n\n        InteractionResult interactionResult = checkBlockStackInternal(superiorPlayer, block, handItem);\n        if (interactionResult != InteractionResult.SUCCESS)\n            return interactionResult;\n\n        int amountToDeposit = onlinePlayer == null ? 1 : handItem == null ? 1 : onlinePlayer.isSneaking() ? handItem.getAmount() : 1;\n\n        return handleBlockStackInternal(superiorPlayer, block, amountToDeposit, Either.left(usedHand));\n    }\n\n    @Override\n    public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block,\n                                                     int amountToDeposit, OnItemRemovalCallback itemRemovalCallback) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer cannot be null\");\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n        Preconditions.checkNotNull(itemRemovalCallback, \"itemRemovalCallback cannot be null\");\n\n        if (!plugin.getSettings().getStackedBlocks().isEnabled())\n            return InteractionResult.STACKED_BLOCKS_DISABLED;\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.DISABLED_WORLD;\n\n        InteractionResult interactionResult = checkBlockStackInternal(superiorPlayer, block, null);\n        if (interactionResult != InteractionResult.SUCCESS)\n            return interactionResult;\n\n        return handleBlockStackInternal(superiorPlayer, block, amountToDeposit, Either.right(itemRemovalCallback));\n    }\n\n    @Override\n    public InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPlayer, Block block, ItemStack itemStack) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null\");\n        Preconditions.checkNotNull(block, \"block parameter cannot be null\");\n        Preconditions.checkNotNull(itemStack, \"itemStack parameter cannot be null\");\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.DISABLED_WORLD;\n\n        return checkBlockStackInternal(superiorPlayer, block, itemStack);\n    }\n\n    @Override\n    public InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer) {\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n\n        // We do not care about spawn island, and therefore only island worlds are relevant.\n        if (!plugin.getGrid().isIslandsWorld(block.getWorld()))\n            return InteractionResult.DISABLED_WORLD;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location blockLocation = block.getLocation(wrapper.getHandle());\n\n            int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation);\n            if (blockAmount <= 1)\n                return InteractionResult.NOT_STACKED_BLOCK;\n\n            Island island = plugin.getGrid().getIslandAt(blockLocation);\n            if (superiorPlayer != null && island != null) {\n                com.bgsoftware.superiorskyblock.api.service.region.InteractionResult interactionResult =\n                        this.regionManagerService.get().handleBlockBreak(superiorPlayer, block);\n                if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true))\n                    return InteractionResult.STACKED_BLOCK_PROTECTED;\n            }\n\n            Player onlinePlayer = superiorPlayer == null ? null : superiorPlayer.asPlayer();\n\n            int amountToBreak = Math.min(blockAmount, onlinePlayer != null && onlinePlayer.isSneaking() ? 64 : 1);\n\n            int leftAmount = blockAmount - amountToBreak;\n\n            if (!PluginEventsFactory.callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount))\n                return InteractionResult.EVENT_CANCELLED;\n\n            if (!plugin.getStackedBlocks().setStackedBlock(block, leftAmount))\n                return InteractionResult.GLITCHED_STACKED_BLOCK;\n\n            plugin.getNMSWorld().playBreakAnimation(block);\n\n            if (superiorPlayer != null) {\n                OfflinePlayer offlinePlayer = onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer;\n                plugin.getProviders().notifyStackedBlocksListeners(offlinePlayer, block, IStackedBlocksListener.Action.BLOCK_BREAK);\n            }\n\n            if (island != null)\n                island.handleBlockBreak(block, amountToBreak);\n\n            ItemStack blockItem = ServerVersion.isLegacy() ?\n                    block.getState().getData().toItemStack(amountToBreak) :\n                    new ItemStack(block.getType(), amountToBreak);\n\n            if (leftAmount <= 0)\n                block.setType(Material.AIR);\n\n            // Dropping the item\n            if (onlinePlayer != null && plugin.getSettings().getStackedBlocks().isAutoCollect()) {\n                BukkitItems.addItem(blockItem, onlinePlayer.getInventory(), blockLocation);\n            } else {\n                block.getWorld().dropItemNaturally(blockLocation.add(0, 0.5, 0), blockItem);\n            }\n        }\n\n        return InteractionResult.SUCCESS;\n    }\n\n    private InteractionResult checkBlockStackInternal(SuperiorPlayer superiorPlayer, Block block, @Nullable ItemStack itemStack) {\n        if (!superiorPlayer.hasBlocksStackerEnabled())\n            return InteractionResult.PLAYER_STACKED_BLOCKS_DISABLED;\n\n        if (plugin.getSettings().getStackedBlocks().getDisabledWorlds().contains(block.getWorld().getName()))\n            return InteractionResult.DISABLED_WORLD;\n\n        Key blockKey = Keys.of(block);\n\n        if (itemStack != null) {\n            if (itemStack.hasItemMeta() && (itemStack.getItemMeta().hasDisplayName() || itemStack.getItemMeta().hasLore()))\n                return InteractionResult.CUSTOMIZED_ITEM;\n\n            Key itemKey = Keys.of(itemStack);\n            if (!itemKey.equals(blockKey))\n                return InteractionResult.PLAYER_HOLDING_DIFFERENT_ITEM;\n        }\n\n        Material blockType = block.getType();\n\n        if (!superiorPlayer.hasPermission(\"superior.island.stacker.*\") &&\n                !superiorPlayer.hasPermission(\"superior.island.stacker.\" + blockType))\n            return InteractionResult.PLAYER_MISSING_PERMISSION;\n\n        Key newBlockKey = BLOCK_KEY_TRANSFORMER.getOrDefault(blockKey, blockKey);\n\n        KeySet whitelist = (KeySet) plugin.getSettings().getStackedBlocks().getWhitelisted();\n\n        if (!whitelist.contains(newBlockKey))\n            return InteractionResult.STACKED_BLOCK_NOT_WHITELISTED;\n\n        return InteractionResult.SUCCESS;\n    }\n\n    private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock,\n                                                       int amountToDeposit,\n                                                       Either<EquipmentSlot, OnItemRemovalCallback> removalData) {\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return handleBlockStackInternal(superiorPlayer, stackedBlock, stackedBlock.getLocation(wrapper.getHandle()),\n                    amountToDeposit, removalData);\n        }\n    }\n\n    private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock,\n                                                       Location stackedBlockLocation, int amountToDeposit,\n                                                       Either<EquipmentSlot, OnItemRemovalCallback> removalData) {\n        Player onlinePlayer = superiorPlayer.asPlayer();\n\n        int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(stackedBlockLocation);\n        Key blockKey = plugin.getStackedBlocks().getStackedBlockKey(stackedBlockLocation);\n        if (blockKey == null)\n            blockKey = Keys.of(stackedBlock);\n\n        int blockLimit = plugin.getSettings().getStackedBlocks().getLimits().getOrDefault(blockKey, Integer.MAX_VALUE);\n        // We make sure the amountToDeposit does not exceed the block limit\n        if (blockAmount + amountToDeposit > blockLimit)\n            amountToDeposit = blockLimit - blockAmount;\n\n        if (amountToDeposit <= 0) {\n            // Inform GUI/caller that nothing was deposited so it can refund its previewed removal\n            removalData.ifRight(cb -> cb.accept(0));\n            return InteractionResult.NOT_ENOUGH_BLOCKS;\n        }\n\n        Island island = plugin.getGrid().getIslandAt(stackedBlockLocation);\n        if (island != null) {\n            // We ensure we do not exceed island's block limit\n            BigInteger amountToDepositBig = BigInteger.valueOf(amountToDeposit);\n\n            // Checking for the specific block key\n            BigInteger islandBlockLimit = BigInteger.valueOf(island.getExactBlockLimit(blockKey));\n            BigInteger islandBlockCount = island.getBlockCountAsBigInteger(blockKey);\n            if (islandBlockLimit.compareTo(BigInteger.ZERO) >= 0 &&\n                    islandBlockCount.add(amountToDepositBig).compareTo(islandBlockLimit) > 0) {\n                amountToDeposit = islandBlockLimit.subtract(islandBlockCount).intValue();\n            } else {\n                // Checking for the global block key\n                Key globalKey = ((BaseKey<?>) blockKey).toGlobalKey();\n                islandBlockLimit = BigInteger.valueOf(island.getExactBlockLimit(globalKey));\n                islandBlockCount = island.getBlockCountAsBigInteger(globalKey);\n                if (islandBlockLimit.compareTo(BigInteger.ZERO) >= 0 &&\n                        islandBlockCount.add(amountToDepositBig).compareTo(islandBlockLimit) > 0) {\n                    amountToDeposit = islandBlockLimit.subtract(islandBlockCount).intValue();\n                }\n            }\n        }\n\n        if (amountToDeposit <= 0) {\n            // Island/global limit reached ⇒ notify caller so it can refund\n            removalData.ifRight(cb -> cb.accept(0));\n            return InteractionResult.NOT_ENOUGH_BLOCKS;\n        }\n\n        int newStackedBlockAmount = blockAmount + amountToDeposit;\n\n        if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) {\n            // Event cancelled ⇒ nothing deposited, request refund\n            removalData.ifRight(cb -> cb.accept(0));\n            return InteractionResult.EVENT_CANCELLED;\n        }\n\n        if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) {\n            // Failed to persist/update ⇒ request refund\n            removalData.ifRight(cb -> cb.accept(0));\n            return InteractionResult.GLITCHED_STACKED_BLOCK;\n        }\n\n        if (island != null)\n            island.handleBlockPlace(blockKey, amountToDeposit);\n\n        plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer,\n                stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE);\n\n        final int finalAmountToDeposit = amountToDeposit;\n\n        removalData.ifRight(itemRemovalCallback -> itemRemovalCallback.accept(finalAmountToDeposit)).ifLeft(usedHand -> {\n            if (onlinePlayer != null && onlinePlayer.getGameMode() != GameMode.CREATIVE) {\n                BukkitItems.removeHandItem(onlinePlayer, PlayerHand.of(usedHand), finalAmountToDeposit);\n            }\n        });\n\n        return InteractionResult.SUCCESS;\n    }\n\n    private static KeyMap<Key> createBlockKeyTransformer() {\n        KeyMap<Key> blockKeyTransformer = KeyMaps.createArrayMap(KeyIndicator.MATERIAL);\n\n        Material GLOWING_REDSTONE_ORE = EnumHelper.getEnum(Material.class, \"GLOWING_REDSTONE_ORE\");\n        if (GLOWING_REDSTONE_ORE != null)\n            blockKeyTransformer.put(Keys.of(GLOWING_REDSTONE_ORE), Keys.of(Material.REDSTONE_ORE));\n\n        return KeyMaps.unmodifiableKeyMap(blockKeyTransformer);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksServiceHelper.java",
    "content": "package com.bgsoftware.superiorskyblock.service.stackedblocks;\n\nimport com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult;\n\npublic class StackedBlocksServiceHelper {\n\n    private StackedBlocksServiceHelper() {\n\n    }\n\n    public static boolean shouldCancelOriginalEvent(InteractionResult result) {\n        switch (result) {\n            case STACKED_BLOCK_PROTECTED:\n            case EVENT_CANCELLED:\n            case SUCCESS:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.service.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.service.world.RecordResult;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags;\nimport com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService;\nimport com.bgsoftware.superiorskyblock.core.Materials;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits;\nimport com.bgsoftware.superiorskyblock.service.IService;\nimport com.bgsoftware.superiorskyblock.world.BukkitEntities;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.block.BlockState;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Minecart;\n\nimport java.util.EnumMap;\n\npublic class WorldRecordServiceImpl implements WorldRecordService, IService {\n\n    @WorldRecordFlags\n    private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS;\n    private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{\n            BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST\n    };\n\n    private final SuperiorSkyblockPlugin plugin;\n\n    public WorldRecordServiceImpl(SuperiorSkyblockPlugin plugin) {\n        this.plugin = plugin;\n    }\n\n    @Override\n    public Class<?> getAPIClass() {\n        return WorldRecordService.class;\n    }\n\n    @Override\n    public RecordResult recordBlockPlace(Block block, int blockCount, @Nullable BlockState oldBlockState,\n                                         @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return recordBlockPlace(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, oldBlockState, flags);\n        }\n    }\n\n    @Override\n    public RecordResult recordBlockPlace(Key blockKey, Location blockLocation, int blockCount,\n                                         @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(blockKey, \"blockKey cannot be null\");\n        Preconditions.checkNotNull(blockLocation, \"blockLocation cannot be null\");\n        Preconditions.checkArgument(blockLocation.getWorld() != null, \"blockLocation's world cannot be null\");\n\n        Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        recordBlockPlaceInternal(island, blockKey, blockLocation, blockCount, oldBlockState, flags);\n        return RecordResult.SUCCESS;\n    }\n\n    @Override\n    public RecordResult recordMultiBlocksPlace(KeyMap<Integer> blockCounts, Location location,\n                                               @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(blockCounts, \"blockCounts cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world cannot be null\");\n\n        if (blockCounts.isEmpty())\n            return RecordResult.SUCCESS;\n\n        Island island = plugin.getGrid().getIslandAt(location);\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0;\n        boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0;\n\n        int blockPlaceFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS |\n                (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0);\n        island.handleBlocksPlace(blockCounts, blockPlaceFlags);\n\n        if (dirtyChunks) {\n            island.markChunkDirty(location.getWorld(), location.getBlockX() >> 4,\n                    location.getBlockZ() >> 4, true);\n        }\n\n        return RecordResult.SUCCESS;\n    }\n\n    private void recordBlockPlaceInternal(Island island, Key blockKey, Location blockLocation, int blockCount,\n                                          @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) {\n        boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0;\n        boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0;\n\n        if (oldBlockState != null && oldBlockState.getType() != Material.AIR) {\n            Material blockStateType = oldBlockState.getType();\n            Key oldBlockKey;\n            int oldBlockCount = 1;\n\n            if (Materials.isLava(blockStateType)) {\n                oldBlockKey = ConstantKeys.LAVA;\n            } else if (Materials.isWater(blockStateType)) {\n                oldBlockKey = ConstantKeys.WATER;\n            } else {\n                oldBlockKey = Keys.of(oldBlockState);\n                oldBlockCount = plugin.getNMSWorld().getDefaultAmount(oldBlockState);\n            }\n\n            recordBlockBreakInternal(island, oldBlockKey, blockLocation, oldBlockCount, flags);\n        }\n\n        if (blockKey.equals(ConstantKeys.END_PORTAL_FRAME_WITH_EYE))\n            recordBlockBreakInternal(island, ConstantKeys.END_PORTAL_FRAME, blockLocation, 1, flags);\n\n        if (plugin.getProviders().shouldListenToSpawnerChanges() || !(blockKey instanceof SpawnerKey)) {\n            int blockPlaceFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS;\n            if (saveBlockCounts) blockPlaceFlags |= IslandBlockFlags.SAVE_BLOCK_COUNTS;\n            island.handleBlockPlace(blockKey, blockCount, blockPlaceFlags);\n        }\n\n        if (dirtyChunks) {\n            island.markChunkDirty(blockLocation.getWorld(), blockLocation.getBlockX() >> 4,\n                    blockLocation.getBlockZ() >> 4, true);\n        }\n    }\n\n    @Override\n    public RecordResult recordBlockBreak(Block block, @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n        return recordBlockBreak(block, plugin.getNMSWorld().getDefaultAmount(block), flags);\n    }\n\n    @Override\n    public RecordResult recordBlockBreak(Block block, int blockCount, @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(block, \"block cannot be null\");\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return recordBlockBreak(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, flags);\n        }\n    }\n\n    @Override\n    public RecordResult recordBlockBreak(Key blockKey, Location blockLocation, int blockCount, @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(blockKey, \"blockKey cannot be null\");\n        Preconditions.checkNotNull(blockLocation, \"blockLocation cannot be null\");\n        Preconditions.checkArgument(blockLocation.getWorld() != null, \"blockLocation's world cannot be null\");\n\n        Island island = plugin.getGrid().getIslandAt(blockLocation);\n\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        recordBlockBreakInternal(island, blockKey, blockLocation, blockCount, flags);\n        return RecordResult.SUCCESS;\n    }\n\n    @Override\n    public RecordResult recordMultiBlocksBreak(KeyMap<Integer> blockCounts, Location location,\n                                               @WorldRecordFlags int flags) {\n        Preconditions.checkNotNull(blockCounts, \"blockCounts cannot be null\");\n        Preconditions.checkNotNull(location, \"location cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world cannot be null\");\n\n        if (blockCounts.isEmpty())\n            return RecordResult.SUCCESS;\n\n        Island island = plugin.getGrid().getIslandAt(location);\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0;\n        boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0;\n\n        int blockBreakFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS |\n                (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0);\n\n        island.handleBlocksBreak(blockCounts, blockBreakFlags);\n\n        if (dirtyChunks && plugin.getNMSChunks().isChunkEmpty(location.getChunk())) {\n            island.markChunkEmpty(location.getWorld(), location.getBlockX() >> 4,\n                    location.getBlockZ() >> 4, true);\n        }\n\n        return RecordResult.SUCCESS;\n    }\n\n    private void recordBlockBreakInternal(Island island, Key blockKey, Location blockLocation, int blockCount,\n                                          @WorldRecordFlags int flags) {\n        boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0;\n        boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0;\n        boolean handleNearbyBlocks = (flags & WorldRecordFlags.HANDLE_NEARBY_BLOCKS) != 0;\n\n        int handleBlockBreakFlag = IslandBlockFlags.UPDATE_LAST_TIME_STATUS |\n                (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0);\n\n        if (plugin.getProviders().shouldListenToSpawnerChanges() || !(blockKey instanceof SpawnerKey))\n            island.handleBlockBreak(blockKey, blockCount, handleBlockBreakFlag);\n\n        if (handleNearbyBlocks || dirtyChunks) {\n            EnumMap<BlockFace, Key> nearbyBlocks = new EnumMap<>(BlockFace.class);\n            Block block = blockLocation.getBlock();\n\n            if (handleNearbyBlocks) {\n                for (BlockFace nearbyFace : NEARBY_BLOCKS) {\n                    Block nearbyBlock = block.getRelative(nearbyFace);\n                    Material blockType = nearbyBlock.getType();\n                    if (blockType != Material.AIR && !blockType.isSolid()) {\n                        Key nearbyBlockKey = Keys.of(nearbyBlock);\n                        nearbyBlocks.put(nearbyFace, nearbyBlockKey);\n                    }\n                }\n            }\n\n            BukkitExecutor.sync(() -> {\n                if (dirtyChunks) {\n                    if (plugin.getNMSChunks().isChunkEmpty(block.getChunk())) {\n                        island.markChunkEmpty(block.getWorld(), block.getX() >> 4,\n                                block.getZ() >> 4, true);\n                    }\n                }\n                if (handleNearbyBlocks) {\n                    for (BlockFace nearbyFace : NEARBY_BLOCKS) {\n                        Key nearbyBlock = Keys.of(block.getRelative(nearbyFace));\n                        Key oldNearbyBlock = nearbyBlocks.getOrDefault(nearbyFace, ConstantKeys.AIR);\n                        if (oldNearbyBlock != ConstantKeys.AIR && !nearbyBlock.equals(oldNearbyBlock)) {\n                            island.handleBlockBreak(oldNearbyBlock, 1, handleBlockBreakFlag);\n                        }\n                    }\n                }\n            }, 2L);\n        }\n    }\n\n    @Override\n    public RecordResult recordEntitySpawn(Entity entity) {\n        Preconditions.checkNotNull(entity, \"entity parameter cannot be null\");\n\n        if (entity.isDead())\n            return RecordResult.ENTITY_CANNOT_BE_TRACKED;\n\n        if (BukkitEntities.canBypassEntityLimit(entity))\n            return RecordResult.ENTITY_CANNOT_BE_TRACKED;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            return recordEntitySpawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle()));\n        }\n    }\n\n    @Override\n    public RecordResult recordEntitySpawn(EntityType entityType, Location location) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null\");\n        Preconditions.checkNotNull(location, \"location parameter cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world parameter cannot be null\");\n\n        return recordEntitySpawnInternal(entityType, location);\n    }\n\n    private RecordResult recordEntitySpawnInternal(EntityType entityType, Location location) {\n        if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) ||\n                !BukkitEntities.canHaveLimit(entityType))\n            return RecordResult.ENTITY_CANNOT_BE_TRACKED;\n\n        Island island = plugin.getGrid().getIslandAt(location);\n\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        island.getEntitiesTracker().trackEntity(Keys.of(entityType), 1);\n        // TODO: elsewhere\n        IslandsDatabaseBridge.saveEntityCounts(island);\n\n\n        return RecordResult.SUCCESS;\n    }\n\n    @Override\n    public RecordResult recordEntityDespawn(Entity entity) {\n        Preconditions.checkNotNull(entity, \"entity parameter cannot be null\");\n\n        if (BukkitEntities.canBypassEntityLimit(entity))\n            return RecordResult.ENTITY_CANNOT_BE_TRACKED;\n\n        RecordResult recordResult;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            recordResult = recordEntityDespawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle()));\n        }\n        if (recordResult != RecordResult.SUCCESS)\n            return recordResult;\n\n        if (entity instanceof Minecart) {\n            Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) entity);\n            try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS);\n            }\n        }\n\n        return RecordResult.SUCCESS;\n    }\n\n    @Override\n    public RecordResult recordEntityDespawn(EntityType entityType, Location location) {\n        Preconditions.checkNotNull(entityType, \"entityType parameter cannot be null\");\n        Preconditions.checkNotNull(location, \"location parameter cannot be null\");\n        Preconditions.checkArgument(location.getWorld() != null, \"location's world parameter cannot be null\");\n\n        return recordEntityDespawnInternal(entityType, location);\n    }\n\n    private RecordResult recordEntityDespawnInternal(EntityType entityType, Location location) {\n        if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) ||\n                !BukkitEntities.canHaveLimit(entityType))\n            return RecordResult.ENTITY_CANNOT_BE_TRACKED;\n\n        Island island = plugin.getGrid().getIslandAt(location);\n\n        if (island == null)\n            return RecordResult.NOT_IN_ISLAND;\n\n        island.getEntitiesTracker().untrackEntity(Keys.of(entityType), 1);\n        // TODO: not here\n        IslandsDatabaseBridge.saveEntityCounts(island);\n\n        return RecordResult.SUCCESS;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.math.MathContext;\n\npublic class BigDecimalTag extends Tag<BigDecimal> {\n\n    private BigDecimalTag(BigDecimal value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeInt(value.scale());\n        os.writeInt(value.precision());\n\n        byte[] data = value.toBigIntegerExact().toByteArray();\n        os.writeInt(data.length);\n        os.write(data);\n    }\n\n    public static BigDecimalTag of(BigDecimal value) {\n        return new BigDecimalTag(value);\n    }\n\n    public static BigDecimalTag fromStream(DataInputStream is) throws IOException {\n        int scale = is.readInt();\n        int precision = is.readInt();\n        byte[] data = new byte[is.readInt()];\n        is.readFully(data);\n\n        return BigDecimalTag.of(new BigDecimal(new BigInteger(data), scale, new MathContext(precision)));\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.Locale;\n\n/**\n * The <code>TAG_Byte_Array</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class ByteArrayTag extends Tag<byte[]> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagByteArray\", \"ByteArrayTag\"}, byte[].class);\n\n    private static final ByteArrayTag EMPTY = new ByteArrayTag(new byte[0]);\n\n    private ByteArrayTag(byte[] value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeInt(value.length);\n        os.write(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder hex = new StringBuilder();\n        for (byte b : value) {\n            String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ENGLISH);\n            if (hexDigits.length() == 1) {\n                hex.append(\"0\");\n            }\n            hex.append(hexDigits).append(\" \");\n        }\n        return \"TAG_Byte_Array: \" + hex;\n    }\n\n    public static ByteArrayTag of(byte[] value) {\n        return value.length == 0 ? EMPTY : new ByteArrayTag(value);\n    }\n\n    public static ByteArrayTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to ByteArrayTag!\");\n\n        try {\n            byte[] value = plugin.getNMSTags().getNBTByteArrayValue(tag);\n            return ByteArrayTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag byte-array from NMS:\");\n            return null;\n        }\n    }\n\n    public static ByteArrayTag fromStream(DataInputStream is) throws IOException {\n        int length = is.readInt();\n        byte[] bytes = new byte[length];\n        is.readFully(bytes);\n        return ByteArrayTag.of(bytes);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Byte</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class ByteTag extends NumberTag<Byte> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagByte\", \"ByteTag\"}, byte.class);\n\n    private static final ByteTag[] CACHE = new ByteTag[256];\n\n    private ByteTag(byte value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeByte(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static ByteTag of(byte value) {\n        int index = value - Byte.MIN_VALUE;\n        ByteTag tag = CACHE[index];\n        if (tag == null)\n            tag = CACHE[index] = new ByteTag(value);\n        return tag;\n    }\n\n    public static ByteTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to ByteTag!\");\n\n        try {\n            byte value = plugin.getNMSTags().getNBTByteValue(tag);\n            return ByteTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag byte from NMS:\");\n            return null;\n        }\n    }\n\n    public static ByteTag fromStream(DataInputStream is) throws IOException {\n        return ByteTag.of(is.readByte());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.OptionalDouble;\nimport java.util.OptionalInt;\nimport java.util.OptionalLong;\nimport java.util.Set;\n\n/**\n * The <code>TAG_Compound</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class CompoundTag extends Tag<Map<String, Tag<?>>> implements Iterable<Tag<?>> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\"NBTTagCompound\", \"CompoundTag\");\n\n    private CompoundTag(Map<String, Tag<?>> value, boolean cloneMap) {\n        super(cloneMap ? new HashMap<>(value) : value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        for (Map.Entry<String, Tag<?>> entry : value.entrySet()) {\n            entry.getValue().write(os);\n\n            byte[] keyBytes = entry.getKey().getBytes(StandardCharsets.UTF_8);\n            os.writeShort(keyBytes.length);\n            os.write(keyBytes);\n        }\n\n        os.writeByte((byte) 0);\n    }\n\n    public CompoundTag copy() {\n        return of(this.value);\n    }\n\n    public Optional<Tag<?>> getTag(String key) {\n        return Optional.ofNullable(getTagInternal(key));\n    }\n\n    public Optional<byte[]> getByteArray(String key) {\n        return getTagInternal(key, ByteArrayTag.class).map(tag -> tag.value);\n    }\n\n    public OptionalInt getByte(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.byteValue());\n    }\n\n    public Optional<CompoundTag> getCompound(String key) {\n        return getTagInternal(key, CompoundTag.class);\n    }\n\n    public OptionalDouble getDouble(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.doubleValue());\n    }\n\n    public OptionalDouble getFloat(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.floatValue());\n    }\n\n    public Optional<int[]> getIntArray(String key) {\n        return getTagInternal(key, IntArrayTag.class).map(tag -> tag.value);\n    }\n\n    public OptionalInt getInt(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.intValue());\n    }\n\n    public Optional<ListTag> getList(String key) {\n        return getTagInternal(key, ListTag.class);\n    }\n\n    public OptionalLong getLong(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalLong.empty() : OptionalLong.of(tag.value.longValue());\n    }\n\n    public Optional<Number> getNumber(String key) {\n        return getTagInternal(key, NumberTag.class).map(tag -> (Number) tag.value);\n    }\n\n    public OptionalInt getShort(String key) {\n        NumberTag<?> tag = getTagInternal(key, NumberTag.class).orElse(null);\n        return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.shortValue());\n    }\n\n    public Optional<String> getString(String key) {\n        return getTagInternal(key, StringTag.class).map(tag -> tag.value);\n    }\n\n    @Nullable\n    public Tag<?> setTag(String key, Tag<?> value) {\n        return this.value.put(key, value);\n    }\n\n    public void setByteArray(String key, byte[] value) {\n        setTag(key, ByteArrayTag.of(value));\n    }\n\n    public void setByte(String key, byte value) {\n        setTag(key, ByteTag.of(value));\n    }\n\n    public void setDouble(String key, double value) {\n        setTag(key, DoubleTag.of(value));\n    }\n\n    public void setFloat(String key, float value) {\n        setTag(key, FloatTag.of(value));\n    }\n\n    public void setIntArray(String key, int[] value) {\n        setTag(key, IntArrayTag.of(value));\n    }\n\n    public void setInt(String key, int value) {\n        setTag(key, IntTag.of(value));\n    }\n\n    public void setLong(String key, long value) {\n        setTag(key, LongTag.of(value));\n    }\n\n    public void setShort(String key, short value) {\n        setTag(key, ShortTag.of(value));\n    }\n\n    public void setString(String key, String value) {\n        setTag(key, StringTag.of(value));\n    }\n\n    public void putAll(CompoundTag other) {\n        this.value.putAll(other.value);\n    }\n\n    public boolean containsKey(String key) {\n        return this.value.containsKey(key);\n    }\n\n    public Tag<?> remove(String key) {\n        return this.value.remove(key);\n    }\n\n    public int size() {\n        return value.size();\n    }\n\n    public boolean isEmpty() {\n        return value.isEmpty();\n    }\n\n    public Set<Map.Entry<String, Tag<?>>> entrySet() {\n        return value.entrySet();\n    }\n\n    @NotNull\n    @Override\n    public Iterator<Tag<?>> iterator() {\n        return value.values().iterator();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder bldr = new StringBuilder();\n        bldr.append(\"TAG_Compound: \").append(value.size()).append(\" entries\\r\\n{\\r\\n\");\n        for (Map.Entry<String, Tag<?>> entry : value.entrySet()) {\n            bldr.append(\"   \").append((entry.getValue() + \"\").replaceAll(\"\\r\\n\", \"\\r\\n   \")).append(\"\\r\\n\");\n        }\n        bldr.append(\"}\");\n        return bldr.toString();\n    }\n\n    @Override\n    public Object toNBT() {\n        try {\n            Object nbtTagCompound = TAG_CONVERTER.toNBT();\n\n            for (Map.Entry<String, Tag<?>> entry : value.entrySet()) {\n                plugin.getNMSTags().setNBTCompoundTagValue(nbtTagCompound, entry.getKey(), entry.getValue().toNBT());\n            }\n\n            return nbtTagCompound;\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag compound to NMS:\");\n            return null;\n        }\n    }\n\n    @Nullable\n    private Tag<?> getTagInternal(String key) {\n        return this.value.get(key);\n    }\n\n    @Nullable\n    private <T extends Tag<?>> Optional<T> getTagInternal(String key, Class<T> valueType) {\n        Tag<?> tag = this.value.get(key);\n        return tag != null && valueType.isAssignableFrom(tag.getClass()) ? Optional.of(valueType.cast(tag)) : Optional.empty();\n    }\n\n    public static CompoundTag of() {\n        return new CompoundTag(new HashMap<>(), false);\n    }\n\n    public static CompoundTag of(Map<String, Tag<?>> value) {\n        return new CompoundTag(value, true);\n    }\n\n    public static CompoundTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to CompoundTag!\");\n\n        Map<String, Tag<?>> map = new HashMap<>();\n\n        try {\n            Set<String> keySet = plugin.getNMSTags().getNBTCompoundValue(tag);\n\n            for (String key : keySet) {\n                map.put(key, Tag.fromNBT(plugin.getNMSTags().getNBTCompoundTag(tag, key)));\n            }\n\n            return new CompoundTag(map, false);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag compound from NMS:\");\n            return null;\n        }\n    }\n\n    public static CompoundTag fromStream(DataInputStream is, int depth) throws IOException {\n        Map<String, Tag<?>> tagMap = new HashMap<>();\n        Tag<?> tag;\n\n        while (!((tag = Tag.fromStream(is, depth + 1)) instanceof EndTag)) {\n            int keyLength = is.readShort() & 0xFFFF;\n            byte[] keyBytes = new byte[keyLength];\n            is.readFully(keyBytes);\n            String key = new String(keyBytes, StandardCharsets.UTF_8);\n            tagMap.put(key, tag);\n        }\n\n        return new CompoundTag(tagMap, false);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Double</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class DoubleTag extends NumberTag<Double> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagDouble\", \"DoubleTag\"}, double.class);\n\n    private static final DoubleTag[] CACHE = new DoubleTag[100];\n\n    private DoubleTag(double value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeDouble(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static DoubleTag of(double value) {\n        if (value == (int) value && value >= 0 && value < CACHE.length) {\n            DoubleTag tag = CACHE[(int) value];\n            if (tag == null)\n                tag = CACHE[(int) value] = new DoubleTag(value);\n            return tag;\n        } else {\n            return new DoubleTag(value);\n        }\n    }\n\n    public static DoubleTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to DoubleTag!\");\n\n        try {\n            double value = plugin.getNMSTags().getNBTDoubleValue(tag);\n            return DoubleTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag double from NMS:\");\n            return null;\n        }\n    }\n\n    public static DoubleTag fromStream(DataInputStream is) throws IOException {\n        return DoubleTag.of(is.readDouble());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_End</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class EndTag extends Tag<Object> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\"NBTTagEnd\", \"EndTag\");\n\n    private static final EndTag INSTANCE = new EndTag();\n\n    private EndTag() {\n        super(null);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) {\n        // Do nothing.\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    @Override\n    public String toString() {\n        return \"TAG_End\";\n    }\n\n    public static EndTag of() {\n        return INSTANCE;\n    }\n\n    public static EndTag fromStream(DataInputStream is, int depth) throws IOException {\n        if (depth == 0) {\n            throw new IOException(\"TAG_End found without a TAG_Compound/TAG_List tag preceding it.\");\n        } else {\n            return EndTag.INSTANCE;\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Float</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class FloatTag extends NumberTag<Float> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagFloat\", \"FloatTag\"}, float.class);\n\n    private static final FloatTag[] CACHE = new FloatTag[100];\n\n    private FloatTag(float value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeFloat(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static FloatTag of(float value) {\n        if (value == (int) value && value >= 0 && value < CACHE.length) {\n            FloatTag tag = CACHE[(int) value];\n            if (tag == null)\n                tag = CACHE[(int) value] = new FloatTag(value);\n            return tag;\n        } else {\n            return new FloatTag(value);\n        }\n    }\n\n    public static FloatTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to FloatTag!\");\n\n        try {\n            float value = plugin.getNMSTags().getNBTFloatValue(tag);\n            return FloatTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag float from NMS:\");\n            return null;\n        }\n    }\n\n    public static FloatTag fromStream(DataInputStream is) throws IOException {\n        return FloatTag.of(is.readFloat());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java",
    "content": "//@formatter:off\n\n/*\n * JNBT License\n *\n * Copyright (c) 2010 Graham Edgecombe\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *\n *     * Neither the name of the JNBT team nor the names of its\n *       contributors may be used to endorse or promote products derived from\n *       this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n//@formatter:on\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.UUID;\n\n/**\n * The <code>TAG_Byte_Array</code> tag.\n *\n * @author Jocopa3\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class IntArrayTag extends Tag<int[]> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagIntArray\", \"IntArrayTag\"}, int[].class);\n\n    private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]);\n\n    /**\n     * Creates the tag.\n     *\n     * @param value The value.\n     */\n    private IntArrayTag(int[] value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeInt(value.length);\n        for (int i : value)\n            os.writeInt(i);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder integers = new StringBuilder();\n        for (int b : value) {\n            integers.append(b).append(\" \");\n        }\n        return \"TAG_Int_Array: \" + integers;\n    }\n\n    @Override\n    public int hashCode() {\n        int prime = 31;\n        int result = super.hashCode();\n        result = (prime * result) + Arrays.hashCode(value);\n        return result;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        return this == obj || (obj instanceof IntArrayTag && Arrays.equals(value, ((IntArrayTag) obj).value));\n    }\n\n    public static IntArrayTag of(int[] value) {\n        return value.length == 0 ? EMPTY : new IntArrayTag(value);\n    }\n\n    public static IntArrayTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to IntArrayTag!\");\n\n        try {\n            int[] value = plugin.getNMSTags().getNBTIntArrayValue(tag);\n            return IntArrayTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag int-array from NMS:\");\n            return null;\n        }\n    }\n\n    public static IntArrayTag fromUUID(UUID uuid) {\n        long MSB = uuid.getMostSignificantBits();\n        long LSB = uuid.getLeastSignificantBits();\n        return IntArrayTag.of(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB});\n    }\n\n    public static IntArrayTag fromStream(DataInputStream is) throws IOException {\n        int length = is.readInt();\n        int[] data = new int[length];\n        for (int i = 0; i < length; i++) {\n            data[i] = is.readInt();\n        }\n        return IntArrayTag.of(data);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Int</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class IntTag extends NumberTag<Integer> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagInt\", \"IntTag\"}, int.class);\n\n    private static final IntTag[] CACHE = new IntTag[100];\n\n    private IntTag(int value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeInt(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static IntTag of(int value) {\n        if (value >= 0 && value < CACHE.length) {\n            IntTag tag = CACHE[value];\n            if (tag == null)\n                tag = CACHE[value] = new IntTag(value);\n            return tag;\n        } else {\n            return new IntTag(value);\n        }\n    }\n\n    public static IntTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to IntTag!\");\n\n        try {\n            int value = plugin.getNMSTags().getNBTIntValue(tag);\n            return IntTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag int from NMS:\");\n            return null;\n        }\n    }\n\n    public static IntTag fromStream(DataInputStream is) throws IOException {\n        return IntTag.of(is.readInt());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.RandomAccess;\n\n/**\n * The <code>TAG_List</code> tag.\n *\n * @author Graham Edgecombe\n */\n@SuppressWarnings(\"rawtypes\")\npublic class ListTag extends Tag<List<Tag<?>>> implements Iterable<Tag<?>> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\"NBTTagList\", \"ListTag\");\n\n    private static final byte DYNAMIC_LIST_INDICATOR = (byte) 0xFF;\n\n    /**\n     * Hint to the type of elements in the list.\n     */\n    @Nullable\n    private Class<? extends Tag> hintType;\n\n    private ListTag(List<Tag<?>> value, @Nullable Class<? extends Tag> hintType, boolean cloneList) {\n        super(cloneListIfNeeded(value, cloneList));\n        this.hintType = hintType;\n    }\n\n    public ListTag copy() {\n        return of(this.value, this.hintType);\n    }\n\n    public void addTag(Tag<?> tag) {\n        this.value.add(tag);\n        // In case the type of the tag is not similar to the hintType, we reset it.\n        if (this.hintType != null && tag.getClass() != this.hintType) {\n            this.hintType = null;\n        }\n    }\n\n    @Override\n    public List<Tag<?>> getValue() {\n        return Collections.unmodifiableList(value);\n    }\n\n    @NotNull\n    @Override\n    public Iterator<Tag<?>> iterator() {\n        return value.iterator();\n    }\n\n    public int size() {\n        return this.value.size();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder bldr = new StringBuilder();\n        bldr.append(\"TAG_List: \").append(value.size()).append(\" entries\");\n        if (this.hintType != null) {\n            bldr.append(\" of type \").append(NBTUtils.getTypeName(hintType));\n        }\n        bldr.append(\"\\r\\n{\\r\\n\");\n        for (Tag<?> t : value) {\n            bldr.append(\"   \").append(t.toString().replaceAll(\"\\r\\n\", \"\\r\\n   \")).append(\"\\r\\n\");\n        }\n        bldr.append(\"}\");\n        return bldr.toString();\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        if (this.hintType != null) {\n            writeDataWithHint(os);\n        } else {\n            writeDataWithoutHint(os);\n        }\n    }\n\n    private void writeDataWithHint(DataOutputStream os) throws IOException {\n        int size = value.size();\n        os.writeByte(NBTUtils.getTypeCode(this.hintType));\n        os.writeInt(size);\n        for (Tag<?> _tag : value)\n            _tag.writeData(os);\n    }\n\n    private void writeDataWithoutHint(DataOutputStream os) throws IOException {\n        int size = value.size();\n        os.writeByte(DYNAMIC_LIST_INDICATOR);\n        os.writeInt(size);\n        for (Tag<?> _tag : value)\n            _tag.write(os);\n    }\n\n    @Override\n    public Object toNBT() {\n        return plugin.getNMSTags().parseList(this);\n    }\n\n    public static ListTag of(@Nullable Class<? extends Tag> hintType) {\n        return new ListTag(new LinkedList<>(), hintType, false);\n    }\n\n    public static ListTag of(List<Tag<?>> value) {\n        return of(value, null);\n    }\n\n    public static ListTag of(List<Tag<?>> value, @Nullable Class<? extends Tag> hintType) {\n        return new ListTag(value, hintType, true);\n    }\n\n    public static ListTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to ListTag!\");\n\n        List<Tag<?>> list = new LinkedList<>();\n\n        try {\n            int size = plugin.getNMSTags().getNBTTagListSize(tag);\n            Class<? extends Tag> lastTagType = null;\n            boolean isSimilarType = true;\n\n            for (int i = 0; i < size; i++) {\n                Tag<?> currTag = Tag.fromNBT(plugin.getNMSTags().getNBTListIndexValue(tag, i));\n                if (isSimilarType) {\n                    if (lastTagType != null && currTag.getClass() != lastTagType) {\n                        isSimilarType = false;\n                    } else {\n                        lastTagType = currTag.getClass();\n                    }\n                }\n                list.add(currTag);\n            }\n\n            return new ListTag(list, !isSimilarType || size == 0 ? null : lastTagType, false);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag list from NMS:\");\n            return null;\n        }\n    }\n\n    public static ListTag fromStream(DataInputStream is, int depth) throws IOException {\n        int childType = is.readByte();\n        return childType == DYNAMIC_LIST_INDICATOR ?\n                fromStreamWithoutHint(is, depth) : fromStreamWithHint(is, depth, childType);\n    }\n\n    private static ListTag fromStreamWithHint(DataInputStream is, int depth, int childType) throws IOException {\n        int length = is.readInt();\n\n        List<Tag<?>> tagList = new LinkedList<>();\n\n        for (int i = 0; i < length; i++) {\n            Tag<?> tag = Tag.fromStream(is, depth + 1, childType);\n            if (tag instanceof EndTag) {\n                throw new IOException(\"TAG_End not permitted in a list.\");\n            }\n            tagList.add(tag);\n        }\n\n        return new ListTag(tagList, NBTUtils.getTypeClass(childType), false);\n    }\n\n    private static ListTag fromStreamWithoutHint(DataInputStream is, int depth) throws IOException {\n        int length = is.readInt();\n\n        List<Tag<?>> tagList = new LinkedList<>();\n\n        for (int i = 0; i < length; i++) {\n            Tag<?> tag = Tag.fromStream(is, depth + 1);\n            if (tag instanceof EndTag) {\n                throw new IOException(\"TAG_End not permitted in a list.\");\n            }\n            tagList.add(tag);\n        }\n\n        return new ListTag(tagList, null, false);\n    }\n\n    private static <T> List<T> cloneListIfNeeded(List<T> list, boolean cloneList) {\n        return cloneList || list instanceof RandomAccess ? new LinkedList<>(list) : list;\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Long</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class LongTag extends NumberTag<Long> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagLong\", \"LongTag\"}, long.class);\n\n    private static final LongTag[] CACHE = new LongTag[100];\n\n    private LongTag(long value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeLong(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static LongTag of(long value) {\n        if (value >= 0 && value < CACHE.length) {\n            LongTag tag = CACHE[(int) value];\n            if (tag == null)\n                tag = CACHE[(int) value] = new LongTag(value);\n            return tag;\n        } else {\n            return new LongTag(value);\n        }\n    }\n\n    public static LongTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to LongTag!\");\n\n        try {\n            long value = plugin.getNMSTags().getNBTLongValue(tag);\n            return LongTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag long from NMS:\");\n            return null;\n        }\n    }\n\n    public static LongTag fromStream(DataInputStream is) throws IOException {\n        return LongTag.of(is.readLong());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/NBTTags.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\npublic class NBTTags {\n\n    public static final int TYPE_END = 0;\n    public static final int TYPE_BYTE = 1;\n    public static final int TYPE_SHORT = 2;\n    public static final int TYPE_INT = 3;\n    public static final int TYPE_LONG = 4;\n    public static final int TYPE_FLOAT = 5;\n    public static final int TYPE_DOUBLE = 6;\n    public static final int TYPE_BYTE_ARRAY = 7;\n    public static final int TYPE_STRING = 8;\n    public static final int TYPE_LIST = 9;\n    public static final int TYPE_COMPOUND = 10;\n    public static final int TYPE_INT_ARRAY = 11;\n    public static final int TYPE_BIG_DECIMAL = 12;\n    public static final int TYPE_UUID = 13;\n    public static final int TYPE_PERSISTENT_DATA = 14;\n\n    private NBTTags() {\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\n/**\n * A class which contains NBT-related utility methods.\n *\n * @author Graham Edgecombe\n */\n@SuppressWarnings(\"WeakerAccess\")\npublic class NBTUtils {\n\n    /**\n     * Default private constructor.\n     */\n    private NBTUtils() {\n\n    }\n\n    /**\n     * Gets the type name of a tag.\n     *\n     * @param clazz The tag class.\n     * @return The type name.\n     */\n    public static String getTypeName(Class<? extends Tag> clazz) {\n        if (clazz.equals(BigDecimalTag.class)) {\n            return \"TAG_Big_Decimal\";\n        } else if (clazz.equals(ByteArrayTag.class)) {\n            return \"TAG_Byte_Array\";\n        } else if (clazz.equals(ByteTag.class)) {\n            return \"TAG_Byte\";\n        } else if (clazz.equals(CompoundTag.class)) {\n            return \"TAG_Compound\";\n        } else if (clazz.equals(DoubleTag.class)) {\n            return \"TAG_Double\";\n        } else if (clazz.equals(EndTag.class)) {\n            return \"TAG_End\";\n        } else if (clazz.equals(FloatTag.class)) {\n            return \"TAG_Float\";\n        } else if (clazz.equals(IntTag.class)) {\n            return \"TAG_Int\";\n        } else if (clazz.equals(ListTag.class)) {\n            return \"TAG_List\";\n        } else if (clazz.equals(LongTag.class)) {\n            return \"TAG_Long\";\n        } else if (clazz.equals(ShortTag.class)) {\n            return \"TAG_Short\";\n        } else if (clazz.equals(StringTag.class)) {\n            return \"TAG_String\";\n        } else if (clazz.equals(IntArrayTag.class)) {\n            return \"TAG_Int_Array\";\n        } else {\n            throw new IllegalArgumentException(\"Invalid tag class (\" + clazz.getName() + \").\");\n        }\n    }\n\n    /**\n     * Gets the type code of a tag class.\n     *\n     * @param clazz The tag class.\n     * @return The type code.\n     * @throws IllegalArgumentException if the tag class is invalid.\n     */\n    public static int getTypeCode(Class<? extends Tag> clazz) {\n        if (clazz.equals(BigDecimalTag.class)) {\n            return NBTTags.TYPE_BIG_DECIMAL;\n        } else if (clazz.equals(ByteArrayTag.class)) {\n            return NBTTags.TYPE_BYTE_ARRAY;\n        } else if (clazz.equals(ByteTag.class)) {\n            return NBTTags.TYPE_BYTE;\n        } else if (clazz.equals(CompoundTag.class)) {\n            return NBTTags.TYPE_COMPOUND;\n        } else if (clazz.equals(DoubleTag.class)) {\n            return NBTTags.TYPE_DOUBLE;\n        } else if (clazz.equals(EndTag.class)) {\n            return NBTTags.TYPE_END;\n        } else if (clazz.equals(FloatTag.class)) {\n            return NBTTags.TYPE_FLOAT;\n        } else if (clazz.equals(IntTag.class)) {\n            return NBTTags.TYPE_INT;\n        } else if (clazz.equals(ListTag.class)) {\n            return NBTTags.TYPE_LIST;\n        } else if (clazz.equals(LongTag.class)) {\n            return NBTTags.TYPE_LONG;\n        } else if (clazz.equals(PersistentDataTag.class) || clazz.equals(PersistentDataTagSerialized.class)) {\n            return NBTTags.TYPE_PERSISTENT_DATA;\n        } else if (clazz.equals(ShortTag.class)) {\n            return NBTTags.TYPE_SHORT;\n        } else if (clazz.equals(StringTag.class)) {\n            return NBTTags.TYPE_STRING;\n        } else if (clazz.equals(IntArrayTag.class)) {\n            return NBTTags.TYPE_INT_ARRAY;\n        } else if (clazz.equals(UUIDTag.class)) {\n            return NBTTags.TYPE_UUID;\n        } else {\n            throw new IllegalArgumentException(\"Invalid tag class (\" + clazz.getName() + \").\");\n        }\n    }\n\n    /**\n     * Gets the class of a type of tag.\n     *\n     * @param type The type.\n     * @return The class.\n     * @throws IllegalArgumentException if the tag type is invalid.\n     */\n    public static Class<? extends Tag> getTypeClass(int type) {\n        switch (type) {\n            case NBTTags.TYPE_END:\n                return EndTag.class;\n            case NBTTags.TYPE_BYTE:\n                return ByteTag.class;\n            case NBTTags.TYPE_SHORT:\n                return ShortTag.class;\n            case NBTTags.TYPE_INT:\n                return IntTag.class;\n            case NBTTags.TYPE_LONG:\n                return LongTag.class;\n            case NBTTags.TYPE_FLOAT:\n                return FloatTag.class;\n            case NBTTags.TYPE_DOUBLE:\n                return DoubleTag.class;\n            case NBTTags.TYPE_BYTE_ARRAY:\n                return ByteArrayTag.class;\n            case NBTTags.TYPE_STRING:\n                return StringTag.class;\n            case NBTTags.TYPE_LIST:\n                return ListTag.class;\n            case NBTTags.TYPE_COMPOUND:\n                return CompoundTag.class;\n            case NBTTags.TYPE_INT_ARRAY:\n                return IntArrayTag.class;\n            case NBTTags.TYPE_BIG_DECIMAL:\n                return BigDecimalTag.class;\n            case NBTTags.TYPE_UUID:\n                return UUIDTag.class;\n            case NBTTags.TYPE_PERSISTENT_DATA:\n                return PersistentDataTagSerialized.class;\n            default:\n                throw new IllegalArgumentException(\"Invalid tag type : \" + type + \".\");\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.common.reflection.ReflectConstructor;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.core.Either;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport org.bukkit.Bukkit;\n\nimport javax.annotation.Nullable;\n\npublic class NMSTagConverter {\n\n    private static final Class<?>[] EMPTY_PARAMS = new Class[0];\n\n    private final Class<?> clazz;\n    private final ReflectMethod<Object> A;\n    private final ReflectConstructor<Object> CONSTRUCTOR;\n\n    public static NMSTagConverter of(String nbtClassName) {\n        return of(nbtClassName, null);\n    }\n\n    public static NMSTagConverter of(String nbtClassName, @Nullable Class<?> parameterType) {\n        Class<?>[] parameterTypes = parameterType == null ? EMPTY_PARAMS : new Class[]{parameterType};\n        return new NMSTagConverter(nbtClassName, parameterTypes);\n    }\n\n    public static NMSTagConverter choice(String... nbtClassNames) {\n        return choice(nbtClassNames, null);\n    }\n\n    public static NMSTagConverter choice(String[] nbtClassNames, @Nullable Class<?> parameterType) {\n        for (int i = nbtClassNames.length - 1; i >= 1; --i) {\n            String nbtClassName = nbtClassNames[i];\n            Either<Class<?>, Exception> clazz = getNNTClass(nbtClassName);\n            if (clazz.getLeft() != null)\n                return of(nbtClassName, parameterType);\n        }\n\n        // Couldn't find one, we'll try the first one and return whatever the result is\n        return of(nbtClassNames[0], parameterType);\n    }\n\n    private NMSTagConverter(String nbtClassName, Class<?>[] parameterTypes) {\n        this.clazz = getNNTClassOrError(nbtClassName);\n        this.A = new ReflectMethod<>(this.clazz, this.clazz, \"a\", parameterTypes);\n        this.CONSTRUCTOR = new ReflectConstructor<>(this.clazz, parameterTypes);\n    }\n\n    public Class<?> getNBTClass() {\n        return clazz;\n    }\n\n    public Object toNBT(Object... args) {\n        if (A.isValid()) {\n            return A.invoke(null, args);\n        } else {\n            return CONSTRUCTOR.newInstance(args);\n        }\n    }\n\n    private static Either<Class<?>, Exception> getNNTClass(String nbtType) {\n        try {\n            if (ServerVersion.isAtLeast(ServerVersion.v1_17)) {\n                return Either.left(Class.forName(\"net.minecraft.nbt.\" + nbtType));\n            } else {\n                String version = Bukkit.getServer().getClass().getPackage().getName().split(\"\\\\.\")[3];\n                return Either.left(Class.forName(\"net.minecraft.server.\" + version + \".\" + nbtType));\n            }\n        } catch (Exception error) {\n            return Either.right(error);\n        }\n    }\n\n    private static Class<?> getNNTClassOrError(String nbtType) {\n        Either<Class<?>, Exception> clazz = getNNTClass(nbtType);\n\n        if (clazz.getRight() != null) {\n            Log.error(clazz.getRight(), \"An unexpected error while loading nbt class \", nbtType, \":\");\n            return null;\n        }\n\n        return clazz.getLeft();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\npublic abstract class NumberTag<E extends Number> extends Tag<E> {\n\n    protected NumberTag(E value) {\n        super(value);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\npublic class PersistentDataTag<E> extends Tag<E> {\n\n    private final PersistentDataTypeContext<E> serializer;\n\n    private PersistentDataTag(E value, PersistentDataTypeContext<E> serializer) {\n        super(value);\n        this.serializer = serializer;\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        byte[] data = serializer.serialize(value);\n        os.writeInt(data.length);\n        os.write(data);\n    }\n\n    public static <E> PersistentDataTag<E> of(E value, PersistentDataTypeContext<E> serializer) {\n        return new PersistentDataTag<>(value, serializer);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType;\nimport com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\npublic class PersistentDataTagSerialized extends Tag<byte[]> {\n\n    private static final PersistentDataTagSerialized EMPTY = new PersistentDataTagSerialized(new byte[0]);\n\n    private PersistentDataTagSerialized(byte[] value) {\n        super(value);\n    }\n\n    public <E> PersistentDataTag<E> getPersistentDataTag(PersistentDataType<E> type) {\n        PersistentDataTypeContext<E> serializer = type.getContext();\n        if (serializer == null)\n            throw new IllegalArgumentException(\"Cannot find a valid serializer for \" + type);\n        return PersistentDataTag.of(serializer.deserialize(value), serializer);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeInt(value.length);\n        os.write(value);\n    }\n\n    public static PersistentDataTagSerialized of(byte[] value) {\n        return value.length == 0 ? EMPTY : new PersistentDataTagSerialized(value);\n    }\n\n    public static PersistentDataTagSerialized fromStream(DataInputStream is) throws IOException {\n        int length = is.readInt();\n        byte[] bytes = new byte[length];\n        is.readFully(bytes);\n        return new PersistentDataTagSerialized(bytes);\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * The <code>TAG_Short</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class ShortTag extends NumberTag<Short> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagShort\", \"ShortTag\"}, short.class);\n\n    private static final ShortTag[] CACHE = new ShortTag[100];\n\n    private ShortTag(short value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeShort(value);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static ShortTag of(short value) {\n        if (value >= 0 && value < CACHE.length) {\n            ShortTag tag = CACHE[value];\n            if (tag == null)\n                tag = CACHE[value] = new ShortTag(value);\n            return tag;\n        } else {\n            return new ShortTag(value);\n        }\n    }\n\n    public static ShortTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to ShortTag!\");\n\n        try {\n            short value = plugin.getNMSTags().getNBTShortValue(tag);\n            return ShortTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag short from NMS:\");\n            return null;\n        }\n    }\n\n    public static ShortTag fromStream(DataInputStream is) throws IOException {\n        return ShortTag.of(is.readShort());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.google.common.base.Preconditions;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * The <code>TAG_String</code> tag.\n *\n * @author Graham Edgecombe\n */\npublic class StringTag extends Tag<String> {\n\n    /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice(\n            new String[]{\"NBTTagString\", \"StringTag\"}, String.class);\n\n    private static final StringTag EMPTY = new StringTag(\"\");\n\n    private StringTag(String value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);\n        os.writeShort(bytes.length);\n        if (bytes.length > 0)\n            os.write(bytes);\n    }\n\n    @Override\n    protected NMSTagConverter getNMSConverter() {\n        return TAG_CONVERTER;\n    }\n\n    public static StringTag of(String value) {\n        return value.isEmpty() ? EMPTY : new StringTag(value);\n    }\n\n    public static StringTag fromNBT(Object tag) {\n        Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), \"Cannot convert \" + tag.getClass() + \" to StringTag!\");\n\n        try {\n            String value = plugin.getNMSTags().getNBTStringValue(tag);\n            return StringTag.of(value);\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while converting tag string from NMS:\");\n            return null;\n        }\n    }\n\n    public static StringTag fromStream(DataInputStream is) throws IOException {\n        int length = is.readShort();\n        if (length <= 0)\n            return EMPTY;\n        byte[] bytes = new byte[length];\n        is.readFully(bytes);\n        return StringTag.of(new String(bytes, StandardCharsets.UTF_8));\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java",
    "content": "/*\n * JNBT License\n\nCopyright (c) 2010 Graham Edgecombe\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n      \n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n      \n    * Neither the name of the JNBT team nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n */\npackage com.bgsoftware.superiorskyblock.tag;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.Objects;\n\n/**\n * Represents a single NBT tag.\n *\n * @author Graham Edgecombe\n */\npublic abstract class Tag<E> {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    protected final E value;\n\n    protected Tag(E value) {\n        this.value = value;\n    }\n\n    public static Tag<?> fromNBT(Object tag) {\n        if (tag.getClass().equals(ByteArrayTag.TAG_CONVERTER.getNBTClass()))\n            return ByteArrayTag.fromNBT(tag);\n        else if (tag.getClass().equals(ByteTag.TAG_CONVERTER.getNBTClass()))\n            return ByteTag.fromNBT(tag);\n        else if (tag.getClass().equals(CompoundTag.TAG_CONVERTER.getNBTClass()))\n            return CompoundTag.fromNBT(tag);\n        else if (tag.getClass().equals(DoubleTag.TAG_CONVERTER.getNBTClass()))\n            return DoubleTag.fromNBT(tag);\n        else if (tag.getClass().equals(EndTag.TAG_CONVERTER.getNBTClass()))\n            return EndTag.of();\n        else if (tag.getClass().equals(FloatTag.TAG_CONVERTER.getNBTClass()))\n            return FloatTag.fromNBT(tag);\n        else if (tag.getClass().equals(IntArrayTag.TAG_CONVERTER.getNBTClass()))\n            return IntArrayTag.fromNBT(tag);\n        else if (tag.getClass().equals(IntTag.TAG_CONVERTER.getNBTClass()))\n            return IntTag.fromNBT(tag);\n        else if (tag.getClass().equals(ListTag.TAG_CONVERTER.getNBTClass()))\n            return ListTag.fromNBT(tag);\n        else if (tag.getClass().equals(LongTag.TAG_CONVERTER.getNBTClass()))\n            return LongTag.fromNBT(tag);\n        else if (tag.getClass().equals(ShortTag.TAG_CONVERTER.getNBTClass()))\n            return ShortTag.fromNBT(tag);\n        else if (tag.getClass().equals(StringTag.TAG_CONVERTER.getNBTClass()))\n            return StringTag.fromNBT(tag);\n\n        throw new IllegalArgumentException(\"Cannot convert \" + tag.getClass() + \" to Tag!\");\n    }\n\n    public static Tag<?> fromStream(DataInputStream is, int depth) throws IOException {\n        int type = is.readByte() & 0xFF;\n        return fromStream(is, depth, type);\n    }\n\n    protected static Tag<?> fromStream(DataInputStream is, int depth, int type) throws IOException {\n        switch (type) {\n            case NBTTags.TYPE_END:\n                return EndTag.fromStream(is, depth);\n            case NBTTags.TYPE_BYTE:\n                return ByteTag.fromStream(is);\n            case NBTTags.TYPE_SHORT:\n                return ShortTag.fromStream(is);\n            case NBTTags.TYPE_INT:\n                return IntTag.fromStream(is);\n            case NBTTags.TYPE_LONG:\n                return LongTag.fromStream(is);\n            case NBTTags.TYPE_FLOAT:\n                return FloatTag.fromStream(is);\n            case NBTTags.TYPE_DOUBLE:\n                return DoubleTag.fromStream(is);\n            case NBTTags.TYPE_BYTE_ARRAY:\n                return ByteArrayTag.fromStream(is);\n            case NBTTags.TYPE_STRING:\n                return StringTag.fromStream(is);\n            case NBTTags.TYPE_LIST:\n                return ListTag.fromStream(is, depth);\n            case NBTTags.TYPE_COMPOUND:\n                return CompoundTag.fromStream(is, depth);\n            case NBTTags.TYPE_INT_ARRAY:\n                return IntArrayTag.fromStream(is);\n            case NBTTags.TYPE_BIG_DECIMAL:\n                return BigDecimalTag.fromStream(is);\n            case NBTTags.TYPE_UUID:\n                return UUIDTag.fromStream(is);\n            case NBTTags.TYPE_PERSISTENT_DATA:\n                return PersistentDataTagSerialized.fromStream(is);\n        }\n\n        throw new IllegalArgumentException(\"Invalid tag: \" + type);\n    }\n\n    public E getValue() {\n        return value;\n    }\n\n    @Override\n    public String toString() {\n        return NBTUtils.getTypeName(this.getClass()) + \": \" + value;\n    }\n\n    public void write(DataOutputStream os) throws IOException {\n        int type = NBTUtils.getTypeCode(this.getClass());\n\n        os.writeByte(type);\n\n        if (type == NBTTags.TYPE_END) {\n            throw new IOException(\"Named TAG_End not permitted.\");\n        }\n\n        writeData(os);\n    }\n\n    protected abstract void writeData(DataOutputStream outputStream) throws IOException;\n\n    @Nullable\n    protected NMSTagConverter getNMSConverter() {\n        return null;\n    }\n\n    public Object toNBT() {\n        NMSTagConverter converter = getNMSConverter();\n        if (converter == null)\n            throw new UnsupportedOperationException();\n        return Objects.requireNonNull(converter.toNBT(this.value));\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java",
    "content": "package com.bgsoftware.superiorskyblock.tag;\n\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.util.UUID;\n\npublic class UUIDTag extends Tag<UUID> {\n\n    private UUIDTag(UUID value) {\n        super(value);\n    }\n\n    @Override\n    protected void writeData(DataOutputStream os) throws IOException {\n        os.writeLong(value.getMostSignificantBits());\n        os.writeLong(value.getLeastSignificantBits());\n    }\n\n    public static UUIDTag of(long mostSigBits, long leastSigBits) {\n        return new UUIDTag(new UUID(mostSigBits, leastSigBits));\n    }\n\n    public static UUIDTag of(UUID value) {\n        return new UUIDTag(value);\n    }\n\n    public static UUIDTag fromStream(DataInputStream is) throws IOException {\n        return UUIDTag.of(is.readLong(), is.readLong());\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.threads.Synchronized;\nimport com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory;\nimport org.bukkit.Material;\nimport org.bukkit.entity.AbstractHorse;\nimport org.bukkit.entity.ArmorStand;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Hanging;\nimport org.bukkit.entity.Horse;\nimport org.bukkit.entity.LivingEntity;\nimport org.bukkit.entity.Pig;\nimport org.bukkit.entity.Player;\nimport org.bukkit.entity.Projectile;\nimport org.bukkit.entity.Tameable;\nimport org.bukkit.entity.Vehicle;\nimport org.bukkit.inventory.AbstractHorseInventory;\nimport org.bukkit.inventory.HorseInventory;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.projectiles.ProjectileSource;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\n\npublic class BukkitEntities {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private static final Synchronized<Int2ObjectMapView<List<ItemStack>>> entityContent = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap());\n    @Nullable\n    private static final EntityType NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, \"NAUTILUS\");\n    @Nullable\n    private static final EntityType ZOMBIE_NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, \"ZOMBIE_NAUTILUS\");\n\n    private BukkitEntities() {\n\n    }\n\n    public static boolean isEquipment(LivingEntity livingEntity, ItemStack itemStack) {\n        List<ItemStack> entityEquipment = entityContent.writeAndGet(entityContent ->\n                entityContent.computeIfAbsent(livingEntity.getEntityId(), u -> cacheEntityEquipmentInternal(livingEntity)));\n\n        return entityEquipment.stream().anyMatch(equipmentItem -> equipmentItem != null &&\n                equipmentItem.getType() == itemStack.getType());\n    }\n\n    public static void cacheEntityEquipment(LivingEntity livingEntity) {\n        List<ItemStack> entityEquipment = cacheEntityEquipmentInternal(livingEntity);\n        entityContent.write(entityContent ->\n                entityContent.put(livingEntity.getEntityId(), entityEquipment));\n    }\n\n    private static List<ItemStack> cacheEntityEquipmentInternal(LivingEntity livingEntity) {\n        List<ItemStack> entityEquipment = new LinkedList<>(Arrays.asList(plugin.getNMSEntities().getEquipment(livingEntity.getEquipment())));\n\n        if (livingEntity instanceof Pig) {\n            if (((Pig) livingEntity).hasSaddle())\n                entityEquipment.add(new ItemStack(Material.SADDLE));\n        } else if (livingEntity instanceof Horse) {\n            HorseInventory horseInventory = ((Horse) livingEntity).getInventory();\n            horseInventory.forEach(itemStack -> {\n                if (itemStack != null)\n                    entityEquipment.add(itemStack);\n            });\n\n            entityEquipment.add(new ItemStack(Material.CHEST));\n\n            if (horseInventory.getSaddle() != null)\n                entityEquipment.add(horseInventory.getSaddle());\n            if (horseInventory.getArmor() != null)\n                entityEquipment.add(horseInventory.getArmor());\n        }\n\n        try {\n            if (livingEntity instanceof AbstractHorse) {\n                AbstractHorseInventory horseInventory = ((AbstractHorse) livingEntity).getInventory();\n                horseInventory.forEach(itemStack -> {\n                    if (itemStack != null)\n                        entityEquipment.add(itemStack);\n                });\n\n                entityEquipment.add(new ItemStack(Material.CHEST));\n\n                if (horseInventory.getSaddle() != null)\n                    entityEquipment.add(horseInventory.getSaddle());\n                if (horseInventory instanceof HorseInventory && ((HorseInventory) horseInventory).getArmor() != null)\n                    entityEquipment.add(((HorseInventory) horseInventory).getArmor());\n            }\n        } catch (Throwable ignored) {\n        }\n\n        return entityEquipment.isEmpty() ? Collections.emptyList() : entityEquipment;\n    }\n\n    public static void clearEntityEquipment(LivingEntity livingEntity) {\n        entityContent.write(entityContent -> entityContent.remove(livingEntity.getEntityId()));\n    }\n\n    public static Optional<Player> getPlayerSource(Entity damager) {\n        if (damager instanceof Projectile) {\n            ProjectileSource shooter = ((Projectile) damager).getShooter();\n            if (shooter instanceof Player)\n                return Optional.of((Player) shooter);\n        } else if (damager instanceof Player) {\n            return Optional.of((Player) damager);\n        }\n\n        return Optional.empty();\n    }\n\n    public static Key getLimitEntityType(Entity entity) {\n        // TODO - Is this really necessary?\n        return Keys.of(entity.getType());\n    }\n\n    public static boolean canHaveLimit(EntityType entityType) {\n        Class<?> entityClass = entityType.getEntityClass();\n        return (entityClass != null && (LivingEntity.class.isAssignableFrom(entityClass) ||\n                Hanging.class.isAssignableFrom(entityClass) || Vehicle.class.isAssignableFrom(entityClass)));\n    }\n\n    public static boolean canBypassEntityLimit(Entity entity) {\n        return canBypassEntityLimit(entity, true);\n    }\n\n    public static boolean canBypassEntityLimit(Entity entity, boolean checkProviders) {\n        if (entity instanceof ArmorStand && !((ArmorStand) entity).isVisible())\n            return true;\n\n        if (checkProviders) {\n            for (EntitiesProvider entitiesProvider : plugin.getProviders().getEntitiesProviders()) {\n                if (!entitiesProvider.shouldTrackEntity(entity))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    public static boolean isTameable(Entity entity) {\n        return entity instanceof Tameable && ((Tameable) entity).isTamed();\n    }\n\n    public static boolean isHorse(Entity entity) {\n        return entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && entity instanceof org.bukkit.entity.AbstractHorse);\n    }\n\n    public static boolean isNautilus(EntityType entityType) {\n        return entityType == NAUTILUS_TYPE || entityType == ZOMBIE_NAUTILUS_TYPE;\n    }\n\n    public static List<EntityCategory> getCategories(Entity entity) {\n        List<EntityCategory> categories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity));\n        if (isTameable(entity)) {\n            categories = new LinkedList<>(categories);\n            categories.add(BuiltinEntityCategory.TAMEABLE.getEntityCategory());\n        }\n        return categories;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.reflection.ReflectMethod;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.PlayerHand;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.Event;\nimport org.bukkit.event.block.BlockPlaceEvent;\nimport org.bukkit.event.player.PlayerInteractEntityEvent;\nimport org.bukkit.event.player.PlayerInteractEvent;\nimport org.bukkit.inventory.EquipmentSlot;\nimport org.bukkit.inventory.ItemStack;\nimport org.bukkit.inventory.PlayerInventory;\nimport org.bukkit.inventory.meta.SpawnEggMeta;\n\nimport java.util.Map;\n\npublic class BukkitItems {\n\n    private static final ReflectMethod<EquipmentSlot> GET_HAND_BLOCK_PLACE = new ReflectMethod<>(BlockPlaceEvent.class, \"getHand\");\n    private static final ReflectMethod<EquipmentSlot> GET_HAND_PLAYER_INTERACT = new ReflectMethod<>(PlayerInteractEvent.class, \"getHand\");\n    private static final ReflectMethod<EquipmentSlot> GET_HAND_PLAYER_INTERACT_ENTITY = new ReflectMethod<>(PlayerInteractEntityEvent.class, \"getHand\");\n    private static final ReflectMethod<ItemStack> GET_ITEM_IN_OFF_HAND = new ReflectMethod<>(PlayerInventory.class, \"getItemInOffHand\");\n    private static final ReflectMethod<ItemStack> SET_ITEM_IN_OFF_HAND = new ReflectMethod<>(PlayerInventory.class, \"setItemInOffHand\", ItemStack.class);\n\n    private static final Material END_CRYSTAL_ITEM_TYPE = EnumHelper.getEnum(Material.class, \"END_CRYSTAL\");\n\n    private BukkitItems() {\n\n    }\n\n    public static void removeHandItem(Player onlinePlayer, PlayerHand usedHand, int amount) {\n        PlayerInventory playerInventory = onlinePlayer.getInventory();\n\n        if (usedHand == PlayerHand.MAIN_HAND) {\n            ItemStack mainHand = playerInventory.getItemInHand();\n            if (mainHand != null) {\n                mainHand.setAmount(mainHand.getAmount() - amount);\n                playerInventory.setItemInHand(mainHand);\n            }\n        } else if (usedHand == PlayerHand.OFF_HAND) {\n            ItemStack offHand = GET_ITEM_IN_OFF_HAND.invoke(playerInventory);\n            if (offHand != null) {\n                offHand.setAmount(offHand.getAmount() - amount);\n                SET_ITEM_IN_OFF_HAND.invoke(playerInventory, offHand);\n            }\n        }\n    }\n\n    @Nullable\n    public static PlayerHand getHand(Event event) {\n        ReflectMethod<EquipmentSlot> reflectMethod;\n\n        if (event instanceof BlockPlaceEvent) {\n            reflectMethod = GET_HAND_BLOCK_PLACE;\n        } else if (event instanceof PlayerInteractEvent) {\n            reflectMethod = GET_HAND_PLAYER_INTERACT;\n        } else if (event instanceof PlayerInteractEntityEvent) {\n            reflectMethod = GET_HAND_PLAYER_INTERACT_ENTITY;\n        } else {\n            throw new IllegalArgumentException(\"Cannot get hand of event: \" + event.getClass());\n        }\n\n        EquipmentSlot equipmentSlot = reflectMethod.isValid() ? reflectMethod.invoke(event) : EquipmentSlot.HAND;\n\n        return equipmentSlot == null ? null : PlayerHand.of(equipmentSlot);\n    }\n\n    @Nullable\n    public static ItemStack getHandItem(Player onlinePlayer, @Nullable PlayerHand usedHand) {\n        if (usedHand == null) {\n            return null;\n        }\n\n        ItemStack handItem;\n\n        if (usedHand == PlayerHand.OFF_HAND) {\n            handItem = GET_ITEM_IN_OFF_HAND.invoke(onlinePlayer.getInventory());\n        } else {\n            handItem = onlinePlayer.getItemInHand();\n        }\n\n        return handItem == null || handItem.getType() == Material.AIR ? null : handItem;\n    }\n\n    public static void setHandItem(Player player, PlayerHand playerHand, @Nullable ItemStack itemStack) {\n        if (playerHand == PlayerHand.MAIN_HAND) {\n            player.getInventory().setItemInHand(itemStack == null ? new ItemStack(Material.AIR) : itemStack);\n        } else if (playerHand == PlayerHand.OFF_HAND) {\n            SET_ITEM_IN_OFF_HAND.invoke(player.getInventory(), itemStack == null ? new ItemStack(Material.AIR) : itemStack);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static EntityType getEntityType(ItemStack itemStack) {\n        if (!isValidAndSpawnEgg(itemStack)) {\n            Material itemType = itemStack.getType();\n\n            if (itemType == Material.ARMOR_STAND) {\n                return EntityType.ARMOR_STAND;\n            } else if (itemType == END_CRYSTAL_ITEM_TYPE) {\n                return EntityType.ENDER_CRYSTAL;\n            }\n\n            return EntityType.UNKNOWN;\n        }\n\n        if (ServerVersion.isLegacy()) {\n            try {\n                SpawnEggMeta spawnEggMeta = (SpawnEggMeta) itemStack.getItemMeta();\n                return spawnEggMeta.getSpawnedType() == null ? EntityType.PIG : spawnEggMeta.getSpawnedType();\n            } catch (NoClassDefFoundError error) {\n                return EntityType.fromId(itemStack.getDurability());\n            }\n        } else {\n            return EntityType.fromName(itemStack.getType().name().replace(\"_SPAWN_EGG\", \"\"));\n        }\n    }\n\n    public static void addItem(ItemStack itemStack, PlayerInventory playerInventory, Location toDrop) {\n        Map<Integer, ItemStack> additionalItems = playerInventory.addItem(itemStack);\n        for (ItemStack additionalItem : additionalItems.values())\n            toDrop.getWorld().dropItemNaturally(toDrop, additionalItem);\n    }\n\n    public static boolean isValidAndSpawnEgg(@Nullable ItemStack itemStack) {\n        return itemStack != null && isValidAndSpawnEgg(itemStack.getType());\n    }\n\n    public static boolean isValidAndSpawnEgg(Material itemType) {\n        return !itemType.isBlock() && itemType.name().contains(ServerVersion.isLegacy() ? \"MONSTER_EGG\" : \"SPAWN_EGG\");\n    }\n\n    public static boolean isInteractableItem(@Nullable ItemStack itemStack) {\n        if (itemStack == null)\n            return false;\n\n        Material itemType = itemStack.getType();\n\n        return itemType == Material.ARMOR_STAND || isValidAndSpawnEgg(itemType);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher;\nimport org.bukkit.World;\n\nimport java.util.EnumMap;\n\npublic class Dimensions {\n\n    private static final EnumMap<World.Environment, Dimension> ENVIRONMENT_TO_DIMENSION = new EnumMap<>(World.Environment.class);\n\n    public static void registerListeners(PluginEventsDispatcher dispatcher) {\n        dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Dimensions::onSettingsUpdate);\n    }\n\n    private static void onSettingsUpdate() {\n        ENVIRONMENT_TO_DIMENSION.clear();\n\n        for (Dimension dimension : Dimension.values()) {\n            Dimension currentDimension = ENVIRONMENT_TO_DIMENSION.get(dimension.getEnvironment());\n            if (currentDimension == null || dimension.ordinal() < currentDimension.ordinal())\n                ENVIRONMENT_TO_DIMENSION.put(dimension.getEnvironment(), dimension);\n        }\n    }\n\n    @Nullable\n    public static Dimension fromEnvironment(World.Environment environment) {\n        return ENVIRONMENT_TO_DIMENSION.get(environment);\n    }\n\n    private Dimensions() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.world.WorldInfo;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.IslandWorlds;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.formatting.Formatters;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.island.IslandUtils;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport com.google.common.base.Preconditions;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.entity.Entity;\n\nimport java.time.Duration;\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.Objects;\nimport java.util.Queue;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\npublic class EntityTeleports {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private EntityTeleports() {\n    }\n\n    public static void warmupTeleport(SuperiorPlayer superiorPlayer, long warmupInMillis, TeleportCallback teleportCallback) {\n        if (warmupInMillis > 0 && !superiorPlayer.hasBypassModeEnabled() &&\n                !superiorPlayer.hasPermission(\"superior.admin.bypass.warmup\")) {\n            Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format(\n                    Duration.ofMillis(warmupInMillis), superiorPlayer.getUserLocale()));\n\n            superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> teleportCallback.accept(true), warmupInMillis / 50));\n        } else {\n            teleportCallback.accept(false);\n        }\n    }\n\n    public static void teleport(Entity entity, Location location) {\n        teleport(entity, location, null);\n    }\n\n    public static void teleport(Entity entity, Location location, @Nullable Consumer<Boolean> teleportResult) {\n        Island island = plugin.getGrid().getIslandAt(location);\n\n        if (island != null) {\n            plugin.getProviders().getWorldsProvider().prepareTeleport(island, location.clone(),\n                    () -> teleportEntity(entity, location, teleportResult));\n        } else {\n            teleportEntity(entity, location, teleportResult);\n        }\n    }\n\n    public static void teleportUntilSuccess(Entity entity, Location location, long cooldown, @Nullable Runnable onFinish) {\n        teleport(entity, location, succeed -> {\n            if (!succeed) {\n                if (cooldown > 0) {\n                    BukkitExecutor.sync(() -> teleportUntilSuccess(entity, location, cooldown, onFinish), cooldown);\n                } else {\n                    teleportUntilSuccess(entity, location, cooldown, onFinish);\n                }\n            } else if (onFinish != null) {\n                onFinish.run();\n            }\n        });\n    }\n\n    public static CompletableFuture<Location> findIslandSafeLocation(Island island, Dimension dimension) {\n        CompletableFuture<Location> result = new CompletableFuture<>();\n        IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> {\n            islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world ->\n                    findIslandSafeLocation(island, dimension, result));\n        });\n        return result;\n    }\n\n    public static void findIslandSafeLocation(Island island, Dimension dimension, CompletableFuture<Location> result) {\n        Location homeLocation = island.getIslandHome(dimension);\n\n        Preconditions.checkNotNull(homeLocation, \"Cannot find a suitable home location for island \" +\n                island.getUniqueId());\n\n        World islandsWorld = Objects.requireNonNull(plugin.getGrid().getIslandsWorld(island, dimension), \"world is null\");\n        float rotationYaw = homeLocation.getYaw();\n        float rotationPitch = homeLocation.getPitch();\n\n        Log.debug(Debug.FIND_SAFE_TELEPORT, island.getOwner().getName(), dimension.getName());\n\n        // We first check that the home location is safe. If it is, we can return.\n        {\n            Block homeLocationBlock = homeLocation.getBlock();\n            if (island.isSpawn() || WorldBlocks.isSafeBlock(homeLocationBlock)) {\n                Log.debugResult(Debug.FIND_SAFE_TELEPORT, \"Result Location\", homeLocation);\n                result.complete(homeLocation);\n                return;\n            }\n        }\n\n        // In case it is not safe anymore, we check in the same location if the highest block is safe.\n        {\n            Block teleportLocationHighestBlock = islandsWorld.getHighestBlockAt(homeLocation).getRelative(BlockFace.UP);\n            if (WorldBlocks.isSafeBlock(teleportLocationHighestBlock)) {\n                result.complete(adjustLocationToHome(island, teleportLocationHighestBlock, rotationYaw, rotationPitch));\n                return;\n            }\n        }\n\n        // The teleport location is not safe. We check for a safe spot in the center of the island.\n\n        Location islandCenterLocation = island.getCenter(dimension);\n\n        if (!islandCenterLocation.equals(homeLocation)) {\n            ChunksProvider.loadChunk(ChunkPosition.of(islandCenterLocation), ChunkLoadReason.FIND_SAFE_SPOT, chunk -> {\n                {\n                    Block islandCenterBlock = islandCenterLocation.getBlock().getRelative(BlockFace.UP);\n                    if (WorldBlocks.isSafeBlock(islandCenterBlock)) {\n                        result.complete(adjustLocationToHome(island, islandCenterBlock, rotationYaw, rotationPitch));\n                        return;\n                    }\n                }\n\n                // The center is not safe, we check in the same location if the highest block is safe.\n                {\n                    Block islandCenterHighestBlock = islandsWorld.getHighestBlockAt(islandCenterLocation).getRelative(BlockFace.UP);\n                    if (WorldBlocks.isSafeBlock(islandCenterHighestBlock)) {\n                        result.complete(adjustLocationToHome(island, islandCenterHighestBlock, rotationYaw, rotationPitch));\n                        return;\n                    }\n                }\n\n                // The center is not safe; we look for a new spot on the island.\n                findNewSafeSpotOnIsland(island, islandsWorld, homeLocation, rotationYaw, rotationPitch, result);\n            });\n        } else {\n            findNewSafeSpotOnIsland(island, islandsWorld, homeLocation, rotationYaw, rotationPitch, result);\n        }\n    }\n\n    private static void findNewSafeSpotOnIsland(Island island, World islandsWorld, Location homeLocation,\n                                                float rotationYaw, float rotationPitch, CompletableFuture<Location> result) {\n        LinkedList<ChunkPosition> islandChunks = new LinkedList<>(IslandUtils.getChunkCoords(island,\n                WorldInfo.of(islandsWorld), IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS));\n\n        try (ChunkPosition homeChunk = ChunkPosition.of(homeLocation)) {\n            islandChunks.sort(Comparator.comparingInt(o -> o.distanceSquared(homeChunk)));\n        }\n\n        findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, safeSpot -> {\n            if (safeSpot != null) {\n                result.complete(adjustLocationToHome(island, safeSpot.getBlock(), rotationYaw, rotationPitch));\n            } else {\n                result.complete(null);\n            }\n        });\n    }\n\n    private static void findSafeSpotInChunk(Island island, Queue<ChunkPosition> islandChunks, World islandsWorld,\n                                            Location homeLocation, Consumer<Location> onResult) {\n        ChunkPosition chunkPosition = islandChunks.poll();\n        if (chunkPosition == null) {\n            onResult.accept(null);\n            return;\n        }\n\n        ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.FIND_SAFE_SPOT, null).whenComplete((chunk, err) -> {\n            ChunkSnapshot chunkSnapshot = chunk.getChunkSnapshot();\n\n            if (WorldBlocks.isChunkEmpty(island, chunkSnapshot)) {\n                findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult);\n                return;\n            }\n\n            BukkitExecutor.createTask().runAsync(v -> {\n                Location closestSafeSpot = null;\n                double closestSafeSpotDistance = 0;\n\n                int worldBuildLimit = islandsWorld.getMaxHeight() - 1;\n                int worldMinLimit = plugin.getNMSWorld().getMinHeight(islandsWorld);\n\n                for (int x = 0; x < 16; x++) {\n                    for (int z = 0; z < 16; z++) {\n                        int y = chunkSnapshot.getHighestBlockYAt(x, z);\n\n                        if (y < worldMinLimit || y + 2 > worldBuildLimit)\n                            continue;\n\n                        int worldX = chunkSnapshot.getX() * 16 + x;\n                        int worldZ = chunkSnapshot.getZ() * 16 + z;\n\n                        // In some versions, the ChunkSnapshot#getHighestBlockYAt seems to return\n                        // one block above the actual highest block. Therefore, the check is on the\n                        // returned block and the block below it.\n                        Location safeSpot;\n                        if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y, z)) {\n                            safeSpot = new Location(islandsWorld, worldX, y, worldZ);\n                        } else if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y - 1, z)) {\n                            safeSpot = new Location(islandsWorld, worldX, y - 1, worldZ);\n                        } else {\n                            continue;\n                        }\n\n                        double distanceFromHome = safeSpot.distanceSquared(homeLocation);\n                        if (closestSafeSpot == null || distanceFromHome < closestSafeSpotDistance) {\n                            closestSafeSpotDistance = distanceFromHome;\n                            closestSafeSpot = safeSpot;\n                        }\n                    }\n                }\n\n                return closestSafeSpot;\n            }).runSync(location -> {\n                if (location != null) {\n                    onResult.accept(location);\n                } else {\n                    findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult);\n                }\n            });\n\n        });\n    }\n\n    private static void teleportEntity(Entity entity, Location location, @Nullable Consumer<Boolean> teleportResult) {\n        entity.eject();\n        plugin.getProviders().getAsyncProvider().teleport(entity, location, teleportResult);\n    }\n\n    private static Location adjustLocationToHome(Island island, Block block, float yaw, float pitch) {\n        Location newHomeLocation;\n\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            Location location = block.getLocation(wrapper.getHandle()).add(0.5, 0, 0.5);\n            location.setYaw(yaw);\n            location.setPitch(pitch);\n\n            PluginEvent<PluginEventArgs.IslandSetHome> event = PluginEventsFactory.callIslandSetHomeEvent(\n                    island, (SuperiorPlayer) null, location, IslandSetHomeEvent.Reason.SAFE_HOME);\n\n            if (event.isCancelled()) {\n                newHomeLocation = location;\n            } else {\n                newHomeLocation = event.getArgs().islandHome;\n                island.setIslandHome(newHomeLocation);\n            }\n        }\n\n        Log.debugResult(Debug.FIND_SAFE_TELEPORT, \"Result Location\", newHomeLocation);\n\n        return newHomeLocation;\n    }\n\n    public interface TeleportCallback {\n\n        void accept(boolean afterWarmup);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/GeneratorType.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.EnumHelper;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.key.ConstantKeys;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\n\npublic enum GeneratorType {\n\n    NORMAL(ConstantKeys.COBBLESTONE),\n    BASALT(ConstantKeys.BASALT),\n    NONE(null);\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final BlockFace[] nearbyFaces = new BlockFace[]{\n            BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP\n    };\n    private static final Material BLUE_ICE_MATERIAL = EnumHelper.getEnum(Material.class, \"BLUE_ICE\");\n    private static final Material SOUL_SOIL_MATERIAL = EnumHelper.getEnum(Material.class, \"SOUL_SOIL\");\n\n    public static GeneratorType fromDimension(Dimension dimension) {\n        return dimension.getEnvironment() == World.Environment.NETHER &&\n                ServerVersion.isAtLeast(ServerVersion.v1_16) ? BASALT : NORMAL;\n    }\n\n    public static GeneratorType detectGenerator(Block block) {\n        if (ServerVersion.isAtLeast(ServerVersion.v1_16) &&\n                block.getWorld().getEnvironment() == World.Environment.NETHER) {\n            for (BlockFace blockFace : nearbyFaces) {\n                if (block.getRelative(blockFace).getType() == BLUE_ICE_MATERIAL &&\n                        block.getRelative(BlockFace.DOWN).getType() == SOUL_SOIL_MATERIAL)\n                    return GeneratorType.BASALT;\n            }\n        } else {\n            for (BlockFace blockFace : nearbyFaces) {\n                if (plugin.getNMSWorld().isWaterLogged(block.getRelative(blockFace)))\n                    return GeneratorType.NORMAL;\n            }\n        }\n\n        return GeneratorType.NONE;\n    }\n\n    @Nullable\n    private final Key defaultBlock;\n\n    GeneratorType(@Nullable Key defaultBlock) {\n        this.defaultBlock = defaultBlock;\n    }\n\n    @Nullable\n    public Key getDefaultBlock() {\n        return defaultBlock;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\npublic enum SignType {\n\n    STANDING_SIGN,\n    WALL_SIGN,\n    HANGING_WALL_SIGN,\n    HANGING_SIGN,\n    UNKNOWN\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.LazyWorldLocation;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.types.MaterialKey;\nimport org.bukkit.Bukkit;\nimport org.bukkit.ChunkSnapshot;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.block.Block;\nimport org.bukkit.block.BlockFace;\n\npublic class WorldBlocks {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private WorldBlocks() {\n\n    }\n\n    public static boolean isSafeBlock(Block block) {\n        return isSafeBlockInternal(block) || isSafeBlockInternal(block.getRelative(BlockFace.DOWN));\n    }\n\n    private static boolean isSafeBlockInternal(Block block) {\n        // Checks that the block in the parameter is safe for teleportation.\n        // This means that the block below it is considered \"safe\", and the two blocks above the safe blocks\n        // cannot suffocate the player.\n\n        return !canPlayerSuffocateFromBlock(block) && !canPlayerSuffocateFromBlock(block.getRelative(BlockFace.UP)) &&\n                plugin.getSettings().getSafeBlocks().contains(Keys.of(block.getRelative(BlockFace.DOWN)));\n    }\n\n    private static boolean canPlayerSuffocateFromBlock(Block block) {\n        return canPlayerGetHurtFromBlock(block.getType()) || plugin.getNMSWorld().canPlayerSuffocate(block);\n    }\n\n    public static boolean isSafeBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        return isSafeBlockInternal(chunkSnapshot, x, y, z) || isSafeBlockInternal(chunkSnapshot, x, y - 1, z);\n    }\n\n    private static boolean isSafeBlockInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        // Checks that the block in the parameter is safe for teleportation.\n        // This means that the block below it is considered \"safe\", and the two blocks above the safe blocks\n        // cannot suffocate the player.\n\n        return !canPlayerSuffocateFromBlock(chunkSnapshot, x, y, z) &&\n                !canPlayerSuffocateFromBlock(chunkSnapshot, x, y + 1, z) &&\n                plugin.getSettings().getSafeBlocks().contains(plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y - 1, z));\n    }\n\n    private static boolean canPlayerSuffocateFromBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) {\n        if (plugin.getNMSWorld().canPlayerSuffocate(chunkSnapshot, x, y, z))\n            return true;\n\n        Key blockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y, z);\n        return blockKey != null && canPlayerGetHurtFromBlock(((MaterialKey) blockKey).getMaterial());\n    }\n\n    private static boolean canPlayerGetHurtFromBlock(Material material) {\n        return material == Material.LAVA || material == Material.FIRE;\n    }\n\n    public static boolean isChunkEmpty(Island island, ChunkSnapshot chunkSnapshot) {\n        for (int i = 0; i < 16; i++) {\n            if (!chunkSnapshot.isSectionEmpty(i)) {\n                return false;\n            }\n        }\n\n        island.markChunkEmpty(Bukkit.getWorld(chunkSnapshot.getWorldName()),\n                chunkSnapshot.getX(), chunkSnapshot.getZ(), true);\n\n        return true;\n    }\n\n    public static Location getChunkBlock(ChunkPosition chunkPosition, int x, int y, int z) {\n        int realWorldChunkX = chunkPosition.getX() << 4;\n        int realWorldChunkZ = chunkPosition.getZ() << 4;\n\n        return new LazyWorldLocation(chunkPosition.getWorldName(),\n                realWorldChunkX + x, y, realWorldChunkZ + z, 0, 0);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/WorldGenerator.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.SuperiorSkyblock;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.collections.EnumerateMap;\nimport com.bgsoftware.superiorskyblock.core.io.FileClassLoader;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.JarFiles;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup;\nimport com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport org.bukkit.generator.ChunkGenerator;\nimport org.bukkit.plugin.java.JavaPlugin;\n\nimport java.io.File;\nimport java.lang.reflect.Constructor;\nimport java.util.List;\n\npublic class WorldGenerator {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final EnumerateMap<Dimension, IslandsGenerator> defaultWorldGenerators = new EnumerateMap<>(Dimension.values());\n    @Nullable\n    private static ChunkGenerator customWorldGenerator;\n    private static boolean loadedCustomWorldGenerator = false;\n\n    public static ChunkGenerator getWorldGenerator(Dimension dimension) {\n        if (!loadedCustomWorldGenerator && customWorldGenerator == null)\n            customWorldGenerator = loadGeneratorFromFile();\n\n        if (customWorldGenerator != null)\n            return customWorldGenerator;\n\n        return defaultWorldGenerators.computeIfAbsent(dimension, d -> plugin.getNMSWorld().createGenerator(d));\n    }\n\n    @Nullable\n    private static ChunkGenerator loadGeneratorFromFile() {\n        if (loadedCustomWorldGenerator)\n            return null;\n\n        loadedCustomWorldGenerator = true;\n\n        File generatorFolder = new File(plugin.getDataFolder(), \"world-generator\");\n\n        if (!generatorFolder.isDirectory()) {\n            generatorFolder.delete();\n        }\n\n        if (!generatorFolder.exists()) {\n            generatorFolder.mkdirs();\n            return null;\n        }\n\n        List<File> generatorsFiles = Files.listFolderFiles(generatorFolder, false, f -> f.getName().endsWith(\".jar\"));\n        if (generatorsFiles.isEmpty())\n            return null;\n\n        try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(generatorFolder)) {\n            for (File file : generatorsFiles) {\n                String fileName = file.getName();\n                file = filesLookup.getFile(fileName);\n\n                FileClassLoader classLoader = new FileClassLoader(file, plugin.getPluginClassLoader(),\n                        plugin.getNMSAlgorithms().getClassProcessor());\n\n                //noinspection deprecation\n                Class<?> generatorClass = JarFiles.getClass(file.toURL(), ChunkGenerator.class, classLoader).getLeft();\n\n                if (generatorClass != null) {\n                    for (Constructor<?> constructor : generatorClass.getConstructors()) {\n                        if (constructor.getParameterCount() == 0) {\n                            return (ChunkGenerator) generatorClass.newInstance();\n                        } else if (constructor.getParameterTypes()[0].equals(JavaPlugin.class) || constructor.getParameterTypes()[0].equals(SuperiorSkyblock.class)) {\n                            return (ChunkGenerator) constructor.newInstance(plugin);\n                        }\n                    }\n                }\n            }\n        } catch (Exception error) {\n            Log.error(error, \"An unexpected error occurred while loading the generator:\");\n        }\n\n        return null;\n    }\n\n    private WorldGenerator() {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java",
    "content": "package com.bgsoftware.superiorskyblock.world;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport org.bukkit.World;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class WorldReader {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final World world;\n    private final ChunkLoadReason chunkLoadReason;\n    private final CompletableFutureList<ChunkReader> chunkReaderFutures = new CompletableFutureList<>(-1L);\n\n    private final Map<ChunkPosition, ChunkReader> cachedChunkReaders = new HashMap<>();\n    private boolean finishCalled = false;\n    private boolean inFinishCallback = false;\n\n    public WorldReader(World world, ChunkLoadReason chunkLoadReason) {\n        this.world = world;\n        this.chunkLoadReason = chunkLoadReason;\n    }\n\n    public void prepareChunk(ChunkPosition chunkPosition) {\n        if (this.finishCalled)\n            throw new IllegalStateException(\"Cannot call WorldReader#prepareChunk after WorldReader#finish was called\");\n\n        chunkReaderFutures.add(ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null)\n                .thenApply(chunk -> plugin.getNMSWorld().createChunkReader(chunk)));\n    }\n\n    @Nullable\n    public ChunkReader getChunkReader(int blockX, int blockZ) {\n        if (!this.inFinishCallback)\n            throw new IllegalStateException(\"Cannot call WorldReader#getChunkReader from this state\");\n\n        int chunkX = blockX >> 4;\n        int chunkZ = blockZ >> 4;\n        try (ChunkPosition chunkPosition = ChunkPosition.of(this.world, chunkX, chunkZ)) {\n            return this.cachedChunkReaders.get(chunkPosition);\n        }\n    }\n\n    public void finish(Runnable onFinish) {\n        this.finishCalled = true;\n\n        BukkitExecutor.async(() -> {\n            MutableBoolean failed = new MutableBoolean(false);\n\n            chunkReaderFutures.forEachCompleted(chunkReader -> {\n                ChunkPosition chunkPosition = ChunkPosition.of(world, chunkReader.getX(), chunkReader.getZ(), false);\n                cachedChunkReaders.put(chunkPosition, chunkReader);\n            }, error -> {\n                failed.set(true);\n                Log.error(error, \"An error occurred while waiting for chunks to load:\");\n            });\n\n            if (!failed.get()) {\n                try {\n                    this.inFinishCallback = true;\n                    onFinish.run();\n                } finally {\n                    this.inFinishCallback = true;\n                }\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java",
    "content": "package com.bgsoftware.superiorskyblock.world.chunk;\n\npublic enum ChunkLoadReason {\n\n    SCHEMATIC_PLACE,\n    SCHEMATIC_SAVE,\n    ENTITY_TELEPORT,\n    BLOCKS_RECALCULATE,\n    ENTITIES_RECALCULATE,\n    FIND_SAFE_SPOT,\n    API_REQUEST,\n    BIOME_REQUEST,\n    WARP_SIGN_BREAK,\n    SET_BIOME,\n    DELETE_CHUNK\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java",
    "content": "package com.bgsoftware.superiorskyblock.world.chunk;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.common.executors.IWorker;\nimport com.bgsoftware.common.executors.WorkerExecutor;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport org.bukkit.Chunk;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\n\npublic class ChunksProvider {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final WorkerExecutor chunksExecutor = new WorkerExecutor(10);\n\n    private static final Map<ChunkPosition, PendingChunkLoadRequest> pendingRequests = new ConcurrentHashMap<>();\n\n    private static boolean stopped = false;\n\n    private ChunksProvider() {\n\n    }\n\n    public static CompletableFuture<Chunk> loadChunk(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason,\n                                                     @Nullable Consumer<Chunk> onLoadConsumer) {\n        try {\n            return loadChunkInternal(chunkPosition, chunkLoadReason, onLoadConsumer);\n        } finally {\n            chunkPosition.release();\n        }\n    }\n\n    private static CompletableFuture<Chunk> loadChunkInternal(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason,\n                                                     @Nullable Consumer<Chunk> onLoadConsumer) {\n        if (stopped)\n            return new CompletableFuture<>();\n\n        Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason);\n\n        Chunk loadedChunk = ChunkPosition.getLoadedChunk(chunkPosition).orElse(null);\n\n        if (loadedChunk != null) {\n            processPendingChunkLoadRequest(loadedChunk, chunkPosition);\n            if (onLoadConsumer != null)\n                onLoadConsumer.accept(loadedChunk);\n            return CompletableFuture.completedFuture(loadedChunk);\n        }\n\n        PendingChunkLoadRequest pendingRequest = pendingRequests.get(chunkPosition);\n\n        if (pendingRequest != null) {\n            if (onLoadConsumer != null)\n                pendingRequest.callbacks.add(onLoadConsumer);\n            return pendingRequest.completableFuture;\n        } else {\n            CompletableFuture<Chunk> completableFuture = new CompletableFuture<>();\n            Set<Consumer<Chunk>> chunkConsumers = new HashSet<>();\n\n            if (onLoadConsumer != null)\n                chunkConsumers.add(onLoadConsumer);\n\n            // Copy pool resource\n            ChunkPosition clonedChunkPos = chunkPosition.copy();\n\n            pendingRequests.put(clonedChunkPos, new PendingChunkLoadRequest(completableFuture, chunkConsumers));\n            BukkitExecutor.ensureMain(() -> {\n                chunksExecutor.addWorker(new ChunkLoadWorker(clonedChunkPos, chunkLoadReason));\n                if (!chunksExecutor.isRunning())\n                    start();\n            });\n\n            return completableFuture;\n        }\n    }\n\n    public static void stop() {\n        stopped = true;\n        if (chunksExecutor.isRunning())\n            chunksExecutor.stop();\n    }\n\n    public static void start() {\n        chunksExecutor.start(plugin);\n    }\n\n    private static class ChunkLoadWorker implements IWorker {\n\n        private final ChunkPosition chunkPosition;\n        private final ChunkLoadReason chunkLoadReason;\n\n        public ChunkLoadWorker(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason) {\n            this.chunkPosition = chunkPosition;\n            this.chunkLoadReason = chunkLoadReason;\n        }\n\n        @Override\n        public void work() {\n            if (stopped)\n                return;\n\n            long profiler = Profiler.start(ProfileType.LOAD_CHUNK);\n            Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason);\n\n            plugin.getProviders().getChunksProvider().loadChunk(chunkPosition.getWorld(),\n                    chunkPosition.getX(), chunkPosition.getZ()).whenComplete((chunk, error) -> {\n                if (error != null) {\n                    Log.entering(\"ENTER\", chunkPosition, chunkLoadReason);\n                    Log.error(error, \"An unexpected error occurred while loading chunk:\");\n                    error.printStackTrace();\n                }\n\n                try {\n                    finishLoad(chunk, profiler);\n                } catch (Exception error2) {\n                    Log.entering(\"ENTER\", chunkPosition, chunkLoadReason);\n                    Log.error(error2, \"An unexpected error occurred while finishing chunk loading:\");\n                }\n            });\n        }\n\n        private void finishLoad(Chunk chunk, long profiler) {\n            Profiler.end(profiler);\n            Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason);\n            processPendingChunkLoadRequest(chunk, chunkPosition);\n        }\n\n    }\n\n    private static void processPendingChunkLoadRequest(Chunk chunk, ChunkPosition chunkPosition) {\n        PendingChunkLoadRequest pendingRequest = pendingRequests.remove(chunkPosition);\n\n        if (pendingRequest == null)\n            return;\n\n        pendingRequest.callbacks.forEach(chunkConsumer -> chunkConsumer.accept(chunk));\n        pendingRequest.completableFuture.complete(chunk);\n    }\n\n    private static class PendingChunkLoadRequest {\n\n        private final CompletableFuture<Chunk> completableFuture;\n        private final Set<Consumer<Chunk>> callbacks;\n\n        public PendingChunkLoadRequest(CompletableFuture<Chunk> completableFuture, Set<Consumer<Chunk>> callbacks) {\n            this.completableFuture = completableFuture;\n            this.callbacks = callbacks;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java",
    "content": "package com.bgsoftware.superiorskyblock.world.entity;\n\nimport com.bgsoftware.common.annotations.NotNull;\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.Keys;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\nimport org.bukkit.entity.Ambient;\nimport org.bukkit.entity.Creature;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Flying;\nimport org.bukkit.entity.Monster;\nimport org.bukkit.entity.Slime;\nimport org.bukkit.entity.Tameable;\nimport org.bukkit.entity.Vehicle;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\n\npublic enum BuiltinEntityCategory {\n\n    TAMEABLE {\n        @Override\n        protected boolean isEntityListedInternal(Class<? extends Entity> entityClass) {\n            return Tameable.class.isAssignableFrom(entityClass);\n        }\n    },\n    VEHICLE {\n        @Override\n        protected boolean isEntityListedInternal(Class<? extends Entity> entityClass) {\n            return Vehicle.class.isAssignableFrom(entityClass) && !Creature.class.isAssignableFrom(entityClass);\n        }\n    },\n    MONSTER {\n        @Override\n        protected boolean isEntityListedInternal(Class<? extends Entity> entityClass) {\n            return Monster.class.isAssignableFrom(entityClass) ||\n                    Slime.class.isAssignableFrom(entityClass) || Flying.class.isAssignableFrom(entityClass) ||\n                    entityClass == HOGLIN_CLASS || entityClass == SKELETON_HORSE_CLASS ||\n                    entityClass == ZOMBIE_HORSE_CLASS || entityClass == ZOMBIE_NAUTILUS_CLASS;\n        }\n    },\n    ANIMAL {\n        @Override\n        protected boolean isEntityListedInternal(Class<? extends Entity> entityClass) {\n            return !BuiltinEntityCategory.MONSTER.isEntityListedInternal(entityClass) &&\n                    (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass));\n        }\n    };\n\n    @Nullable\n    private static final Class<?> HOGLIN_CLASS = getEntityTypeClass(\"org.bukkit.entity.Hoglin\");\n    @Nullable\n    private static final Class<?> SKELETON_HORSE_CLASS = getEntityTypeClass(\"org.bukkit.entity.SkeletonHorse\");\n    @Nullable\n    private static final Class<?> ZOMBIE_HORSE_CLASS = getEntityTypeClass(\"org.bukkit.entity.ZombieHorse\");\n    @Nullable\n    private static final Class<?> ZOMBIE_NAUTILUS_CLASS = getEntityTypeClass(\"org.bukkit.entity.ZombieNautilus\");\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private final KeySet entities = getEntitiesInternal();\n    private WeakReference<EntityCategory> entityCategoryReference;\n\n    public KeySet getEntities() {\n        return entities;\n    }\n\n    @NotNull\n    public EntityCategory getEntityCategory() {\n        if (this.entityCategoryReference == null) {\n            EntityCategory entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name());\n            this.entityCategoryReference = new WeakReference<>(entityCategory);\n            return Objects.requireNonNull(entityCategory);\n        }\n\n        EntityCategory entityCategory = this.entityCategoryReference.get();\n        if (entityCategory == null) {\n            entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name());\n            this.entityCategoryReference = new WeakReference<>(entityCategory);\n        }\n\n        return Objects.requireNonNull(entityCategory);\n    }\n\n    private KeySet getEntitiesInternal() {\n        KeySet entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE);\n        for (EntityType entityType : EntityType.values()) {\n            Class<? extends Entity> entityClass = entityType.getEntityClass();\n            if (entityClass != null && isEntityListedInternal(entityClass)) {\n                entities.add(Keys.of(entityType));\n            }\n        }\n        return entities.isEmpty() ? KeySets.createEmptySet() : KeySets.unmodifiableKeySet(entities);\n    }\n\n    protected boolean isEntityListedInternal(Class<? extends Entity> entityClass) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Nullable\n    private static Class<?> getEntityTypeClass(String clazz) {\n        try {\n            return Class.forName(clazz);\n        } catch (ClassNotFoundException error) {\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.world.entity;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.entity.EntityCategory;\nimport com.bgsoftware.superiorskyblock.api.island.IslandFlag;\nimport com.bgsoftware.superiorskyblock.api.island.IslandPrivilege;\nimport com.bgsoftware.superiorskyblock.api.key.KeySet;\nimport com.bgsoftware.superiorskyblock.core.LazyReference;\nimport com.bgsoftware.superiorskyblock.core.key.set.KeySets;\n\nimport java.util.HashSet;\n\npublic class EntityCategoryImpl implements EntityCategory {\n\n    private final String name;\n    private final KeySet entities;\n    @Nullable\n    private final IslandPrivilege spawnPrivilege;\n    @Nullable\n    private final IslandPrivilege damagePrivilege;\n    @Nullable\n    private final IslandPrivilege interactPrivilege;\n    @Nullable\n    private final IslandFlag spawnerSpawnFlag;\n    @Nullable\n    private final IslandFlag naturalSpawnFlag;\n\n    public EntityCategoryImpl(String name, KeySet entities, @Nullable IslandPrivilege spawnPrivilege,\n                              @Nullable IslandPrivilege damagePrivilege, @Nullable IslandPrivilege interactPrivilege,\n                              @Nullable IslandFlag spawnerSpawnFlag, @Nullable IslandFlag naturalSpawnFlag) {\n        this.name = name;\n        this.entities = KeySets.unmodifiableKeySet(entities);\n        this.spawnPrivilege = spawnPrivilege;\n        this.damagePrivilege = damagePrivilege;\n        this.interactPrivilege = interactPrivilege;\n        this.spawnerSpawnFlag = spawnerSpawnFlag;\n        this.naturalSpawnFlag = naturalSpawnFlag;\n    }\n\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    @Override\n    public KeySet getEntities() {\n        return this.entities;\n    }\n\n    @Override\n    public IslandPrivilege getSpawnPrivilege() {\n        return this.spawnPrivilege;\n    }\n\n    @Override\n    public IslandPrivilege getDamagePrivilege() {\n        return this.damagePrivilege;\n    }\n\n    @Override\n    public IslandPrivilege getInteractPrivilege() {\n        return this.interactPrivilege;\n    }\n\n    @Override\n    public IslandFlag getSpawnerSpawningIslandFlag() {\n        return this.spawnerSpawnFlag;\n    }\n\n    @Override\n    public IslandFlag getNaturalSpawningIslandFlag() {\n        return this.naturalSpawnFlag;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/generator/IslandsGenerator.java",
    "content": "package com.bgsoftware.superiorskyblock.world.generator;\n\nimport org.bukkit.generator.ChunkGenerator;\n\npublic abstract class IslandsGenerator extends ChunkGenerator {\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.key.KeyIndicator;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport org.bukkit.Location;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\npublic abstract class BaseSchematic implements Schematic {\n\n    protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    protected final String name;\n\n    protected final KeyMap<Integer> cachedCounts;\n\n    protected BaseSchematic(String name) {\n        this(name, KeyMaps.createArrayMap(KeyIndicator.MATERIAL));\n    }\n\n    protected BaseSchematic(String name, KeyMap<Integer> cachedCounts) {\n        this.name = name;\n        this.cachedCounts = cachedCounts;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public Map<Key, Integer> getBlockCounts() {\n        return Collections.unmodifiableMap(cachedCounts);\n    }\n\n    @Override\n    public void pasteSchematic(Island island, Location location, Runnable callback) {\n        pasteSchematic(island, location, callback, null);\n    }\n\n    public abstract List<ChunkPosition> getAffectedChunks();\n\n    @Nullable\n    public abstract Runnable onTeleportCallback();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic;\n\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicEntityFilter;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.entity.EntityType;\n\n@SuppressWarnings(\"UnusedReturnValue\")\npublic class SchematicBuilder {\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n    private final CompoundTag compoundTag = CompoundTag.of();\n\n    public SchematicBuilder withBlockOffset(BlockOffset blockOffset) {\n        this.compoundTag.setString(\"blockPosition\", Serializers.OFFSET_SERIALIZER.serialize(blockOffset));\n        return this;\n    }\n\n    public SchematicBuilder withBlockType(Material blockType, int data) {\n        if (ServerVersion.isLegacy()) {\n            this.compoundTag.setInt(\"combinedId\", plugin.getNMSAlgorithms().getCombinedId(blockType, (byte) data));\n        } else {\n            this.compoundTag.setString(\"type\", blockType.name());\n            if (data != 0)\n                this.compoundTag.setInt(\"data\", data);\n        }\n\n        return this;\n    }\n\n    public SchematicBuilder withLightLevels(byte[] lightLevels) {\n        if (lightLevels.length > 0 && lightLevels[0] > 0)\n            this.compoundTag.setByte(\"skyLightLevel\", lightLevels[0]);\n        if (lightLevels.length > 1 && lightLevels[1] > 0)\n            this.compoundTag.setByte(\"blockLightLevel\", lightLevels[1]);\n        return this;\n    }\n\n    public SchematicBuilder withStates(CompoundTag statesTag) {\n        if (statesTag != null)\n            this.compoundTag.setTag(\"states\", statesTag);\n        return this;\n    }\n\n    public SchematicBuilder withTileEntity(CompoundTag tileEntity) {\n        if (tileEntity != null)\n            this.compoundTag.setTag(\"tileEntity\", tileEntity);\n        return this;\n    }\n\n    public SchematicBuilder applyEntity(EntityType entityType, CompoundTag entityTag, Location offset) {\n        this.compoundTag.setString(\"offset\", Serializers.LOCATION_SERIALIZER.serialize(offset));\n        this.compoundTag.setString(\"entityType\", entityType.name());\n        this.compoundTag.setTag(\"NBT\", SchematicEntityFilter.filterNBTTag(entityTag));\n\n        return this;\n    }\n\n    public CompoundTag build() {\n        return this.compoundTag;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.handlers.SchematicManager;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition;\nimport com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.Manager;\nimport com.bgsoftware.superiorskyblock.core.ObjectsPools;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.SequentialListBuilder;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException;\nimport com.bgsoftware.superiorskyblock.core.io.Files;\nimport com.bgsoftware.superiorskyblock.core.io.Resources;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.messages.Message;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.world.ChunkReader;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.FloatTag;\nimport com.bgsoftware.superiorskyblock.tag.IntTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.StringTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.WorldReader;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.schematic.container.SchematicsContainer;\nimport com.bgsoftware.superiorskyblock.world.schematic.impl.CachedSuperiorSchematic;\nimport com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic;\nimport com.bgsoftware.superiorskyblock.world.schematic.parser.DefaultSchematicParser;\nimport com.google.common.base.Preconditions;\nimport com.google.common.util.concurrent.ThreadFactoryBuilder;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.Material;\nimport org.bukkit.World;\nimport org.bukkit.entity.Entity;\nimport org.bukkit.entity.EntityType;\nimport org.bukkit.entity.Player;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.function.Consumer;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\npublic class SchematicsManagerImpl extends Manager implements SchematicManager {\n\n    private final SchematicsContainer schematicsContainer;\n\n    public SchematicsManagerImpl(SuperiorSkyblockPlugin plugin, SchematicsContainer schematicsContainer) {\n        super(plugin);\n        this.schematicsContainer = schematicsContainer;\n    }\n\n    public void loadData() throws ManagerLoadException {\n        File schematicsFolder = new File(plugin.getDataFolder(), \"schematics\");\n\n        if (!schematicsFolder.exists()) {\n            schematicsFolder.mkdirs();\n            Resources.saveResource(\"schematics/desert.schematic\");\n            Resources.saveResource(\"schematics/desert_nether.schematic\", \"schematics/normal_nether.schematic\");\n            Resources.saveResource(\"schematics/desert_the_end.schematic\", \"schematics/normal_the_end.schematic\");\n            Resources.saveResource(\"schematics/mycel.schematic\");\n            Resources.saveResource(\"schematics/mycel_nether.schematic\", \"schematics/normal_nether.schematic\");\n            Resources.saveResource(\"schematics/mycel_the_end.schematic\", \"schematics/normal_the_end.schematic\");\n            Resources.saveResource(\"schematics/normal.schematic\");\n            Resources.saveResource(\"schematics/normal_nether.schematic\");\n            Resources.saveResource(\"schematics/normal_the_end.schematic\");\n        }\n\n        loadDefaultSchematicParsers();\n        loadSchematics();\n    }\n\n    public void loadSchematics() throws ManagerLoadException {\n        this.schematicsContainer.clearSchematics();\n\n        File schematicsFolder = new File(plugin.getDataFolder(), \"schematics\");\n        List<File> schematicFilesList = Files.listFolderFiles(schematicsFolder, false);\n\n        if (!schematicFilesList.isEmpty()) {\n            int schematicFilesCount = schematicFilesList.size();\n            List<Schematic> loadedSchematics = Collections.synchronizedList(new LinkedList<>());\n\n            CountDownLatch latch = new CountDownLatch(schematicFilesCount);\n\n            int threadCount = Math.min(schematicFilesCount, Runtime.getRuntime().availableProcessors() * 2);\n            ExecutorService loadService = Executors.newFixedThreadPool(threadCount,\n                    new ThreadFactoryBuilder().setNameFormat(\"SuperiorSkyblock Load Schematic Worker #%d\").build());\n\n            Log.info(\"Loading \" + schematicFilesCount + \" schematics using \" + threadCount + \" threads...\");\n\n            try {\n                for (File schemFile : schematicFilesList) {\n                    loadService.submit(() -> {\n                        String schemName = Files.getFileName(schemFile).toLowerCase(Locale.ENGLISH);\n                        try {\n                            Schematic schematic = loadFromFile(schemName, schemFile);\n                            if (schematic != null) {\n                                loadedSchematics.add(schematic);\n                            }\n                        } catch (Throwable error) {\n                            Log.error(error, \"An unexpected error occurred while loading schematic \" + schemName);\n                        } finally {\n                            latch.countDown();\n\n                            long remaining = latch.getCount();\n                            if (remaining > 0 && remaining % 50 == 0) {\n                                Log.info(\"Schematic loading progress: \" + (schematicFilesCount - remaining) + \"/\" + schematicFilesCount);\n                            }\n                        }\n                    });\n                }\n\n                latch.await();\n\n                loadService.shutdown();\n\n                Log.info(\"Successfully loaded \" + loadedSchematics.size() + \" schematics.\");\n\n                for (Schematic schematic : loadedSchematics) {\n                    this.schematicsContainer.addSchematic(schematic);\n                }\n            } catch (InterruptedException e) {\n                Log.error(\"Schematic loading thread was interrupted.\");\n                loadService.shutdownNow();\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        if (this.schematicsContainer.getSchematics().isEmpty()) {\n            throw new ManagerLoadException(\"&cThere were no valid schematics.\",\n                    ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN);\n        }\n\n        // Force garbage collection to release file handles on Windows\n        System.gc();\n    }\n\n    public void cacheSchematics() {\n        if (!plugin.getSettings().isCacheSchematics() || plugin.getSettings().getMaxIslandSize() % 4 != 0 || true)\n            return;\n\n        List<Schematic> newSchematics = new LinkedList<>();\n        boolean cachedSchematic = false;\n\n        for (Schematic schematic : this.schematicsContainer.getSchematics().values()) {\n            if (schematic instanceof SuperiorSchematic) {\n                try {\n                    schematic = new CachedSuperiorSchematic((SuperiorSchematic) schematic);\n                    cachedSchematic = true;\n                } catch (Throwable error) {\n                    Log.warn(\"Cannot cache schematic \", schematic.getName(), \", skipping...\");\n                }\n            }\n            newSchematics.add(schematic);\n        }\n\n        if (!cachedSchematic)\n            return;\n\n        this.schematicsContainer.clearSchematics();\n        newSchematics.forEach(this.schematicsContainer::addSchematic);\n    }\n\n    private void loadDefaultSchematicParsers() {\n        if (Bukkit.getPluginManager().isPluginEnabled(\"FastAsyncWorldEdit\")) {\n            try {\n                Class.forName(\"com.boydti.fawe.object.schematic.Schematic\");\n                SchematicParser schematicParser = (SchematicParser) Class.forName(\"com.bgsoftware.superiorskyblock.world.schematic.parser.FAWESchematicParser\").newInstance();\n                this.schematicsContainer.addSchematicParser(schematicParser);\n            } catch (Exception ignored) {\n            }\n        }\n    }\n\n    @Override\n    public Schematic getSchematic(String name) {\n        Preconditions.checkNotNull(name, \"name parameter cannot be null.\");\n        return this.schematicsContainer.getSchematic(name);\n    }\n\n    @Override\n    public List<String> getSchematics() {\n        return new SequentialListBuilder<String>()\n                .build(this.schematicsContainer.getSchematics().keySet());\n    }\n\n    @Override\n    public void registerSchematicParser(SchematicParser schematicParser) {\n        Preconditions.checkNotNull(schematicParser, \"schematicParser parameter cannot be null.\");\n        this.schematicsContainer.addSchematicParser(schematicParser);\n    }\n\n    @Override\n    public List<SchematicParser> getSchematicParsers() {\n        return this.schematicsContainer.getSchematicParsers();\n    }\n\n    @Override\n    public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName) {\n        saveSchematic(superiorPlayer, schematicName, false);\n    }\n\n    @Override\n    public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir) {\n        Preconditions.checkNotNull(superiorPlayer, \"superiorPlayer parameter cannot be null.\");\n        Preconditions.checkArgument(superiorPlayer.isOnline(), \"superiorPlayer must be online.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n\n        BlockPosition pos1 = superiorPlayer.getSchematicPos1();\n        BlockPosition pos2 = superiorPlayer.getSchematicPos2();\n\n        Location offset;\n        try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n            offset = superiorPlayer.getLocation(wrapper.getHandle()).subtract(\n                    Math.min(pos1.getX(), pos2.getX()),\n                    Math.min(pos1.getY(), pos2.getY()) + 1,\n                    Math.min(pos1.getZ(), pos2.getZ())\n            );\n        }\n\n        SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName)\n                .setOffset(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ())\n                .setDirection(offset.getYaw(), offset.getPitch())\n                .setSaveAir(saveAir)\n                .build();\n\n        World world = offset.getWorld();\n        saveSchematic(pos1.toLocation(world), pos2.toLocation(world), schematicOptions,\n                () -> Message.SCHEMATIC_SAVED.send(superiorPlayer));\n\n        superiorPlayer.setSchematicPos1(null);\n        superiorPlayer.setSchematicPos2(null);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName) {\n        Preconditions.checkNotNull(pos1, \"pos1 parameter cannot be null.\");\n        Preconditions.checkNotNull(pos2, \"pos2 parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, 0, 0, schematicName);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName) {\n        Preconditions.checkNotNull(pos1, \"pos1 parameter cannot be null.\");\n        Preconditions.checkNotNull(pos2, \"pos2 parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, yaw, pitch, schematicName, null);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName, Runnable callable) {\n        Preconditions.checkNotNull(pos1, \"pos1 parameter cannot be null.\");\n        Preconditions.checkNotNull(pos2, \"pos2 parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n        saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, 0, 0, schematicName, callable);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch,\n                              String schematicName, @Nullable Runnable callable) {\n        Preconditions.checkNotNull(pos1, \"pos1 parameter cannot be null.\");\n        Preconditions.checkNotNull(pos2, \"pos2 parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicName, \"schematicName parameter cannot be null.\");\n\n        SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName)\n                .setOffset(offsetX, offsetY, offsetZ)\n                .setDirection(yaw, pitch)\n                .build();\n\n        saveSchematic(pos1, pos2, schematicOptions, callable);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions) {\n        saveSchematic(pos1, pos2, schematicOptions, null);\n    }\n\n    @Override\n    public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable) {\n        Preconditions.checkNotNull(pos1, \"pos1 parameter cannot be null.\");\n        Preconditions.checkNotNull(pos2, \"pos2 parameter cannot be null.\");\n        Preconditions.checkNotNull(schematicOptions, \"schematicOptions parameter cannot be null.\");\n\n        Log.debug(Debug.SAVE_SCHEMATIC, pos1, pos2, schematicOptions.getOffsetX(), schematicOptions.getOffsetY(),\n                schematicOptions.getOffsetZ(), schematicOptions.getYaw(), schematicOptions.getPitch(),\n                schematicOptions.shouldSaveAir(), schematicOptions.getSchematicName());\n\n        World world = pos1.getWorld();\n\n        int minBlockX = Math.min(pos1.getBlockX(), pos2.getBlockX());\n        int minBlockY = Math.min(pos1.getBlockY(), pos2.getBlockY());\n        int minBlockZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());\n\n        int maxBlockX = Math.max(pos1.getBlockX(), pos2.getBlockX());\n        int maxBlockY = Math.max(pos1.getBlockY(), pos2.getBlockY());\n        int maxBlockZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());\n\n        int xSize = maxBlockX - minBlockX;\n        int ySize = maxBlockY - minBlockY;\n        int zSize = maxBlockZ - minBlockZ;\n\n        WorldReader worldReader = new WorldReader(world, ChunkLoadReason.SCHEMATIC_SAVE);\n\n        int minChunkX = minBlockX >> 4;\n        int minChunkZ = minBlockZ >> 4;\n        int maxChunkX = maxBlockX >> 4;\n        int maxChunkZ = maxBlockZ >> 4;\n        for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) {\n            for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) {\n                worldReader.prepareChunk(ChunkPosition.of(world, chunkX, chunkZ));\n            }\n        }\n\n        worldReader.finish(() -> {\n            List<Tag<?>> entities = new ArrayList<>();\n            List<Tag<?>> blocks = new ArrayList<>();\n\n            for (int x = minBlockX; x <= maxBlockX; ++x) {\n                for (int z = minBlockZ; z <= maxBlockZ; ++z) {\n                    ChunkReader chunkReader = worldReader.getChunkReader(x, z);\n\n                    int offsetBlockX = x - minBlockX;\n                    int offsetBlockZ = z - minBlockZ;\n\n                    int chunkBlockX = x & 0xF;\n                    int chunkBlockZ = z & 0xF;\n\n                    for (int chunkBlockY = minBlockY; chunkBlockY <= maxBlockY; ++chunkBlockY) {\n                        Material blockType = chunkReader.getType(chunkBlockX, chunkBlockY, chunkBlockZ);\n                        if (!schematicOptions.shouldSaveAir() && blockType == Material.AIR)\n                            continue;\n\n                        short blockData = chunkReader.getData(chunkBlockX, chunkBlockY, chunkBlockZ);\n                        CompoundTag blockStates = chunkReader.readBlockStates(chunkBlockX, chunkBlockY, chunkBlockZ);\n                        byte[] lightLevels = chunkReader.getLightLevels(chunkBlockX, chunkBlockY, chunkBlockZ);\n                        CompoundTag tileEntity = chunkReader.getTileEntity(chunkBlockX, chunkBlockY, chunkBlockZ);\n\n                        int offsetBlockY = chunkBlockY - minBlockY;\n\n                        blocks.add(new SchematicBuilder()\n                                .withBlockOffset(SBlockOffset.fromOffsets(offsetBlockX, offsetBlockY, offsetBlockZ))\n                                .withBlockType(blockType, blockData)\n                                .withStates(blockStates)\n                                .withLightLevels(lightLevels)\n                                .withTileEntity(tileEntity)\n                                .build()\n                        );\n                    }\n                }\n            }\n\n            for (int x = minChunkX; x <= maxChunkX; ++x) {\n                for (int z = minChunkZ; z <= maxChunkZ; ++z) {\n                    ChunkReader chunkReader = worldReader.getChunkReader(x << 4, z << 4);\n                    if (chunkReader != null) {\n                        chunkReader.forEachEntity((entityType, entityTag, location) -> {\n                            if (entityType != EntityType.PLAYER &&\n                                    location.getBlockX() >= minBlockX && location.getBlockX() <= maxBlockX &&\n                                    location.getBlockY() >= minBlockY && location.getBlockY() <= maxBlockY &&\n                                    location.getBlockZ() >= minBlockZ && location.getBlockZ() <= maxBlockZ) {\n                                location.subtract(minBlockX, minBlockY, minBlockZ);\n                                entities.add(new SchematicBuilder().applyEntity(entityType, entityTag, location).build());\n                            }\n                        });\n                    }\n                }\n            }\n\n            Map<String, Tag<?>> compoundValue = new HashMap<>();\n            compoundValue.put(\"xSize\", IntTag.of(xSize));\n            compoundValue.put(\"ySize\", IntTag.of(ySize));\n            compoundValue.put(\"zSize\", IntTag.of(zSize));\n            compoundValue.put(\"blocks\", ListTag.of(blocks, CompoundTag.class));\n            compoundValue.put(\"entities\", ListTag.of(entities, CompoundTag.class));\n            compoundValue.put(\"offsetX\", IntTag.of(schematicOptions.getOffsetX()));\n            compoundValue.put(\"offsetY\", IntTag.of(schematicOptions.getOffsetY()));\n            compoundValue.put(\"offsetZ\", IntTag.of(schematicOptions.getOffsetZ()));\n            compoundValue.put(\"yaw\", FloatTag.of(schematicOptions.getYaw()));\n            compoundValue.put(\"pitch\", FloatTag.of(schematicOptions.getPitch()));\n            compoundValue.put(\"version\", StringTag.of(ServerVersion.getBukkitVersion()));\n            if (!ServerVersion.isLegacy())\n                compoundValue.put(\"minecraftDataVersion\", IntTag.of(plugin.getNMSAlgorithms().getDataVersion()));\n\n            CompoundTag schematicTag = CompoundTag.of(compoundValue);\n            SuperiorSchematic schematic = new SuperiorSchematic(schematicOptions.getSchematicName(), schematicTag);\n            this.schematicsContainer.addSchematic(schematic);\n            saveIntoFile(schematicOptions.getSchematicName(), schematicTag);\n\n            if (callable != null)\n                BukkitExecutor.sync(callable);\n        });\n\n    }\n\n    public String getDefaultSchematic(Dimension dimension) {\n        String suffix = \"_\" + dimension.getName().toLowerCase(Locale.ENGLISH);\n        for (String schematicName : this.schematicsContainer.getSchematics().keySet()) {\n            if (getSchematic(schematicName + suffix) != null)\n                return schematicName;\n        }\n\n        return \"\";\n    }\n\n    private Schematic parseSchematic(File file, String schemName, SchematicParser schematicParser,\n                                     Consumer<SchematicParseException> onSchematicParseError) {\n        try (DataInputStream reader = new DataInputStream(new GZIPInputStream(java.nio.file.Files.newInputStream(file.toPath())))) {\n            return schematicParser.parseSchematic(reader, schemName);\n        } catch (SchematicParseException error) {\n            onSchematicParseError.accept(error);\n        } catch (Exception error) {\n            Log.entering(\"SchematicsManagerImpl\", \"parseSchematic\", \"ENTER\", file.getName(), schemName);\n            Log.error(error, \"An unexpected error occurred while loading schematic:\");\n        }\n\n        return null;\n    }\n\n    private Schematic loadFromFile(String schemName, File file) {\n        Schematic schematic = null;\n        SchematicParser usedParser = null;\n\n        for (SchematicParser schematicParser : this.schematicsContainer.getSchematicParsers()) {\n            schematic = parseSchematic(file, schemName, schematicParser, error -> {\n            });\n            if (schematic != null) {\n                usedParser = schematicParser;\n                break;\n            }\n        }\n\n        if (schematic == null) {\n            schematic = parseSchematic(file, schemName, DefaultSchematicParser.getInstance(), error ->\n                    Log.warn(\"Schematic \", file.getName(), \" is not a valid schematic, ignoring...\")\n            );\n            if (schematic != null)\n                usedParser = DefaultSchematicParser.getInstance();\n        }\n\n        if (schematic != null && usedParser != null) {\n            Log.info(\"Successfully loaded schematic \", file.getName(), \" (\", usedParser.getClass().getSimpleName(), \")\");\n        }\n\n        return schematic;\n    }\n\n    private void saveIntoFile(String name, CompoundTag schematicTag) {\n        try {\n            File file = new File(plugin.getDataFolder(), \"schematics/\" + name + \".schematic\");\n\n            if (file.exists())\n                file.delete();\n\n            file.getParentFile().mkdirs();\n            file.createNewFile();\n\n            try (DataOutputStream writer = new DataOutputStream(new GZIPOutputStream(java.nio.file.Files.newOutputStream(file.toPath())))) {\n                schematicTag.write(writer);\n            }\n        } catch (IOException error) {\n            Log.entering(\"SchematicsManagerImpl\", \"saveIntoFile\", \"ENTER\", name);\n            Log.error(error, \"An unexpected error occurred while saving schematic into file:\");\n        }\n    }\n\n    private List<Entity> getEntities(Location min, Location max) {\n        List<Entity> livingEntities = new LinkedList<>();\n\n        Chunk minChunk = min.getChunk();\n        Chunk maxChunk = max.getChunk();\n        for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) {\n            for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) {\n                Chunk currentChunk = min.getWorld().getChunkAt(x, z);\n                for (Entity entity : currentChunk.getEntities()) {\n                    try (ObjectsPools.Wrapper<Location> wrapper = ObjectsPools.LOCATION.obtain()) {\n                        if (!(entity instanceof Player) && betweenLocations(entity.getLocation(wrapper.getHandle()), min, max))\n                            livingEntities.add(entity);\n                    }\n                }\n            }\n        }\n\n        return livingEntities;\n    }\n\n    private boolean betweenLocations(Location location, Location min, Location max) {\n        return location.getBlockX() >= min.getBlockX() && location.getBlockX() <= max.getBlockX() &&\n                location.getBlockY() >= min.getBlockY() && location.getBlockY() <= max.getBlockY() &&\n                location.getBlockZ() >= min.getBlockZ() && location.getBlockZ() <= max.getBlockZ();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic class DefaultSchematicsContainer implements SchematicsContainer {\n\n    private final Map<String, Schematic> schematicMap = new LinkedHashMap<>();\n    private final List<SchematicParser> schematicParsers = new LinkedList<>();\n\n    @Nullable\n    @Override\n    public Schematic getSchematic(String name) {\n        return this.schematicMap.get(name.toLowerCase(Locale.ENGLISH));\n    }\n\n    @Override\n    public void addSchematic(Schematic schematic) {\n        this.schematicMap.put(schematic.getName().toLowerCase(Locale.ENGLISH), schematic);\n    }\n\n    @Override\n    public Map<String, Schematic> getSchematics() {\n        return Collections.unmodifiableMap(this.schematicMap);\n    }\n\n    @Override\n    public void addSchematicParser(SchematicParser schematicParser) {\n        this.schematicParsers.add(schematicParser);\n    }\n\n    @Override\n    public List<SchematicParser> getSchematicParsers() {\n        return Collections.unmodifiableList(this.schematicParsers);\n    }\n\n    @Override\n    public void clearSchematics() {\n        this.schematicMap.clear();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.container;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface SchematicsContainer {\n\n    @Nullable\n    Schematic getSchematic(String name);\n\n    void addSchematic(Schematic schematic);\n\n    Map<String, Schematic> getSchematics();\n\n    void addSchematicParser(SchematicParser schematicParser);\n\n    List<SchematicParser> getSchematicParsers();\n\n    void clearSchematics();\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.world.Dimension;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory;\nimport com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView;\nimport com.bgsoftware.superiorskyblock.core.key.map.KeyMaps;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.world.WorldGenerator;\nimport com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator;\nimport com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic;\nimport org.bukkit.Location;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\npublic class CachedSuperiorSchematic extends BaseSchematic implements Schematic {\n\n    private final Int2ObjectMapView<WorldEditSessionCache> cachedSessions = CollectionsFactory.createInt2ObjectArrayMap();\n    private final SuperiorSchematic baseSchematic;\n    private final Dimension schematicDimension;\n\n    public CachedSuperiorSchematic(SuperiorSchematic baseSchematic) {\n        super(baseSchematic.getName(), KeyMaps.createEmptyMap());\n        this.baseSchematic = baseSchematic;\n        this.schematicDimension = getSchematicDimension(baseSchematic.getName());\n        if (!(WorldGenerator.getWorldGenerator(this.schematicDimension) instanceof IslandsGenerator))\n            throw new IllegalStateException(\"Cannot use cached schematics with custom generators\");\n        populateCache();\n    }\n\n    @Override\n    public Map<Key, Integer> getBlockCounts() {\n        return this.baseSchematic.getBlockCounts();\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        return this.baseSchematic.getAffectedChunks();\n    }\n\n    @Override\n    public Runnable onTeleportCallback() {\n        return this.baseSchematic.onTeleportCallback();\n    }\n\n    @Override\n    public void pasteSchematic(Island island, Location location, Runnable callback, Consumer<Throwable> onFailure) {\n        BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure));\n    }\n\n    private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer<Throwable> onFailure) {\n        long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName());\n\n        Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location);\n\n        try {\n            pasteSchematicAsyncInternal(island, location, profiler, callback, onFailure);\n        } catch (Throwable error) {\n            Log.debugResult(Debug.PASTE_SCHEMATIC, \"Failed Schematic Placement\", error);\n            Profiler.end(profiler);\n            if (onFailure != null)\n                onFailure.accept(error);\n        }\n    }\n\n    private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer<Throwable> onFailure) {\n        int chunkX = location.getBlockX() & 0xF;\n        int chunkZ = location.getBlockZ() & 0xF;\n\n        long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName());\n\n        WorldEditSessionCache worldEditSessionCache = this.cachedSessions.get(posKey(chunkX, chunkZ));\n\n        if (worldEditSessionCache == null)\n            throw new IllegalStateException(\"Cannot find cache for (\" + chunkX + \",\" + chunkZ + \")\");\n\n        WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld());\n        worldEditSession.applyData(worldEditSessionCache.sessionData, location);\n\n        worldEditSessionCache.prePlaceTasks.forEach(schematicBlock -> {\n            schematicBlock.doPrePlace(island);\n\n            Location newBlockLoc = new Location(\n                    location.getWorld(),\n                    location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(),\n                    schematicBlock.getLocation().getBlockY(),\n                    location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ()\n            );\n\n            worldEditSession.setBlock(newBlockLoc, schematicBlock.getCombinedId(),\n                    schematicBlock.getStatesTag(), schematicBlock.getTileEntityData());\n        });\n\n        Profiler.end(placeProfiler);\n\n        List<SchematicBlock> postPlaceTasks = worldEditSessionCache.postPlaceTasks.isEmpty() ? Collections.emptyList() : new LinkedList<>();\n        worldEditSessionCache.postPlaceTasks.forEach(schematicBlock -> {\n            Location newBlockLoc = new Location(\n                    location.getWorld(),\n                    location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(),\n                    schematicBlock.getLocation().getBlockY(),\n                    location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ()\n            );\n\n            postPlaceTasks.add(schematicBlock.setLocation(newBlockLoc));\n        });\n\n        this.baseSchematic.finishPlaceSchematic(worldEditSession, postPlaceTasks,\n                island, location, profiler, callback, onFailure);\n    }\n\n    @Override\n    public Location adjustRotation(Location location) {\n        return this.baseSchematic.adjustRotation(location);\n    }\n\n    private void populateCache() {\n        Log.info(\"Caching schematics for \", this.name, \"...\");\n        int cacheSize = calculateCacheSize();\n        switch (cacheSize) {\n            case 1:\n                populateCache1Size();\n                break;\n            case 4:\n                populateCache4Size();\n                break;\n            case 16:\n                populateCache16Size();\n                break;\n        }\n    }\n\n    private void populateCache1Size() {\n        // Possible chunk offsets: {(0, 0)}\n        this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0));\n    }\n\n    private void populateCache4Size() {\n        // Possible chunk offsets: {(8, 8), (0, 8), (8, 0), (0, 0)}\n        this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24));\n        this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24));\n        this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0));\n        this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0));\n    }\n\n    private void populateCache16Size() {\n        // Possible chunk offsets: {(4, 4), (12, 4), (8, 8), (4, 0), (0, 4), (8, 4), (0, 0), (12, 0), (4, 12), (8, 0), (0, 12), (12, 12), (4, 8), (8, 12), (0, 8), (12, 8)}\n        this.cachedSessions.put(posKey(4, 4), createSessionCache(-12, -12));\n        this.cachedSessions.put(posKey(12, 4), createSessionCache(12, -12));\n        this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24));\n        this.cachedSessions.put(posKey(4, 0), createSessionCache(-12, 0));\n        this.cachedSessions.put(posKey(0, 4), createSessionCache(0, -12));\n        this.cachedSessions.put(posKey(8, 4), createSessionCache(24, -12));\n        this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0));\n        this.cachedSessions.put(posKey(12, 0), createSessionCache(12, 0));\n        this.cachedSessions.put(posKey(4, 12), createSessionCache(-12, 12));\n        this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0));\n        this.cachedSessions.put(posKey(0, 12), createSessionCache(0, 12));\n        this.cachedSessions.put(posKey(12, 12), createSessionCache(12, 12));\n        this.cachedSessions.put(posKey(4, 8), createSessionCache(-12, 24));\n        this.cachedSessions.put(posKey(8, 12), createSessionCache(-24, 12));\n        this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24));\n        this.cachedSessions.put(posKey(12, 8), createSessionCache(12, 24));\n    }\n\n    private WorldEditSessionCache createSessionCache(int x, int z) {\n        Location location = new Location(null, x, plugin.getSettings().getIslandHeight() - 1, z);\n        List<SchematicBlock> prePlaceTasks = new LinkedList<>();\n        List<SchematicBlock> postPlaceTasks = new LinkedList<>();\n\n        WorldEditSession worldEditSession = plugin.getNMSWorld().createPartialEditSession(this.schematicDimension);\n        this.baseSchematic.populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks);\n        WorldEditSession.Data sessionData = worldEditSession.readData(location);\n        worldEditSession.release();\n        return new WorldEditSessionCache(sessionData, prePlaceTasks, postPlaceTasks, location);\n    }\n\n    private static int posKey(int x, int z) {\n        byte xByte = (byte) (x & 0xF);\n        byte zByte = (byte) (z & 0xF);\n        return xByte << 8 | zByte;\n    }\n\n    private static int calculateCacheSize() {\n        switch ((plugin.getSettings().getMaxIslandSize() / 4) % 4) {\n            case 0:\n                return 1;\n            case 2:\n                return 4;\n            // case 1:\n            // case 3:\n            default:\n                return 16;\n        }\n    }\n\n    private static Dimension getSchematicDimension(String name) {\n        for (Dimension dimension : Dimension.values()) {\n            if (name.endsWith(\"_\" + dimension.getName().toLowerCase(Locale.ENGLISH)))\n                return dimension;\n        }\n\n        return plugin.getSettings().getWorlds().getDefaultWorldDimension();\n    }\n\n    private static class WorldEditSessionCache {\n\n        private final WorldEditSession.Data sessionData;\n        private final List<SchematicBlock> prePlaceTasks;\n        private final List<SchematicBlock> postPlaceTasks;\n        private final Location baseLocation;\n\n        WorldEditSessionCache(WorldEditSession.Data sessionData, List<SchematicBlock> prePlaceTasks, List<SchematicBlock> postPlaceTasks, Location baseLocation) {\n            this.sessionData = sessionData;\n            this.prePlaceTasks = prePlaceTasks;\n            this.postPlaceTasks = postPlaceTasks;\n            this.baseLocation = baseLocation;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.impl;\n\nimport com.bgsoftware.superiorskyblock.api.island.Island;\nimport com.bgsoftware.superiorskyblock.api.key.Key;\nimport com.bgsoftware.superiorskyblock.api.key.KeyMap;\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.BigBitSet;\nimport com.bgsoftware.superiorskyblock.core.ByteBigArray;\nimport com.bgsoftware.superiorskyblock.core.ChunkPosition;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\nimport com.bgsoftware.superiorskyblock.core.VarintArray;\nimport com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory;\nimport com.bgsoftware.superiorskyblock.core.logging.Debug;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean;\nimport com.bgsoftware.superiorskyblock.core.profiler.ProfileType;\nimport com.bgsoftware.superiorskyblock.core.profiler.Profiler;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicBlockData;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicEntity;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;\nimport com.bgsoftware.superiorskyblock.module.BuiltinModules;\nimport com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth;\nimport com.bgsoftware.superiorskyblock.nms.world.WorldEditSession;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason;\nimport com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider;\nimport com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic;\nimport org.bukkit.Bukkit;\nimport org.bukkit.Chunk;\nimport org.bukkit.Location;\nimport org.bukkit.entity.EntityType;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeSet;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\n\npublic class SuperiorSchematic extends BaseSchematic implements Schematic {\n\n    private static final ByteBigArray EMPTY_BLOCK_IDS = new ByteBigArray((short) 0);\n    private static final BigBitSet EMPTY_BIT_SET = new BigBitSet(0);\n\n    private final Data data;\n\n    private List<ChunkPosition> affectedChunks = null;\n    private Runnable onTeleportCallback = null;\n\n    public SuperiorSchematic(String name, CompoundTag compoundTag) {\n        super(name);\n\n        int xSize = compoundTag.getInt(\"xSize\").orElse(0);\n        int ySize = compoundTag.getInt(\"ySize\").orElse(0);\n        int zSize = compoundTag.getInt(\"zSize\").orElse(0);\n\n        int offsetX = compoundTag.getInt(\"offsetX\").orElse(xSize / 2);\n        int offsetY = compoundTag.getInt(\"offsetY\").orElse(ySize / 2);\n        int offsetZ = compoundTag.getInt(\"offsetZ\").orElse(zSize / 2);\n\n        BlockOffset schematicOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ).negate();\n        float yaw = (float) compoundTag.getFloat(\"yaw\").orElse(0f);\n        float pitch = (float) compoundTag.getFloat(\"pitch\").orElse(0f);\n\n        int dataVersion = compoundTag.getInt(\"minecraftDataVersion\").orElse(-1);\n\n        ByteBigArray blockIds;\n        BigBitSet bitSet;\n        Map<BlockOffset, SchematicBlock.Extra> extra;\n        int minX;\n        int minY;\n        int minZ;\n\n        ListTag blocksList = compoundTag.getList(\"blocks\").orElse(null);\n        if (blocksList == null) {\n            blockIds = EMPTY_BLOCK_IDS;\n            bitSet = EMPTY_BIT_SET;\n            extra = Collections.emptyMap();\n            minX = 0;\n            minY = 0;\n            minZ = 0;\n        } else {\n            minX = Integer.MAX_VALUE;\n            minY = Integer.MAX_VALUE;\n            minZ = Integer.MAX_VALUE;\n\n            int maxX = Integer.MIN_VALUE;\n            int maxY = Integer.MIN_VALUE;\n            int maxZ = Integer.MIN_VALUE;\n\n            TreeSet<SchematicBlockData> schematicBlocks = new TreeSet<>(Comparator.naturalOrder());\n\n            for (Tag<?> tag : blocksList) {\n                SchematicBlockData schematicBlock = SuperiorSchematicDeserializer.deserializeSchematicBlock((CompoundTag) tag, dataVersion);\n                if (schematicBlock != null) {\n                    schematicBlocks.add(schematicBlock);\n                    readBlock(schematicBlock);\n\n                    // Compute the min and max block offset as we want to shrink as much as possible the amount\n                    // of blocks in the schematic in memory. This will give us a layout of blocks that do not\n                    // include any AIR blocks at all.\n                    BlockOffset blockOffset = schematicBlock.getBlockOffset();\n                    minX = Math.min(blockOffset.getOffsetX(), minX);\n                    minY = Math.min(blockOffset.getOffsetY(), minY);\n                    minZ = Math.min(blockOffset.getOffsetZ(), minZ);\n                    maxX = Math.max(blockOffset.getOffsetX(), maxX);\n                    maxY = Math.max(blockOffset.getOffsetY(), maxY);\n                    maxZ = Math.max(blockOffset.getOffsetZ(), maxZ);\n                }\n            }\n\n            // The xSize,ySize,zSize in the schematic consider air blocks, however we do not want them.\n            // Therefore, we adjust the sizes accordingly to the actual blocks in the schematic.\n            xSize = maxX - minX + 1;\n            ySize = maxY - minY + 1;\n            zSize = maxZ - minZ + 1;\n            if ((long) xSize * (long) ySize * (long) zSize > Integer.MAX_VALUE) {\n                throw new IllegalStateException(\"Cannot create such large schematic of size \" + xSize + \"x\" + ySize + \"x\" + zSize);\n            }\n\n            VarintArray blockIdsVarintArray = new VarintArray();\n            bitSet = new BigBitSet(xSize * ySize * zSize);\n            extra = new HashMap<>();\n\n            for (SchematicBlockData schematicBlock : schematicBlocks) {\n                BlockOffset blockOffset = schematicBlock.getBlockOffset();\n\n                int x = blockOffset.getOffsetX() - minX;\n                int y = blockOffset.getOffsetY() - minY;\n                int z = blockOffset.getOffsetZ() - minZ;\n\n                // Calculate index in the BitSet for the given x,y,z.\n                // The BitSet is sorted similar to how SchematicBlockData#compareTo is implemented.\n                int index = y * (xSize * zSize) + x * zSize + z;\n                bitSet.set(index);\n                blockIdsVarintArray.add(schematicBlock.getCombinedId());\n\n                if (schematicBlock.getExtra() != null)\n                    extra.put(blockOffset, schematicBlock.getExtra());\n            }\n\n            blockIds = blockIdsVarintArray.toArray();\n        }\n\n        List<SchematicEntity> entities;\n        ListTag entitiesList = compoundTag.getList(\"entities\").orElse(null);\n        if (entitiesList == null) {\n            entities = Collections.emptyList();\n        } else {\n            entities = new LinkedList<>();\n\n            for (Tag<?> tag : entitiesList) {\n                CompoundTag compound = (CompoundTag) tag;\n                try {\n                    EntityType entityType = EntityType.valueOf(compound.getString(\"entityType\").orElse(null));\n                    CompoundTag entityTag = compound.getCompound(\"NBT\").orElse(null);\n                    Location offset = Serializers.LOCATION_SERIALIZER.deserialize(compound.getString(\"offset\").orElse(null));\n                    if (offset != null)\n                        entities.add(new SchematicEntity(entityType, entityTag,\n                                SBlockOffset.fromOffsets(offset.getX(), offset.getY(), offset.getZ())));\n                } catch (Exception error) {\n                    error.printStackTrace();\n                }\n            }\n        }\n\n        this.data = new Data(schematicOffset, yaw, pitch, bitSet, blockIds,\n                xSize, ySize, zSize, minX, minY, minZ, extra, entities);\n    }\n\n    private SuperiorSchematic(String name, Data data, KeyMap<Integer> cachedCounts) {\n        super(name, cachedCounts);\n        this.data = data;\n    }\n\n    @Override\n    public void pasteSchematic(Island island, Location location, Runnable callback, Consumer<Throwable> onFailure) {\n        BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure));\n    }\n\n    private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer<Throwable> onFailure) {\n        long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName());\n\n        Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location);\n\n        try {\n            pasteSchematicAsyncInternal(island, location, profiler, callback, onFailure);\n        } catch (Throwable error) {\n            Log.debugResult(Debug.PASTE_SCHEMATIC, \"Failed Schematic Placement\", error);\n            Profiler.end(profiler);\n            if (onFailure != null)\n                onFailure.accept(error);\n        }\n    }\n\n    public void populateSessionWithSchematicBlocks(WorldEditSession worldEditSession, Location location,\n                                                   List<SchematicBlock> prePlaceTasks, List<SchematicBlock> postPlaceTasks) {\n        Location min = this.data.offset.applyToLocation(location);\n\n        VarintArray.Itr blockIdsIterator = new VarintArray(this.data.blockIds).iterator();\n\n        for (int i = this.data.bitSet.nextSetBit(0); i >= 0; i = this.data.bitSet.nextSetBit(i + 1)) {\n            int x = ((i / this.data.zSize) % this.data.xSize) + this.data.minX;\n            int y = (i / (this.data.xSize * this.data.zSize)) + this.data.minY;\n            int z = (i % this.data.zSize) + this.data.minZ;\n\n            BlockOffset blockOffset = SBlockOffset.fromOffsets(x, y, z);\n\n            Location blockLocation = blockOffset.applyToLocation(min);\n            SchematicBlock schematicBlock = new SchematicBlock(blockLocation,\n                    (int) blockIdsIterator.next(), data.extra.get(blockOffset));\n\n            prePlaceTasks.add(schematicBlock);\n\n            worldEditSession.setBlock(blockLocation, schematicBlock.getCombinedId(),\n                    schematicBlock.getStatesTag(), schematicBlock.getTileEntityData());\n\n            if (schematicBlock.shouldPostPlace())\n                postPlaceTasks.add(schematicBlock);\n        }\n\n        if (blockIdsIterator.hasNext())\n            throw new IllegalStateException(\"Not all blocks were read from varint iterator\");\n    }\n\n    public void finishPlaceSchematic(WorldEditSession worldEditSession, List<SchematicBlock> postPlaceTasks,\n                                     Island island, Location location, long profiler, Runnable callback,\n                                     Consumer<Throwable> onFailure) {\n        List<ChunkPosition> affectedChunks = worldEditSession.getAffectedChunks();\n        List<CompletableFuture<Chunk>> chunkFutures = new ArrayList<>(affectedChunks.size());\n\n        AtomicBoolean failed = new AtomicBoolean(false);\n        MutableBoolean printedWarning = new MutableBoolean(false);\n\n        affectedChunks.forEach(chunkPosition -> {\n            if (!island.isInside(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ())) {\n                if (!printedWarning.get()) {\n                    Log.warn(\"Part of the schematic \", name, \" is placed outside of the island, skipping this part...\");\n                    printedWarning.set(true);\n                }\n                return;\n            }\n\n            chunkFutures.add(ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.SCHEMATIC_PLACE, chunk -> {\n                if (failed.get())\n                    return;\n\n                try {\n                    worldEditSession.applyBlocks(chunk);\n\n                    boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class);\n                    if (cropGrowthEnabled && island.isInsideRange(chunk)) {\n                        BukkitExecutor.ensureMain(() -> plugin.getNMSChunks().startTickingChunk(island, chunk, false));\n                    }\n\n                    island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true);\n\n                    Log.debugResult(Debug.PASTE_SCHEMATIC, \"Loaded Chunk\", chunkPosition);\n                } catch (Throwable error) {\n                    Log.debugResult(Debug.PASTE_SCHEMATIC, \"Failed Loading Chunk\", error);\n                    failed.set(true);\n                    Profiler.end(profiler);\n                    if (onFailure != null)\n                        onFailure.accept(error);\n                }\n            }));\n        });\n\n        CompletableFuture.allOf(chunkFutures.toArray(new CompletableFuture[0])).whenComplete((v, error) -> {\n            if (failed.get())\n                return;\n\n            Log.debugResult(Debug.PASTE_SCHEMATIC, \"Finished Chunks Loading\", \"\");\n\n            BukkitExecutor.ensureMain(() -> {\n                try {\n                    Log.debugResult(Debug.PASTE_SCHEMATIC, \"Placing Schematic\", \"\");\n                    worldEditSession.finish(island);\n\n                    if (island.getOwner().isOnline()) {\n                        postPlaceTasks.forEach(schematicBlock -> {\n                            schematicBlock.doPostPlace(island);\n                        });\n                    }\n\n                    Log.debugResult(Debug.PASTE_SCHEMATIC, \"Finished Schematic Placement\", \"\");\n\n                    island.handleBlocksPlace(cachedCounts);\n\n                    PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location);\n\n                    Profiler.end(profiler);\n\n                    synchronized (this) {\n                        try {\n                            Location min = this.data.offset.applyToLocation(location);\n                            prepareCallback(affectedChunks, min);\n                            callback.run();\n                        } finally {\n                            finishCallback();\n                        }\n                    }\n                } catch (Throwable error2) {\n                    Log.debugResult(Debug.PASTE_SCHEMATIC, \"Failed Finishing Placement\", error2);\n                    Profiler.end(profiler);\n                    if (onFailure != null)\n                        onFailure.accept(error2);\n                }\n            });\n        });\n    }\n\n    private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer<Throwable> onFailure) {\n        List<SchematicBlock> postPlaceTasks = new LinkedList<>();\n        List<SchematicBlock> prePlaceTasks = new LinkedList<>();\n\n        long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName());\n\n        WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld());\n        populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks);\n\n        prePlaceTasks.forEach(schematicBlock -> {\n            schematicBlock.doPrePlace(island);\n            worldEditSession.setBlock(schematicBlock.getLocation(), schematicBlock.getCombinedId(),\n                    schematicBlock.getStatesTag(), schematicBlock.getTileEntityData());\n        });\n\n        Profiler.end(placeProfiler);\n\n        finishPlaceSchematic(worldEditSession, postPlaceTasks, island, location, profiler, callback, onFailure);\n    }\n\n    @Override\n    public Location adjustRotation(Location location) {\n        location.setYaw(this.data.yaw);\n        location.setPitch(this.data.pitch);\n        return location;\n    }\n\n    @Override\n    public List<ChunkPosition> getAffectedChunks() {\n        return affectedChunks == null ? Collections.emptyList() : Collections.unmodifiableList(affectedChunks);\n    }\n\n    @Override\n    public Runnable onTeleportCallback() {\n        return this.onTeleportCallback;\n    }\n\n    public SuperiorSchematic copy(String newName) {\n        return new SuperiorSchematic(newName, this.data, this.cachedCounts);\n    }\n\n    private void readBlock(SchematicBlockData block) {\n        Key key = plugin.getNMSAlgorithms().getBlockKey(block.getCombinedId());\n        cachedCounts.put(key, cachedCounts.getRaw(key, 0) + 1);\n    }\n\n    private void prepareCallback(List<ChunkPosition> affectedChunks, Location min) {\n        this.affectedChunks = new LinkedList<>(affectedChunks);\n        // We spawn the entities with a delay, waiting for players to teleport to the island first.\n        this.onTeleportCallback = () -> {\n            BukkitExecutor.sync(() -> {\n                for (SchematicEntity entity : data.entities) {\n                    entity.spawnEntity(min);\n                }\n            }, 20L);\n        };\n    }\n\n    private void finishCallback() {\n        this.affectedChunks = null;\n        this.onTeleportCallback = null;\n    }\n\n    private static class Data {\n\n        private final BlockOffset offset;\n        private final float yaw;\n        private final float pitch;\n\n        private final BigBitSet bitSet;\n        private final ByteBigArray blockIds;\n        private final Map<BlockOffset, SchematicBlock.Extra> extra;\n        private final List<SchematicEntity> entities;\n\n        /* Required to deserialize the bitset */\n        private final int minX;\n        private final int minY;\n        private final int minZ;\n        private final int xSize;\n        private final int ySize;\n        private final int zSize;\n\n        Data(BlockOffset offset, float yaw, float pitch,\n             BigBitSet bitSet, ByteBigArray blockIds, int xSize, int ySize, int zSize, int minX, int minY, int minZ,\n             Map<BlockOffset, SchematicBlock.Extra> extra, List<SchematicEntity> entities) {\n            this.offset = offset;\n            this.yaw = yaw;\n            this.pitch = pitch;\n            this.bitSet = bitSet;\n            this.blockIds = blockIds;\n            this.minX = minX;\n            this.minY = minY;\n            this.minZ = minZ;\n            this.xSize = xSize;\n            this.ySize = ySize;\n            this.zSize = zSize;\n            this.extra = Collections.unmodifiableMap(extra);\n            this.entities = Collections.unmodifiableList(entities);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.impl;\n\nimport com.bgsoftware.common.annotations.Nullable;\nimport com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock;\nimport com.bgsoftware.superiorskyblock.core.schematic.SchematicBlockData;\nimport com.bgsoftware.superiorskyblock.core.serialization.Serializers;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.ListTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.google.common.collect.Maps;\nimport org.bukkit.DyeColor;\nimport org.bukkit.Material;\nimport org.bukkit.SkullType;\nimport org.bukkit.block.BlockFace;\nimport org.bukkit.inventory.ItemStack;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\npublic class SuperiorSchematicDeserializer {\n\n    private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList());\n\n    private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();\n\n    private static final EnumMap<BlockFace, Byte> rotationToByte = Maps.newEnumMap(BlockFace.class);\n\n    static {\n        rotationToByte.put(BlockFace.EAST, (byte) 4);\n        rotationToByte.put(BlockFace.SOUTH, (byte) 8);\n        rotationToByte.put(BlockFace.WEST, (byte) 12);\n        rotationToByte.put(BlockFace.NORTH_EAST, (byte) 2);\n        rotationToByte.put(BlockFace.NORTH_WEST, (byte) 14);\n        rotationToByte.put(BlockFace.SOUTH_EAST, (byte) 6);\n        rotationToByte.put(BlockFace.SOUTH_WEST, (byte) 10);\n        rotationToByte.put(BlockFace.WEST_NORTH_WEST, (byte) 13);\n        rotationToByte.put(BlockFace.NORTH_NORTH_WEST, (byte) 15);\n        rotationToByte.put(BlockFace.NORTH_NORTH_EAST, (byte) 1);\n        rotationToByte.put(BlockFace.EAST_NORTH_EAST, (byte) 3);\n        rotationToByte.put(BlockFace.EAST_SOUTH_EAST, (byte) 5);\n        rotationToByte.put(BlockFace.SOUTH_SOUTH_EAST, (byte) 7);\n        rotationToByte.put(BlockFace.SOUTH_SOUTH_WEST, (byte) 9);\n        rotationToByte.put(BlockFace.WEST_SOUTH_WEST, (byte) 11);\n    }\n\n    private SuperiorSchematicDeserializer() {\n\n    }\n\n    public static void convertOldTileEntity(CompoundTag compoundTag) {\n        CompoundTag tileEntity = CompoundTag.of();\n\n        compoundTag.getString(\"baseColor\").ifPresent(baseColor ->\n                tileEntity.setInt(\"Base\", DyeColor.valueOf(baseColor).getDyeData()));\n\n        compoundTag.getCompound(\"patterns\").ifPresent(patterns -> {\n            ListTag patternsList = ListTag.of(CompoundTag.class);\n\n            for (Tag<?> tag : patterns) {\n                if (tag instanceof CompoundTag) {\n                    CompoundTag oldPatternTag = (CompoundTag) tag;\n                    CompoundTag patternTag = CompoundTag.of();\n                    patternTag.setInt(\"Color\", oldPatternTag.getInt(\"color\").orElse(0));\n                    patternTag.setString(\"Pattern\", oldPatternTag.getString(\"type\").orElse(\"\"));\n                    patternsList.addTag(patternTag);\n                }\n            }\n\n            tileEntity.setTag(\"Patterns\", patternsList);\n        });\n\n        compoundTag.getCompound(\"contents\").ifPresent(contents -> {\n            ListTag items = ListTag.of(CompoundTag.class);\n            for (Map.Entry<String, Tag<?>> item : contents.entrySet()) {\n                if (item.getValue() instanceof CompoundTag) {\n                    try {\n                        ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) item.getValue());\n                        CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack);\n                        itemCompound.setByte(\"Slot\", Byte.parseByte(item.getKey()));\n                        items.addTag(itemCompound);\n                    } catch (Exception ignored) {\n                    }\n                }\n            }\n\n            tileEntity.setTag(\"Items\", items);\n\n            String inventoryType = compoundTag.getString(\"inventoryType\").orElse(\"CHEST\");\n            tileEntity.setString(\"inventoryType\", inventoryType);\n        });\n\n        compoundTag.getString(\"flower\").ifPresent(flower -> {\n            try {\n                String[] flowerSections = flower.split(\":\");\n                tileEntity.setString(\"Item\", plugin.getNMSAlgorithms().getMinecraftKey(new ItemStack(Material.valueOf(flowerSections[0]))));\n                tileEntity.setInt(\"Data\", Integer.parseInt(flowerSections[1]));\n            } catch (Exception ignored) {\n            }\n        });\n\n        compoundTag.getString(\"skullType\").ifPresent(skullType ->\n                tileEntity.setByte(\"SkullType\", (byte) (SkullType.valueOf(skullType).ordinal() - 1)));\n\n        compoundTag.getString(\"rotation\").ifPresent(rotation ->\n                tileEntity.setByte(\"Rot\", rotationToByte.getOrDefault(BlockFace.valueOf(rotation), (byte) 0)));\n\n        compoundTag.getString(\"owner\").ifPresent(owner ->\n                tileEntity.setString(\"Name\", owner));\n\n        for (int i = 0; i < 4; ++i) {\n            final String textLineKey = \"Text\" + (i + 1);\n            compoundTag.getString(\"signLine\" + i).ifPresent(signLine ->\n                    tileEntity.setString(textLineKey, plugin.getNMSAlgorithms().parseSignLine(signLine)));\n        }\n\n        compoundTag.getString(\"spawnedType\").ifPresent(spawnedType ->\n                tileEntity.setString(\"EntityId\", spawnedType));\n\n        if (!tileEntity.isEmpty())\n            compoundTag.setTag(\"tileEntity\", tileEntity);\n    }\n\n    @Nullable\n    public static SchematicBlockData deserializeSchematicBlock(CompoundTag compoundTag, int dataVersion) {\n        BlockOffset blockOffset = Serializers.OFFSET_SERIALIZER.deserialize(compoundTag.getString(\"blockPosition\").orElse(null));\n        int combinedId;\n\n        if (compoundTag.containsKey(\"combinedId\")) {\n            combinedId = compoundTag.getInt(\"combinedId\").getAsInt();\n        } else if (compoundTag.containsKey(\"id\") && compoundTag.containsKey(\"data\")) {\n            int id = compoundTag.getInt(\"id\").getAsInt();\n            int data = compoundTag.getInt(\"data\").getAsInt();\n            combinedId = id + (data << 12);\n        } else if (compoundTag.containsKey(\"type\")) {\n            Material type;\n\n            try {\n                type = Material.valueOf(compoundTag.getString(\"type\").get());\n            } catch (Exception ignored) {\n                return null;\n            }\n\n            int data = compoundTag.getInt(\"data\").orElse(0);\n\n            combinedId = plugin.getNMSAlgorithms().getCombinedId(type, (byte) data);\n        } else {\n            Log.warn(\"Couldn't find combinedId for the block \", compoundTag.getString(\"blockPosition\"), \" - skipping...\");\n            return null;\n        }\n\n        SuperiorSchematicDeserializer.convertOldTileEntity(compoundTag);\n\n        SchematicBlock.Extra extra = deserializeSchematicBlockExtra(compoundTag, dataVersion);\n\n        if (extra != null) {\n            CompoundTag tileEntityTag = extra.getTileEntity();\n            if (tileEntityTag != null && !tileEntityTag.containsKey(\"id\")) {\n                // We try to detect the id from its combinedId\n                plugin.getNMSAlgorithms().getTileEntityIdFromCombinedId(combinedId).ifPresent(tileEntityId -> {\n                    tileEntityTag.setString(\"id\", tileEntityId);\n                });\n            }\n        }\n\n        return new SchematicBlockData(combinedId, blockOffset, extra);\n    }\n\n    private static SchematicBlock.Extra deserializeSchematicBlockExtra(CompoundTag compoundTag, int dataVersion) {\n        // Ignore light levels\n        // byte skyLightLevel = compoundTag.getByte(\"skyLightLevel\");\n        // byte blockLightLevel = compoundTag.getByte(\"blockLightLevel\");\n\n        CompoundTag statesTag = compoundTag.getCompound(\"states\").orElse(null);\n        CompoundTag tileEntity = compoundTag.getCompound(\"tileEntity\").orElse(null);\n        tileEntity = SuperiorSchematicDeserializer.upgradeTileEntity(tileEntity, dataVersion);\n\n        return statesTag == null && tileEntity == null ? null : new SchematicBlock.Extra(statesTag, tileEntity);\n    }\n\n    @Nullable\n    private static CompoundTag upgradeTileEntity(@Nullable CompoundTag compoundTag, int dataVersion) {\n        if (compoundTag == null || dataVersion == -1)\n            return compoundTag;\n\n        int currentDataVersion = plugin.getNMSAlgorithms().getDataVersion();\n        if (currentDataVersion <= dataVersion)\n            return compoundTag;\n\n        // Convert chest contents\n        ListTag itemsTag = compoundTag.getList(\"Items\").orElse(EMPTY_ITEMS_LIST);\n        if (itemsTag.size() > 0) {\n            ListTag newItemsTag = ListTag.of(CompoundTag.class);\n\n            for (Tag<?> tag : itemsTag) {\n                if (tag instanceof CompoundTag) {\n                    CompoundTag itemTag = (CompoundTag) tag;\n                    int slot = itemTag.getInt(\"Slot\").orElse(0);\n                    itemTag.setInt(\"DataVersion\", dataVersion);\n                    ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemTag);\n                    CompoundTag newItemTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack);\n                    newItemTag.setInt(\"Slot\", slot);\n                    newItemsTag.addTag(newItemTag);\n                }\n            }\n\n            if (newItemsTag.size() > 0)\n                compoundTag.setTag(\"Items\", newItemsTag);\n        }\n\n        return compoundTag;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.options;\n\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\nimport com.bgsoftware.superiorskyblock.core.SBlockOffset;\n\npublic class SchematicOptionsBuilderImpl implements SchematicOptions.Builder {\n\n    private final String schematicName;\n    private BlockOffset blockOffset = SBlockOffset.ZERO;\n    private float yaw = 0f;\n    private float pitch = 0f;\n    private boolean saveAir = false;\n\n    public SchematicOptionsBuilderImpl(String schematicName) {\n        this.schematicName = schematicName;\n    }\n\n    @Override\n    public SchematicOptionsBuilderImpl setOffset(int offsetX, int offsetY, int offsetZ) {\n        this.blockOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ);\n        return this;\n    }\n\n    @Override\n    public SchematicOptionsBuilderImpl setDirection(float yaw, float pitch) {\n        this.yaw = yaw;\n        this.pitch = pitch;\n        return this;\n    }\n\n    @Override\n    public SchematicOptionsBuilderImpl setSaveAir(boolean saveAir) {\n        this.saveAir = saveAir;\n        return this;\n    }\n\n    @Override\n    public SchematicOptions build() {\n        return new SchematicOptionsImpl(this.schematicName, this.blockOffset, this.yaw, this.pitch, this.saveAir);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.options;\n\nimport com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions;\nimport com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset;\n\npublic class SchematicOptionsImpl implements SchematicOptions {\n\n    private final String schematicName;\n    private final BlockOffset blockOffset;\n    private final float yaw;\n    private final float pitch;\n    private final boolean saveAir;\n\n    public SchematicOptionsImpl(String schematicName, BlockOffset blockOffset, float yaw, float pitch, boolean saveAir) {\n        this.schematicName = schematicName;\n        this.blockOffset = blockOffset;\n        this.yaw = yaw;\n        this.pitch = pitch;\n        this.saveAir = saveAir;\n    }\n\n    @Override\n    public String getSchematicName() {\n        return this.schematicName;\n    }\n\n    @Override\n    public int getOffsetX() {\n        return this.blockOffset.getOffsetX();\n    }\n\n    @Override\n    public int getOffsetY() {\n        return this.blockOffset.getOffsetY();\n    }\n\n    @Override\n    public int getOffsetZ() {\n        return this.blockOffset.getOffsetZ();\n    }\n\n    @Override\n    public float getYaw() {\n        return this.yaw;\n    }\n\n    @Override\n    public float getPitch() {\n        return this.pitch;\n    }\n\n    @Override\n    public boolean shouldSaveAir() {\n        return this.saveAir;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java",
    "content": "package com.bgsoftware.superiorskyblock.world.schematic.parser;\n\nimport com.bgsoftware.superiorskyblock.api.schematic.Schematic;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException;\nimport com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser;\nimport com.bgsoftware.superiorskyblock.core.ServerVersion;\nimport com.bgsoftware.superiorskyblock.core.io.IOUtils;\nimport com.bgsoftware.superiorskyblock.core.logging.Log;\nimport com.bgsoftware.superiorskyblock.tag.CompoundTag;\nimport com.bgsoftware.superiorskyblock.tag.Tag;\nimport com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic;\nimport com.google.common.hash.Hashing;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class DefaultSchematicParser implements SchematicParser {\n\n    private static final DefaultSchematicParser INSTANCE = new DefaultSchematicParser();\n\n    private static final Map<String, SuperiorSchematic> HASHED_SCHEMATIC = new ConcurrentHashMap<>();\n\n    public static DefaultSchematicParser getInstance() {\n        return INSTANCE;\n    }\n\n    private DefaultSchematicParser() {\n\n    }\n\n    @Override\n    public Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException {\n        try {\n            byte[] schematicData = IOUtils.toByteArray(inputStream);\n            String hashedData = Hashing.sha256().hashBytes(schematicData).toString();\n            SuperiorSchematic hashedSchematic = HASHED_SCHEMATIC.get(hashedData);\n            if (hashedSchematic != null)\n                return hashedSchematic.copy(schematicName);\n\n            DataInputStream schematicStream = new DataInputStream(new ByteArrayInputStream(schematicData));\n            CompoundTag compoundTag = (CompoundTag) Tag.fromStream(schematicStream, 0);\n\n            if (ServerVersion.isLegacy() && compoundTag.containsKey(\"version\") &&\n                    !ServerVersion.getBukkitVersion().equals(compoundTag.getString(\"version\")))\n                Log.warn(\"Schematic \", schematicName, \" was created in a different version, may cause issues.\");\n\n            if (!compoundTag.isEmpty()) {\n                SuperiorSchematic schematic = new SuperiorSchematic(schematicName, compoundTag);\n                HASHED_SCHEMATIC.put(hashedData, schematic);\n                return schematic;\n            }\n        } catch (IOException ignored) {\n            ignored.printStackTrace();\n        }\n\n        throw new SchematicParseException(\"This schematic is not valid.\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/resources/block-values/levels.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Here you can set all the level values for your blocks.\n# To set specific spawner types, use 'MOB_SPAWNER:<ENTITY>': <AMOUNT>\n# If no level is found, the formula from config will be used.\n\nEXAMPLE: 5"
  },
  {
    "path": "src/main/resources/block-values/worth.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Here you can set all the block values for your blocks.\n# To set specific spawner types, use 'MOB_SPAWNER:<ENTITY>': <AMOUNT>\n\nACACIA_DOOR: 1\nACACIA_STAIRS: 1\nACACIA_FENCE: 1\nACACIA_FENCE_GATE: 1\nACTIVATOR_RAIL: 10\nANVIL: 10\nARMOR_STAND: 2\nBANNER: 2\nBEACON: 100\nBED_BLOCK: 1\nBEETROOT_BLOCK: 1\nBIRCH_DOOR: 1\nBIRCH_FENCE: 1\nBIRCH_FENCE_GATE: 1\nBIRCH_WOOD_STAIRS: 1\nBLACK_GLAZED_TERRACOTTA: 1\nBLACK_SHULKER_BOX: 1\nBLUE_GLAZED_TERRACOTTA: 1\nBLUE_SHULKER_BOX: 1\nBOAT: 2\nBOAT_ACACIA: 2\nBOAT_BIRCH: 2\nBOAT_DARK_OAK: 2\nBOAT_JUNGLE: 2\nBOAT_SPRUCE: 2\nBONE_BLOCK: 1\nBOOKSHELF: 5\nBREWING_STAND: 20\nBRICK: 5\nBRICK_STAIRS: 5\nBROWN_GLAZED_TERRACOTTA: 1\nBROWN_SHULKER_BOX: 1\nBURNING_FURNACE: 10\nCACTUS: 1\nCAKE_BLOCK: 1\nCARPET: 1\nCAULDRON: 10\nCHEST: 2\nCHORUS_FLOWER: 1\nCHORUS_PLANT: 1\nCLAY: 2\nCOAL_BLOCK: 9\nCOBBLE_WALL: 1\nCOBBLESTONE: 1\nCOBBLESTONE_STAIRS: 1\nCOCOA: 1\nCONCRETE: 1\nCONCRETE_POWDER: 1\nCYAN_GLAZED_TERRACOTTA: 1\nCYAN_SHULKER_BOX: 1\nDARK_OAK_DOOR: 1\nDARK_OAK_FENCE: 1\nDARK_OAK_FENCE_GATE: 1\nDARK_OAK_STAIRS: 1\nDAYLIGHT_DETECTOR: 10\nDAYLIGHT_DETECTOR_INVERTED: 10\nDEAD_BUSH: 1\nDETECTOR_RAIL: 10\nDIAMOND_BLOCK: 300\nDIODE: 5\nDIODE_BLOCK_OFF: 5\nDIODE_BLOCK_ON: 5\nDIRT: 2\nDISPENSER: 5\nDOUBLE_PLANT: 2\nDOUBLE_STEP: 1\nDOUBLE_STONE_SLAB2: 1\nDRAGON_EGG: 150\nDROPPER: 5\nEMERALD_BLOCK: 150\nENCHANTMENT_TABLE: 150\nEND_BRICKS: 2\nENDER_CHEST: 150\nENDER_STONE: 2\nEXPLOSIVE_MINECART: 10\nFENCE: 1\nFENCE_GATE: 1\nFLOWER_POT: 5\nFROSTED_ICE: 1\nFURNACE: 10\nGLASS: 2\nGLOWSTONE: 1\nGOLD_BLOCK: 150\nGRASS: 5\nGRASS_PATH: 5\nGRAY_GLAZED_TERRACOTTA: 1\nGRAY_SHULKER_BOX: 1\nGRAVEL: 1\nGREEN_GLAZED_TERRACOTTA: 1\nGREEN_SHULKER_BOX: 1\nHARD_CLAY: 2\nHAY_BLOCK: 2\nHOPPER: 10\nHOPPER_MINECART: 20\nHUGE_MUSHROOM_1: 1\nHUGE_MUSHROOM_2: 1\nICE: 5\nIRON_BLOCK: 10\nIRON_DOOR_BLOCK: 5\nIRON_FENCE: 5\nIRON_PLATE: 5\nIRON_TRAPDOOR: 1\nITEM_FRAME: 2\nJACK_O_LANTERN: 1\nJUKEBOX: 10\nJUNGLE_DOOR: 1\nJUNGLE_FENCE: 1\nJUNGLE_FENCE_GATE: 1\nJUNGLE_WOOD_STAIRS: 1\nLADDER: 1\nLAPIS_BLOCK: 10\nLEAVES_2: 1\nLEAVES: 1\nLEVER: 1\nLIGHT_BLUE_GLAZED_TERRACOTTA: 1\nLIGHT_BLUE_SHULKER_BOX: 1\nLIME_GLAZED_TERRACOTTA: 1\nLIME_SHULKER_BOX: 1\nLOG: 1\nLOG_2: 1\nLONG_GRASS: 1\nMAGENTA_GLAZED_TERRACOTTA: 1\nMAGENTA_SHULKER_BOX: 1\nMAGMA: 1\nMELON_BLOCK: 1\nMELON_STEM: 1\nMINECART: 10\n'MOB_SPAWNER:IRON_GOLEM': 10000\nMOSSY_COBBLESTONE: 2\nMYCEL: 5\nNETHER_BRICK: 2\nNETHER_BRICK_STAIRS: 2\nNETHER_FENCE: 2\nNETHER_STALK: 1\nNETHER_WART_BLOCK: 2\nNETHERRACK: 1\nNOTE_BLOCK: 10\nOBSERVER: 1\nOBSIDIAN: 10\nORANGE_GLAZED_TERRACOTTA: 1\nORANGE_SHULKER_BOX: 1\nPACKED_ICE: 5\nPAINTING: 2\nPINK_GLAZED_TERRACOTTA: 1\nPINK_SHULKER_BOX: 1\nPISTON_BASE: 2\nPISTON_STICKY_BASE: 2\nPOWERED_MINECART: 10\nPOWERED_RAIL: 10\nPRISMARINE: 10\nPUMPKIN_STEM: 1\nPUMPKIN: 1\nPURPLE_GLAZED_TERRACOTTA: 1\nPURPLE_SHULKER_BOX: 1\nPURPUR_BLOCK: 1\nPURPUR_DOUBLE_SLAB: 1\nPURPUR_PILLAR: 1\nPURPUR_SLAB: 1\nPURPUR_STAIRS: 1\nQUARTZ_BLOCK: 1\nQUARTZ_STAIRS: 1\nQUARTZ: 1\nRAILS: 1\nRED_GLAZED_TERRACOTTA: 1\nRED_MUSHROOM: 1\nRED_NETHER_BRICK: 2\nRED_ROSE: 1\nRED_SANDSTONE: 1\nRED_SANDSTONE_STAIRS: 1\nRED_SHULKER_BOX: 1\nREDSTONE_BLOCK: 10\nREDSTONE_COMPARATOR_OFF: 10\nREDSTONE_COMPARATOR_ON: 10\nREDSTONE_COMPARATOR: 10\nREDSTONE_LAMP_OFF: 10\nREDSTONE_LAMP_ON: 10\nREDSTONE_TORCH_OFF: 5\nREDSTONE_TORCH_ON: 5\nREDSTONE_WIRE: 1\nSAND: 1\nSANDSTONE: 1\nSANDSTONE_STAIRS: 1\nSEA_LANTERN: 1\nSIGN_POST: 1\nSILVER_GLAZED_TERRACOTTA: 1\nSILVER_SHULKER_BOX: 1\nSKULL: 10\nSLIME_BLOCK: 10\nSMOOTH_BRICK: 2\nSMOOTH_STAIRS: 2\nSNOW_BLOCK: 1\nSOIL: 2\nSOUL_SAND: 2\nSPONGE: 10\nSPRUCE_DOOR: 1\nSPRUCE_FENCE: 1\nSPRUCE_FENCE_GATE: 1\nSPRUCE_WOOD_STAIRS: 1\nSTAINED_CLAY: 2\nSTAINED_GLASS: 2\nSTAINED_GLASS_PANE: 1\nSTEP: 1\nSTONE: 1\nSTONE_BUTTON: 1\nSTONE_PLATE: 2\nSTORAGE_MINECART: 10\nSUGAR_CANE_BLOCK: 1\nTHIN_GLASS: 1\nTNT: 5\nTORCH: 2\nTRAP_DOOR: 5\nTRAPPED_CHEST: 10\nTRIPWIRE_HOOK: 2\nTRIPWIRE: 2\nVINE: 1\nWALL_SIGN: 1\nWATER_LILY: 5\nWEB: 10\nWHEAT: 1\nWHITE_GLAZED_TERRACOTTA: 1\nWHITE_SHULKER_BOX: 1\nWOOD: 1\nWOOD_BUTTON: 1\nWOOD_DOOR: 1\nWOOD_DOUBLE_STEP: 1\nWOOD_PLATE: 1\nWOOD_STAIRS: 1\nWOOD_STEP: 1\nWOODEN_DOOR: 1\nWOOL: 1\nWORKBENCH: 1\nYELLOW_FLOWER: 1\nYELLOW_GLAZED_TERRACOTTA: 1\nYELLOW_SHULKER_BOX: 1"
  },
  {
    "path": "src/main/resources/config.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Here you can set the amount of time between auto calculations of all islands.\n# If you want to disable this feature, set interval to 0\n# It's recommended to set the task to have a low interval, as it might cause lag.\ncalc-interval: 0\n\n# All settings related to the database of the plugin.\ndatabase:\n  # For local database, use \"SQLite\".\n  # For remote database, use \"MySQL\" or \"MariaDB\" (Depends on your setup).\n  type: SQLite\n  # Whether the datastore folder should be back-up on startup.\n  backup: true\n  # Remote database information\n  address: 'localhost'\n  port: 3306\n  db-name: 'SuperiorSkyblock'\n  user-name: 'root'\n  password: 'root'\n  prefix: ''\n  useSSL: false\n  allowPublicKeyRetrieval: true\n  waitTimeout: 600000\n  maxLifetime: 1800000\n\n# Set the main command of the plugin.\n# You can add aliases by adding \",\" after the command name, and split them using \",\".\n# You must have a full restart in order to apply changes for the command.\nisland-command: 'island,is,islands'\n\n# Set the maximum island size. Island distances is 3 times bigger than the max size.\n# Please, do not change it while you have a running islands world!\nmax-island-size: 200\n\n# All the default values for new islands that are created.\n# Please note: Upgrades with built-in values (upgrades that don't run commands to update values),\n# will override all the values here. For example, if I set an upgrade that changes generator rates,\n# there's no need to touch the default generator rates here, as new islands will get the rates from\n# the upgrade, and not from here.\ndefault-values:\n  # The default island size of all islands.\n  island-size: 20\n\n  # Set the default block limits of all islands.\n  # The following example will set a limit of 8 hoppers in islands:\n  #   block-limits:\n  #     HOPPER: 8\n  # You can find a list of materials here: https://bg-software.com/materials/\n  block-limits:\n    HOPPER: 8\n\n  # Set the default entity limits of all islands.\n  # The following example will set a limit of 4 Minecarts in islands:\n  #   entity-limits:\n  #     MINECART: 4\n  # You can find a list of entities here: https://bg-software.com/entities/\n  entity-limits:\n    MINECART: 4\n\n  # Set the default warps limit of all islands.\n  warps-limit: 3\n\n  # Set the default team limit of all islands.\n  team-limit: 4\n\n  # Set the default coop limit of all islands.\n  coop-limit: 8\n\n  # Set the default crop-growth multiplier of all islands.\n  crop-growth: 1\n\n  # Set the default spawner-rates multiplier of all islands.\n  spawner-rates: 1\n\n  # Set the default mob-drops multiplier of all islands.\n  mob-drops: 1\n\n  # Set the default bank limit of all islands.\n  bank-limit: -1\n\n  # Set the default generator percentages of all islands.\n  # The following example will set 0.5% chance for diamond block in the normal world, and 50% for gold block in nether:\n  #   generator:\n  #     normal:\n  #       DIAMOND_BLOCK: 1\n  #       STONE: 199\n  #     nether:\n  #       GOLD_BLOCK: 1\n  #       NETHERRACK: 1\n  # You can find a list of materials here: https://bg-software.com/materials/\n  generator:\n    normal:\n      COBBLESTONE: 95\n      COAL_ORE: 5\n\n  # Set the default role limits of all islands.\n  # The following example will set the limit of the role with the id 1 (Moderator by default) to 5:\n  #   role-limits:\n  #     '1': 5\n  role-limits: { }\n\n  # Set the of default island effects for all islands.\n  # The following example will set the effect level of Speed to 3:\n  #   island-effects:\n  #     SPEED: 4\n  # You can find the list of valid potion effects here:\n  # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html\n  island-effects: { }\n\n# Set the islands height generation for islands.\nislands-height: 100\n\n# Feature that adds per player world border in islands.\n# If you want to globally disable it, set this section to false.\n# World borders can be toggled by using the /is toggle border command.\nworld-borders: true\n\n# All settings related to stacked blocks.\nstacked-blocks:\n  # If you want to globally disable stacked blocks, set this section to false.\n  # Placement of stacked blocks can be toggled by using the /is toggle blocks command.\n  enabled: true\n\n  # Custom name for the blocks.\n  custom-name: '&ex{0} {1}'\n\n  # A list of worlds that blocks cannot stack in.\n  disabled-worlds: [ ]\n\n  # A list of whitelisted blocks that will get stacked when players have stack mode toggled on.\n  whitelisted:\n    - 'DIAMOND_BLOCK'\n\n  # Set limits to stacked blocks.\n  limits:\n    EXAMPLE_BLOCK: 5\n\n  # Should blocks get added directly into the player's inventory?\n  auto-collect: false\n\n  # Settings related to the deposit menu.\n  deposit-menu:\n    # Should the menu be opened when shift-clicking stacked blocks?\n    enabled: true\n    # The title of the menu.\n    title: '&lDeposit Blocks'\n\n# The formula used to calculate a block's level when it has a worth defined but no level specified.\n# Use {} as a placeholder for worth. Make sure you only use digits and mathematical operations!\nblock-level-formula: '{} / 2'\n\n# Should the island levels be a rounded integer?\nrounded-island-level: false\n\n# How should the island level be rounded when rounded-island-level feature is enabled?\n# Use UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN or HALF_EVEN\n# You can see more information about it here:\n# https://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html\nisland-level-rounding-mode: 'HALF_UP'\n\n# Whether to automatic track block counts when players place and break blocks.\n# If set to true, block counts, worth and levels will automatically be updated upon\n# placement and breaking of blocks.\nauto-blocks-tracking: true\n\n# How should the island top be ordered by default?\n# Use WORTH, LEVEL, RATING or PLAYERS.\nisland-top-order: 'WORTH'\n\n# How should the global warps be ordered by default?\n# Use WORTH, LEVEL, RATING or PLAYERS.\nglobal-warps-order: 'WORTH'\n\n# Whether coop members should be enabled or not.\ncoop-members: true\n\n# Should players be able to edit island privileges for other players?\n# When set to false, island privileges could be edited only to island roles.\nedit-player-permissions: true\n\n# All settings related to island roles.\n# You can find a list of permissions here: https://wiki.bg-software.com/superiorskyblock/island-permissions\nisland-roles:\n  # This role is given to players that are not part of your island.\n  guest:\n    # A custom name for the role.\n    name: 'Guest'\n    # A list of default permissions for guests.\n    permissions: [ ]\n\n  # This role is given to players that are co-op.\n  coop:\n    name: 'Coop'\n    permissions:\n      - ALLAY_INTERACT\n      - ANIMAL_BREED\n      - ANIMAL_DAMAGE\n      - ANIMAL_SHEAR\n      - BREAK\n      - BRUSH\n      - BUILD\n      - CLOSE_BYPASS\n      - CHORUS_FRUIT\n      - COPPER_GOLEM_INTERACT\n      - CROPS_GROWTH\n      - DROP_ITEMS\n      - DYE_SHEEP\n      - ENDER_PEARL\n      - ENTITY_RIDE\n      - EXPEL_BYPASS\n      - FARM_TRAMPING\n      - FERTILIZE\n      - FISH\n      - HORSE_INTERACT\n      - INTERACT\n      - ITEM_FRAME\n      - LEASH\n      - MINECART_DAMAGE\n      - MINECART_ENTER\n      - MINECART_OPEN\n      - MINECART_PLACE\n      - MONSTER_DAMAGE\n      - NAME_ENTITY\n      - PAINTING\n      - PICKUP_AXOLOTL\n      - PICKUP_DROPS\n      - PICKUP_FISH\n      - PICKUP_LECTERN_BOOK\n      - SADDLE_ENTITY\n      - SIGN_INTERACT\n      - SCULK_SENSOR\n      - TURTLE_EGG_TRAMPING\n      - USE\n      - VILLAGER_TRADING\n      - WIND_CHARGE\n\n  # The roles ladder for island members.\n  # All the island member roles go here.\n  #  - You can add as many roles as you'd like.\n  #  - The default role for new members has a weight of 0.\n  #  - Every role has all the permissions of the role before it.\n  #  - Every role should have a custom id, to determine the role if the name is changed.\n  #    Do not change ids!!! They don't have to be in an order.\n  ladder:\n    member:\n      id: 0\n      name: 'Member'\n      weight: 0\n      permissions:\n        - ANIMAL_SPAWN\n        - CHEST_ACCESS\n        - DEPOSIT_MONEY\n        - FLY\n        - ISLAND_CHEST\n        - MONSTER_SPAWN\n        - RANKUP\n        - SPAWNER_BREAK\n        - TAMED_ANIMAL_DAMAGE\n    mod:\n      id: 1\n      name: 'Moderator'\n      weight: 1\n      permissions:\n        - BAN_MEMBER\n        - CLOSE_ISLAND\n        - DELETE_WARP\n        - EXPEL_PLAYERS\n        - INVITE_MEMBER\n        - KICK_MEMBER\n        - OPEN_ISLAND\n        - RATINGS_SHOW\n        - SET_WARP\n        - VALUABLE_BREAK\n        - WITHDRAW_MONEY\n    admin:\n      id: 2\n      name: 'Admin'\n      weight: 2\n      permissions:\n        - COOP_MEMBER\n        - DEMOTE_MEMBERS\n        - DISCORD_SHOW\n        - PAYPAL_SHOW\n        - PROMOTE_MEMBERS\n        - SET_BIOME\n        - SET_DISCORD\n        - SET_HOME\n        - SET_PAYPAL\n        - SET_PERMISSION\n        - SET_ROLE\n        - SET_SETTINGS\n        - UNCOOP_MEMBER\n    leader:\n      id: 3\n      name: 'Leader'\n      weight: 3\n      permissions:\n        - ALL\n\n# Set the line to create the warp sign.\nsign-warp-line: '[IslandWarp]'\n\n# Set the lines of the island warp.\nsign-warp:\n  - '&a[Island Warp]'\n  - ''\n  - ''\n  - ''\n\n# All settings related to the visitors sign.\nvisitors-sign:\n  # Whether a visitors sign is required for others to visit islands.\n  # If set to false, visitors will be teleported to the regular island home when using `/is visit`\n  required-for-visit: true\n  # Set the line to create the visitors sign.\n  line: '[Welcome]'\n  # The line that will be displayed when the sign is active.\n  active: '&a[Welcome]'\n  # The line that will be displayed when the sign is inactive.\n  inactive: '&c[Welcome]'\n  # The format in which the island description lines will be saved, players can set the island description\n  # by entering it in the next lines of the Visitors Sign. Useful if you want to display a description\n  # in the global-warps menu and want to give it a default color. {0} represents the text on that line.\n  description-line-format: '{0}'\n\n# Settings related to the island worlds.\nworlds:\n  # The default world that will be used.\n  # Use one of the dimensions from below.\n  # The dimension must be enabled or the server won't start.\n  default-world: normal\n  # Set the name of the islands world.\n  world-name: SuperiorWorld\n  # The difficulty of the island worlds.\n  difficulty: EASY\n  # Set the sea level height for island worlds.\n  sea-level-height: 100\n  # Settings related to the dimensions of the plugin.\n  # You can create custom dimensions by adding them here.\n  dimensions:\n    # Settings related to the normal world.\n    normal:\n      # Should the normal world be enabled?\n      enabled: true\n      # Should the normal be unlocked by default to islands?\n      unlock: true\n      # Should the schematics in this world will not be counted towards worth and level values?\n      schematic-offset: true\n      # The environment of this world\n      environment: NORMAL\n      # The default biome for the world.\n      # If the biome is invalid, PLAINS will be set.\n      biome: PLAINS\n      # Configure the portal agents\n      portals:\n        NETHER: nether\n        ENDER: the_end\n    # Settings related to the nether world.\n    nether:\n      # Should the nether world be enabled?\n      enabled: false\n      # Should the nether be unlocked by default to islands?\n      unlock: true\n      # Custom name for the nether world.\n      # When empty, the name will be \"<island-world>_nether\"\n      name: ''\n      # Should the schematics in this world will not be counted towards worth and level values?\n      schematic-offset: true\n      # The environment of this world\n      environment: NETHER\n      # The default biome for the world.\n      # If the biome is invalid, NETHER (or it's 1.16 equivalent) will be used.\n      biome: NETHER_WASTES\n      # Configure the portal agents\n      portals:\n        NETHER: normal\n        ENDER: the_end\n    the_end:\n      # Should the end world be enabled?\n      enabled: false\n      # Should the end be unlocked by default to islands?\n      unlock: false\n      # Custom name for the end world.\n      # When empty, the name will be \"<island-world>_the_end\"\n      name: ''\n      # Should the schematics in this world will not be counted towards worth and level values?\n      schematic-offset: true\n      # The environment of this world\n      environment: THE_END\n      # The default biome for the world.\n      # If the biome is invalid, THE_END will be used.\n      biome: THE_END\n      # Configure the portal agents\n      portals:\n        NETHER: nether\n        ENDER: normal\n      # Settings related to dragon fights on the server.\n      dragon-fight:\n        # Whether dragon fights should be enabled.\n        # If enabled, each island will have it's own ender dragon to battle with.\n        enabled: false\n        # The offset of the end portal (where it should be spawning) from the middle of the island.\n        # The format is '<offset-x>, <offset-y>, <offset-z>' (may be negative).\n        # Having the offset going beyond the island-radius is an undefined behavior!\n        portal-offset: '0, 0, 0'\n\n# All settings related to the spawn island.\nspawn:\n  # The location of the island. Players will be teleported to this\n  # location in many events, such as disbanding islands & getting expelled from one.\n  location: SuperiorWorld, 0, 100, 0, 0, 0\n\n  # Should the spawn be protected?\n  # When set to false, settings and permissions will not be applied to the spawn region.\n  # In that case, it is your own responsibility to protect the spawn region.\n  protection: true\n\n  # A list of settings that will be enabled for the spawn.\n  settings:\n    - CROPS_GROWTH\n    - LAVA_FLOW\n    - NATURAL_ANIMALS_SPAWN\n    - SPAWNER_ANIMALS_SPAWN\n    - TREE_GROWTH\n    - WATER_FLOW\n\n  # A list of permissions for the spawn island.\n  permissions: [ ]\n\n  # Should a world border be displayed in the spawn?\n  world-border: false\n\n  # Set the radius of the spawn island.\n  # This can exceed the max island size, but be aware that it doesn't overlap other islands.\n  size: 200\n\n  # Should players get damage in the spawn?\n  players-damage: false\n\n# A list of permissions players will have in the islands world, outside of islands.\n# By adding permissions to this list, players will be able to grief the world, but not\n# other islands, so use this in caution.\nworld-permissions: [ ]\n\n# When enabled, players will get teleported upon void fall.\n# If they fall not in an island, they will be teleported to spawn.\nvoid-teleport:\n  members: true\n  visitors: true\n\n# When disabled, visitors won't get damaged in other islands.\nvisitors-damage: false\n\n# When disabled, coop won't get damaged in islands they are coop with.\ncoop-damage: true\n\n# Should the list of members in island top also include the island leader?\nisland-top-include-leader: true\n\n# Set default placeholders that will be returned if the island is null.\n# Please use the <placeholder>:<default> format.\n# You can find a list of placeholders here: https://bg-software.com/superiorskyblock/#placeholders\ndefault-placeholders:\n  - 'superior_island_leader:N/A'\n  - 'superior_island_level:0'\n  - 'superior_island_worth:0'\n\n# Should a confirm gui be displayed when /is ban is executed.\nban-confirm: true\n\n# Should a confirm gui be displayed when /is disband is executed.\ndisband-confirm: true\n\n# Should a confirm gui be displayed when /is kick is executed.\nkick-confirm: true\n\n# Should a confirm gui be displayed when /is leave is executed.\nleave-confirm: true\n\n# Should a confirm gui be displayed when /is transfer is executed.\ntransfer-confirm: true\n\n# If you want a specific spawners provider to use, specify it here.\n# Providers: Auto, WildStacker, EpicSpawners, MergedSpawner, PvpingSpawners, SilkSpawners, RoseStacker\nspawners-provider: 'AUTO'\n\n# If you want a specific stacked-blocks provider to use, specify it here.\n# Providers: Auto, WildStacker, RoseStacker\nstacked-blocks-provider: 'AUTO'\n\n# All settings related to island names.\nisland-names:\n  # Should creation of islands will ask for name (/is create <name>)?\n  required-for-creation: true\n\n  # The maximum length for names.\n  max-length: 16\n\n  # The minimum length for names.\n  min-length: 3\n\n  # A list of names that will be blacklisted.\n  filtered-names:\n    - fuck\n    - duck\n    - hypixel\n\n  # Should names have color support enabled?\n  color-support: true\n\n  # Should names be displayed on island-top?\n  island-top: true\n\n  # Should the plugin prevent players from using player names as island names?\n  prevent-player-names: false\n\n  # Should the name change announcement be sent to all players?\n  # When disabled, only island members will see the announcement.\n  announce-change-to-all: true\n\n# Should players get teleported to the island when they create it?\nteleport-on-create: true\n\n# Should players get teleported to the island when they accept an invite?\nteleport-on-join: false\n\n# Should players get teleported to spawn when they are kicked from their island?\nteleport-on-kick: true\n\n# Should players get teleported to spawn when they leave an island?\nteleport-on-leave: false\n\n# List of clear actions to perform on island members when their island is disbanded.\n# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY\n# You can disable this feature by setting the section to 'clear-on-disband: []'\nclear-on-disband:\n  - ENDER_CHEST\n  - INVENTORY\n\n# List of clear actions to perform on players when they accept an invite.\n# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY\n# You can disable this feature by setting the section to 'clear-on-join: []'\nclear-on-join: [ ]\n\n# List of clear actions to perform on players when they are kicked from their island.\n# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY\n# You can disable this feature by setting the section to 'clear-on-kick: []'\nclear-on-kick: [ ]\n\n# List of clear actions to perform on players when they leave an island.\n# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY\n# You can disable this feature by setting the section to 'clear-on-leave: []'\nclear-on-leave: [ ]\n\n# Should players be able to rate their own islands?\nrate-own-island: false\n\n# Should players be able to change island rating?\nchange-island-rating: true\n\n# A list of default settings for new islands.\n# You can find a list of settings here: https://wiki.bg-software.com/superiorskyblock/island-settings\ndefault-settings:\n  - 'CREEPER_EXPLOSION'\n  - 'NATURAL_ANIMALS_SPAWN'\n  - 'NATURAL_MONSTER_SPAWN'\n  - 'SPAWNER_ANIMALS_SPAWN'\n  - 'SPAWNER_MONSTER_SPAWN'\n  - 'WATER_FLOW'\n  - 'LAVA_FLOW'\n  - 'CROPS_GROWTH'\n  - 'TREE_GROWTH'\n  - 'FIRE_SPREAD'\n  - 'EGG_LAY'\n\n# Should redstone be disabled on islands that none of the members are online?\n# This should increase performance on the server.\ndisable-redstone-offline: true\n\n# Settings related to afk integrations.\n# Supported AFK plugins: Essentials, CMI\nafk-integrations:\n  # Should redstone be disabled when all the players inside the island are AFK?\n  disable-redstone: false\n  # Should mob spawning be disabled when all the players inside the island are AFK?\n  disable-spawning: false\n\n# A list of commands that should have cooldown.\n# Cooldowns are in milliseconds.\n# You can disable this section by using:\n# commands-cooldown:\n#   random:\n#     cooldown: 0\ncommands-cooldown:\n  recalc:\n    cooldown: 30000\n    bypass-permission: superior.cooldown.bypass.recalc\n\n# Set a cooldown for upgrading island values.\n# Cooldowns are in milliseconds.\n# You can disable this cooldown by setting it to -1.\nupgrade-cooldown: -1\n\n# Set the number formatting to be used.\n# You can see a list of formats under the \"Language Tag\" column here:\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\nnumber-format: \"en-US\"\n\n# Set the date formatting to be used.\n# You can see more information about it here:\n# https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html\ndate-format: \"dd/MM/yyyy HH:mm:ss\"\n\n# Should players skip menus with only one items inside them?\n# When enabled, creation, island-warps, island-chest and missions menus will be skipped if only one item is inside them.\nskip-one-item-menus: false\n\n# Should visitors get teleported to spawn when pvp is enabled in an island?\nteleport-on-pvp-enable: true\n\n# Should visitors get immuned to pvp for 10 seconds when they teleport to an island that has the settings enabled?\n# This doesn't apply to the spawn island!\nimmune-to-pvp-when-teleport: true\n\n# A list of commands that cannot be executed by visitors.\nblocked-visitors-commands: [ ]\n\n# Set items for containers inside island schematics.\ndefault-containers:\n  # Should this setting be enabled?\n  enabled: false\n  containers:\n    # The type of the container.\n    chest:\n      # The contents of the container.\n      '0':\n        type: ICE\n        amount: 2\n      '1':\n        type: MELON\n      '2':\n        type: TORCH\n        amount: 2\n      '3':\n        type: BONE\n      '4':\n        type: LAVA_BUCKET\n      '5':\n        type: PUMPKIN_SEEDS\n      '6':\n        type: SUGAR_CANE\n      '7':\n        type: RED_MUSHROOM\n      '8':\n        type: BROWN_MUSHROOM\n      '9':\n        type: CACTUS\n      '10':\n        type: BREAD\n      '11':\n        type: WHEAT\n      '12':\n        type: LEATHER_BOOTS\n      '13':\n        type: LEATHER_LEGGINGS\n      '14':\n        type: LEATHER_CHESTPLATE\n      '15':\n        type: LEATHER_HELMET\n\n# Set lines for signs inside island schematics.\n# You can use the following placeholders:\n# {player} - The island-owner's name\n# {island} - The island's name if exists. if not, the owner's name will be pasted.\n# You can disable this feature by setting the section to 'default-signs: []'\ndefault-signs: [ ]\n\n# A list of commands that will be executed when an event is called.\n# You can find a list of events at @ https://bg-software.com/superiorskyblock/api/\n# A list of placeholders (Not all of them work for all the events):\n# %island% %player% %schematic% %enter-cause% %target% %leave-cause% %old-owner% %new-owner% %worth% %level%\nevent-commands:\n  IslandCreateEvent: [ ]\n\n# A delay before getting teleported to a warp (in milliseconds).\n# Players cannot move in that time, or the teleportation will be cancelled.\nwarps-warmup: 0\n\n# A delay before getting teleported to your island (in milliseconds).\n# Players cannot move in that time, or the teleportation will be cancelled.\nhome-warmup: 0\n\n# A delay before getting teleported to another island (in milliseconds).\n# Players cannot move in that time, or the teleportation will be cancelled.\nvisit-warmup: 0\n\n# Should liquids get updated when pasting schematics?\nliquid-update: false\n\n# Should lights get updated when pasting schematics?\n# Enabling this can drop performance a bit.\nlights-update: true\n\n# A list of worlds that PvP will be enabled between island members.\npvp-worlds:\n  - 'PvP'\n\n# Stop players from leaving their island by walking through the border.\nstop-leaving: false\n\n# Should the values menu be enabled?\nvalues-menu: true\n\n# A list of crops that will be affected by the crop growth multiplier.\n# You can find a list of materials here: https://bg-software.com/materials/\ncrops-to-grow:\n  - 'SAPLING'\n  - 'OAK_SAPLING'\n  - 'SPRUCE_SAPLING'\n  - 'BIRCH_SAPLING'\n  - 'JUNGLE_SAPLING'\n  - 'ACACIA_SAPLING'\n  - 'DARK_OAK_SAPLING'\n  - 'MANGROVE_PROPAGULE'\n  - 'CHERRY_SAPLING'\n  - 'PALE_OAK_SAPLING'\n  - 'BROWN_MUSHROOM'\n  - 'RED_MUSHROOM'\n  - 'BAMBOO'\n  - 'BAMBOO_SAPLING'\n  - 'SUGAR_CANE_BLOCK'\n  - 'SUGAR_CANE'\n  - 'CACTUS'\n  - 'WEEPING_VINES'\n  - 'TWISTING_VINES'\n  - 'VINE'\n  - 'CHORUS_FLOWER'\n  - 'WHEAT'\n  - 'COCOA'\n  - 'PUMPKIN_STEM'\n  - 'ATTACHED_PUMPKIN_STEM'\n  - 'MELON_STEM'\n  - 'ATTACHED_MELON_STEM'\n  - 'BEETROOTS'\n  - 'TORCHFLOWER_CROP'\n  - 'PITCHER_CROP'\n  - 'CAVE_VINES'\n  - 'SWEET_BERRY_BUSH'\n  - 'NETHER_WART'\n  - 'NETHER_WARTS'\n  - 'KELP'\n  - 'CARROT'\n  - 'CARROTS'\n  - 'POTATO'\n  - 'POTATOES'\n  - 'CROPS'\n\n# How frequency should the crops task run? (in ticks)\n# You can disable this feature by setting it to 0.\n# Warning: When disabled, crops-growth multiplier will not function!\ncrops-interval: 5\n\n# Should only the back button work for closing menus?\nonly-back-button: false\n\n# Should players be able to build outside their islands?\n# All islands will have the size of the max-island-size * 1.5, which means islands will be connected to each other.\n# It's recommended to have a low max island size when this feature is enabled!\nbuild-outside-island: false\n\n# The default number of times new players can disband their island.\n# If you want to disable this feature, set it to -1.\ndefault-disband-count: 5\n\n# The default language to be used.\n# This should be the same as your language file's name.\ndefault-language: 'en-US'\n\n# Should world borders be enabled by default for new players?\ndefault-world-border: true\n\n# Should blocks stacking be enabled by default for players?\n# The blocks stacking will reset every restart for all players to this value.\ndefault-blocks-stacker: true\n\n# Should panels be toggled by default for new players?\ndefault-toggled-panel: false\n\n# Should fly mode be enabled by default for new players?\ndefault-island-fly: false\n\n# What the default color for world borders be?\n# Can be BLUE, GREEN or RED.\ndefault-border-color: BLUE\n\n# Should obsidian get turned into a lava bucket when clicking it with a bucket in hand?\nobsidian-to-lava: false\n\n# Should the worth values be synced with other prices providers?\n# You can set the following values: NONE (disabled), BUY (buy prices), SELL (sell prices)\n# Supported Providers: ShopGUIPlus\nsync-worth: NONE\n\n# Can the worth value of the island be negative?\nnegative-worth: true\n\n# Can the level of the island be negative?\nnegative-level: true\n\n# A list of events that will not be fired. This can increase performance.\n# You can find a list of events at @ https://bg-software.com/superiorskyblock/api/\ndisabled-events: [ ]\n\n# A list of commands that should be disabled within the plugin.\n# You can add a label or an alias of a command to disable it.\ndisabled-commands: [ ]\n\n# List of plugins that their hooks should not be enabled.\n# Simply add the plugin's name in order to prevent it from enabling.\ndisabled-hooks: [ ]\n\n# Should there be a schematic-name argument in the create command?\n# When enabled, people will be able to skip the create menu and create islands directly with the command.\nschematic-name-argument: true\n\n# Settings related to the island chest.\nisland-chests:\n  # The chest title.\n  chest-title: '&4Island Chest'\n  # Default amount of pages.\n  # You can set this value to 0 to not have any pages by default.\n  default-pages: 0\n  # Default size for the pages.\n  # This is the default number of rows for the chests.\n  # This number must be between 1 and 6.\n  default-size: 3\n\n# Custom aliases for plugin's commands.\ncommand-aliases:\n  example-command:\n    - 'Aliase1'\n    - 'Aliase2'\n\n# A list of valuable blocks.\n# These blocks require the \"VALUABLE_BREAK\" permission in order to break them.\nvaluable-blocks: [ ]\n\n# Settings related to the island previews.\nisland-previews:\n  # The game mode that will be set for the player when they enter preview mode.\n  # Use ADVENTURE, CREATIVE, SPECTATOR or SURVIVAL.\n  game-mode: SPECTATOR\n\n  # The maximum distance a player can move before the preview mode is canceled.\n  max-distance: 100\n\n  # A list of commands that cannot be executed by players in preview mode.\n  blocked-commands: [ ]\n\n  # Preview locations for schematics.\n  # You can disable this feature by setting the section to 'locations: []'\n  # Make sure you follow the location format: '<world>, <x>, <y>, <z>, <pitch>, <yaw>'\n  locations:\n    normal: world, 0, 100, 0\n    mycel: world, 0, 100, 0\n    desert: world, 0, 100, 0\n\n# Should vanished players be hidden in tab completes?\ntab-complete-hide-vanished: true\n\n# When enabled, the drops multiplier will only multiply drops of entities that were killed by players.\ndrops-upgrade-players-multiply: false\n\n# List of messages that should have a delay. (in milliseconds)\nmessage-delays:\n  BUILD_OUTSIDE_ISLAND: 3000\n  ISLAND_BEING_CALCULATED: 3000\n  ISLAND_PROTECTED: 3000\n  ISLAND_PROTECTED_OPPED: 3000\n  SCHEMATIC_NOT_ADDED: 3000\n  SPAWN_PROTECTED: 3000\n  SPAWN_PROTECTED_OPPED: 3000\n  WORLD_NOT_ENABLED: 3000\n  WORLD_NOT_UNLOCKED: 3000\n\n# Should players be able to create warp categories?\nwarp-categories: true\n\n# Should the physics listener be activated?\n# This must be enabled if one of the stacked blocks can be affected by gravity or other things.\n# Disabling this listener can help with performance.\nphysics-listener: true\n\n# Should players be charged when using island warps?\n# You can set an amount of money to charge, 0 to disable the feature.\ncharge-on-warp: 0\n\n# Should island warps be public by default?\npublic-warps: false\n\n# Should islands be locked by default?\nlocked-islands: false\n\n# Timeout for the recalculate task, in seconds.\n# If you want to disable the timeout, set this to 0 or below.\nrecalc-task-timeout: 10\n\n# Detect the player's language automatically when he first joins the server.\n# The language will only get changed if there is a valid translation available,\n# otherwise the default language will be chosen for the player.\nauto-language-detection: true\n\n# Automatically uncoop players when there are no island members left online that can remove uncoop players.\nauto-uncoop-when-alone: false\n\n# The way members of islands will be sorted in top islands when using the {4} placeholder.\n# The followings are available:\n# NAMES - Sort members by their names.\n# ROLES - Sort members by their island roles.\nisland-top-members-sorting: NAMES\n\n# Limit of the amount of bossbar tasks each player can have at the same time.\n# Once the limit is reached, the old ones will get removed.\nbossbar-limit: 1\n\n# Delete unsafe warps when players try to teleport to them automatically.\n# If disabled, warps that are unsafe will stay until players manually delete them.\ndelete-unsafe-warps: true\n\n# List of actions to perform when a player respawns.\n# The plugin will try to perform the actions in the order they are entered here, from top to bottom,\n# until one action succeeds. Custom respawn actions can be registered using the API.\n# The default available actions:\n# BED_TELEPORT - Teleport the player to his bed spawn, if exists.\n# ISLAND_TELEPORT - Teleport the player to his own island, if exists.\n# SPAWN_TELEPORT - Teleport the player to spawn when he spawns.\n# VANILLA - Respawn the player in his vanilla spawn point (bed location or world spawn point).\nplayer-respawn:\n  - ISLAND_TELEPORT\n  - SPAWN_TELEPORT\n\n# The amount of blocks that are required to be updated on the island before updating the block counts in the database.\n# This means that if the threshold is at 100, it will require 100 blocks to be added/removed before updating the\n# database with the new block counts. If the server stops and there was a change to the block counts, the block counts\n# will be saved to the database despite the threshold.\nblock-counts-save-threshold: 100\n\n# Support for chat-signing in 1.19 or above.\n# When set to true, the plugin will properly handle messages to not interface\n# with the signing of chat messages. However, this may cause issues with other\n# plugins that do not properly handle signed messages, and in this case it\n# might be better to disable it.\nchat-signing-support: true\n\n# Amount of commands to be listed in the `/is help` and `/is admin` commands.\n# Setting this to 0 or below will result all commands to be shown in a single page.\ncommands-per-page: 7\n\n# Should players receive a help instead of an `INVALID_COMMAND` message\n# when using a command that doesn't exist?\nhelp-on-invalid-command: true\n\n# Should players receive a help instead of a `NO_COMMAND_PERMISSION` message\n# when using a command they don't have permission for?\nhelp-on-no-permission: false"
  },
  {
    "path": "src/main/resources/entity-categories.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Configure the categories of entities of the plugin.\n# The format of the file is as so:\n# <CATEGORY_NAME>:\n#   entities:\n#     - <ENTITIES...>\n#   actions:\n#     # The privilege required to spawn the entities using spawn eggs\n#     SPAWN: <ISLAND_PRIVILEGE>\n#     # The privilege required to damage the entities\n#     DAMAGE: <ISLAND_PRIVILEGE>\n#     # The privilege required to interact with the entities\n#     INTERACT: <ISLAND_PRIVILEGE>\n#     # The island flag required so the entities can spawn from spawners\n#     SPAWNER_SPAWN: <ISLAND_FLAG>\n#     # The island flag required so the entities can spawn vanilla\n#     NATURAL_SPAWN: <ISLAND_FLAG>\n# You can create as many custom categories as you want.\n# There are custom groups used for detecting animals, monsters and tameable entities.\n# These groups do not have `entities` and the entities are added automatically depending on your Minecraft version.\n\n# Custom interact groups\nALLAY:\n  entities:\n    - ALLAY\n  actions:\n    INTERACT: ALLAY_INTERACT\n\nAXOLOTL:\n  entities:\n    - AXOLOTL\n  actions:\n    INTERACT: PICKUP_AXOLOTL\n\nCOPPER_GOLEM:\n  entities:\n    - COPPER_GOLEM\n  actions:\n    INTERACT: COPPER_GOLEM_INTERACT\n\nFISH:\n  entities:\n    - COD\n    - PUFFERFISH\n    - SALMON\n    - TADPOLE\n    - TROPICAL_FISH\n  actions:\n    INTERACT: PICKUP_FISH\n\nHORSES:\n  entities:\n    - CAMEL\n    - CAMEL_HUSK\n    - DONKEY\n    - HORSE\n    - LLAMA\n    - MULE\n    - SKELETON_HORSE\n    - TRADER_LLAMA\n    - ZOMBIE_HORSE\n  actions:\n    INTERACT: HORSE_INTERACT\n\nNAUTILUS:\n  entities:\n    - NAUTILUS\n    - ZOMBIE_NAUTILUS\n  actions:\n    INTERACT: NAUTILUS_INTERACT\n\nVILLAGERS:\n  entities:\n    - VILLAGER\n  actions:\n    INTERACT: VILLAGER_TRADING\n\n# Custom entities with custom functionalities\nARMOR_STAND:\n  entities:\n    - ARMOR_STAND\n  actions:\n    SPAWN: BUILD\n    DAMAGE: BREAK\n    INTERACT: BUILD\n\nITEM_FRAME:\n  entities:\n    - GLOW_ITEM_FRAME\n    - ITEM_FRAME\n  actions:\n    SPAWN: ITEM_FRAME\n    DAMAGE: ITEM_FRAME\n    INTERACT: ITEM_FRAME\n\nPAINTING:\n  entities:\n    - PAINTING\n  actions:\n    SPAWN: PAINTING\n    DAMAGE: PAINTING\n    INTERACT: PAINTING\n\n# Custom built-in groups\nTAMEABLE:\n  actions:\n    DAMAGE: TAMED_ANIMAL_DAMAGE\n\nVEHICLE:\n  actions:\n    SPAWN: MINECART_PLACE\n    DAMAGE: MINECART_DAMAGE\n\nANIMAL:\n  actions:\n    SPAWN: ANIMAL_SPAWN\n    DAMAGE: ANIMAL_DAMAGE\n    SPAWNER_SPAWN: SPAWNER_ANIMALS_SPAWN\n    NATURAL_SPAWN: NATURAL_ANIMALS_SPAWN\n\nMONSTER:\n  actions:\n    SPAWN: MONSTER_SPAWN\n    DAMAGE: MONSTER_DAMAGE\n    SPAWNER_SPAWN: SPAWNER_MONSTER_SPAWN\n    NATURAL_SPAWN: NATURAL_MONSTER_SPAWN\n"
  },
  {
    "path": "src/main/resources/heads.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# A list of skull textures for spawners.\n# You can find the texture values on https://minecraft-heads.com/\n\nALLAY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmVlYTg0NWNjMGI1OGZmNzYzZGVjZmZlMTFjZDFjODQ1YzVkMDljM2IwNGZlODBiMDY2M2RhNWM3YzY5OWViMyJ9fX0='\nARMADILLO: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTE2NGVkMGUwZWY2OWIwY2U3ODE1ZTQzMDBiNDQxM2E0ODI4ZmNiMDA5MjkxODU0MzU0NWE0MThhNDhlMGMzYyJ9fX0='\nAXOLOTL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg3Mjg2MGRhNGQ0NWNlNDNkMWI5ZDAyMzQ0NDJjMDNhOTE3NjVkOThhM2JiMTVmNzMzZTNjZWE1MmFmNWYxOCJ9fX0='\nBAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmZmZDgwOGY4MTI3YjRhZDQ1OGQ5ZDJlMTgxYzY5MGFkZjQ4OWE2YWQzMmVlMmFhNGFjZmE2MzQxZmU4NDIifX19'\nBEE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTg3NDc4N2UzNjE1OWU0ZDc0ZGI1ZTI1YmFiYTk4N2I2NjVkY2M4OTBiZTlmMjYyYmIwY2JjZjVkMDFiODJiNiJ9fX0='\nBLAZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=='\nBOGGED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTNiOTAwM2JhMmQwNTU2MmM3NTExOWI4YTYyMTg1YzY3MTMwZTkyODJmN2FjYmFjNGJjMjgyNGMyMWViOTVkOSJ9fX0='\nBREEZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTI3NTcyOGFmN2U2YTI5Yzg4MTI1YjY3NWEzOWQ4OGFlOTkxOWJiNjFmZGMyMDAzMzdmZWQ2YWIwYzQ5ZDY1YyJ9fX0='\nCAMEL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2ViNmFkOTA4YjhkNTE1NWJjNGQyNDkyNzFlZjYwODRkNDU1ZGQwZTcwYTQwMDJlYjE0OGY5ZTIwYjlkZWIyYyJ9fX0='\nCAMEL_HUSK: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzUwYmZjOWIyY2M0MGY0ZDhkMDIyNGNjYmFiYWMyNmIzMzhhYTk0N2Q5OWRjZGU3NjlmODU5YjU5YjhkMGIwZSJ9fX0='\nCAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmYxODA2NDE3YzE2Y2NkYzMzOWQ0NGQzMjgyNTFhOGQxYmJlYWI5NDVmODdhODViNDhlNGIxMTRmZGVmYiJ9fX0='\nCAVE_SPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19'\nCHICKEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzODQ2OWE1OTljZWVmNzIwNzUzNzYwMzI0OGE5YWIxMWZmNTkxZmQzNzhiZWE0NzM1YjM0NmE3ZmFlODkzIn19fQ=='\nCOD: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg5MmQ3ZGQ2YWFkZjM1Zjg2ZGEyN2ZiNjNkYTRlZGRhMjExZGY5NmQyODI5ZjY5MTQ2MmE0ZmIxY2FiMCJ9fX0='\nCOPPER_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTllMjRlOTRkYmU0MmUyMzBkODMyOTNhNzdkNjFmZjcxMDFhOGM2OGFiNjhiYmM2YTkzZjk2MzBmYjJmZGI0In19fQ=='\nCOW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19'\nCREAKING: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzdiNWJlNzI3NjljY2ZmMWE2Y2I3N2M1ODQ4ZTAxZDdlNTcwNGEzZDM0OWMwNzM3ZmY5M2NiNTRkMDIzODBhYyJ9fX0='\nCREEPER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0='\nDOLPHIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU5Njg4Yjk1MGQ4ODBiNTViN2FhMmNmY2Q3NmU1YTBmYTk0YWFjNmQxNmY3OGU4MzNmNzQ0M2VhMjlmZWQzIn19fQ=='\nDONKEY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNmMzYzA1MmNmNzg3ZDIzNmEyOTE1ZjgwNzJiNzdjNTQ3NDk3NzE1ZDFkMmY4Y2JjOWQyNDFkODhhIn19fQ=='\nDROWNED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzNmN2NjZjYxZGJjM2Y5ZmU5YTYzMzNjZGUwYzBlMTQzOTllYjJlZWE3MWQzNGNmMjIzYjNhY2UyMjA1MSJ9fX0='\nELDER_GUARDIAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkyMDg5NjE4NDM1YTBlZjYzZTk1ZWU5NWE5MmI4MzA3M2Y4YzMzZmE3N2RjNTM2NTE5OWJhZDMzYjYyNTYifX19'\nENDER_DRAGON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjY4YzFjMDc5YTdmZmIzNmY0OGRkNzE1MDM1NWUzZTBiN2Y2OGRkNjA1ZTZmODg0NzMxM2MzNjBjZjYxZTBjIn19fQ=='\nENDERMAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2E1OWJiMGE3YTMyOTY1YjNkOTBkOGVhZmE4OTlkMTgzNWY0MjQ1MDllYWRkNGU2YjcwOWFkYTUwYjljZiJ9fX0='\nENDERMITE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0='\nEVOKER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDk1NDEzNWRjODIyMTM5NzhkYjQ3ODc3OGFlMTIxMzU5MWI5M2QyMjhkMzZkZDU0ZjFlYTFkYTQ4ZTdjYmE2In19fQ=='\nFOX: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmJkZmZlOTY0MmZjNTI4MGU2OGNlNDg4ZTNiY2Y0NDA2ODdlZDNiYzU2NmUzMTVhZjgyNGY0MjhiNmZmNzE1In19fQ=='\nFROG: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjdiY2NjYzEyNWE0MTEwNDM0YTg1YzQwYWRhMDM5ZDA1MGYxNGVmN2RiMzRhMzQ0NDA2NzMxMGY4Y2U2OTYwNiJ9fX0='\nGHAST: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19'\nGIANT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ=='\nGLOW_SQUID: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTVlMmI0NmU1MmFjOTJkNDE5YTJkZGJjYzljZGNlN2I0NTFjYjQ4YWU3MzlkODVkNjA3ZGIwNTAyYTAwOGNlMCJ9fX0='\nGOAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDU3YTBkNTM4ZmEwOGE3YWZmZTMxMjkwMzQ2ODg2MTcyMGY5ZmEzNGU4NmQ0NGI4OWRjZWM1NjM5MjY1ZjAzIn19fQ=='\nGUARDIAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ=='\nHAPPY_GHAST: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTFhMzZjYjkzZDAxNjc1YzQ2MjJkZDVjOGQ4NzIxMTA5MTFlYzEyYzM3MmU4OWFmYThiYTAzODYyODY3ZjZmYiJ9fX0='\nHOGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWJiOWJjMGYwMWRiZDc2MmEwOGQ5ZTc3YzA4MDY5ZWQ3Yzk1MzY0YWEzMGNhMTA3MjIwODU2MWI3MzBlOGQ3NSJ9fX0='\nHORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjE5MDI4OTgzMDg3MzBjNDc0NzI5OWNiNWE1ZGE5YzI1ODM4YjFkMDU5ZmU0NmZjMzY4OTZmZWU2NjI3MjkifX19'\nHUSK: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDY3NGM2M2M4ZGI1ZjRjYTYyOGQ2OWEzYjFmOGEzNmUyOWQ4ZmQ3NzVlMWE2YmRiNmNhYmI0YmU0ZGIxMjEifX19'\nILLUSIONER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWM2NzhjOWY0YzZkZDRkOTkxOTMwZjgyZTZlN2Q4Yjg5YjI4OTFmMzVjYmE0OGE0YjE4NTM5YmJlN2VjOTI3In19fQ=='\nIRON_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19'\nLLAMA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2YyNGU1NmZkOWZmZDcxMzNkYTZkMWYzZTJmNDU1OTUyYjFkYTQ2MjY4NmY3NTNjNTk3ZWU4MjI5OWEifX19'\nMAGMA_CUBE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0='\nMOOSHROOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ=='\nMULE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTA0ODZhNzQyZTdkZGEwYmFlNjFjZTJmNTVmYTEzNTI3ZjFjM2IzMzRjNTdjMDM0YmI0Y2YxMzJmYjVmNWYifX19'\nMUSHROOM_COW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ=='\nNAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjUzZDYzZWIxNzViMDBmYjM1Mjg1ZjQzMzBkMGJlNjhhMDcxM2RiOTRlMDBlNmZkZDg1ODMyZDQxZTNhMDhiIn19fQ=='\nOCELOT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTY1N2NkNWMyOTg5ZmY5NzU3MGZlYzRkZGNkYzY5MjZhNjhhMzM5MzI1MGMxYmUxZjBiMTE0YTFkYjEifX19'\nPANDA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGYwMDg1ODkyNmNkOGNkZjNmMWNmNzFlMjEwY2RlNWRhZjg3MDgzMjA1NDdiZDZkZjU3OTU4NTljNjhkOWIzZiJ9fX0='\nPARCHED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjRhZWNlZmY1ZjI2ZGQ4NDEzYzVjMDM1NDdjMjM0YWMwMzEwOGQxODdhZjBiOWNkODM0YThjZTEyNTk4NTkxYyJ9fX0='\nPARROT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTRiYThkNjZmZWNiMTk5MmU5NGI4Njg3ZDZhYjRhNTMyMGFiNzU5NGFjMTk0YTI2MTVlZDRkZjgxOGVkYmMzIn19fQ=='\nPHANTOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQ2ODMwZGE1ZjgzYTNhYWVkODM4YTk5MTU2YWQ3ODFhNzg5Y2ZjZjEzZTI1YmVlZjdmNTRhODZlNGZhNCJ9fX0='\nPIG: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjIxNjY4ZWY3Y2I3OWRkOWMyMmNlM2QxZjNmNGNiNmUyNTU5ODkzYjZkZjRhNDY5NTE0ZTY2N2MxNmFhNCJ9fX0='\nPIGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTFkMThiYmQwZDc5NWI5YWM4ZWZhYWQ2NTVlM2QwYzU5ZmNiYjliOTY0YzJhOTk0OGVmNTM3ZjRhM2ZiYmY4NyJ9fX0='\nPIGLIN_BRUTE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2UzMDBlOTAyNzM0OWM0OTA3NDk3NDM4YmFjMjllM2E0Yzg3YTg0OGM1MGIzNGMyMTI0MjcyN2I1N2Y0ZTFjZiJ9fX0='\nPIG_ZOMBIE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ=='\nPILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGFlZTZiYjM3Y2JmYzkyYjBkODZkYjVhZGE0NzkwYzY0ZmY0NDY4ZDY4Yjg0OTQyZmRlMDQ0MDVlOGVmNTMzMyJ9fX0='\nPOLAR_BEAR: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDQ2ZDIzZjA0ODQ2MzY5ZmEyYTM3MDJjMTBmNzU5MTAxYWY3YmZlODQxOTk2NjQyOTUzM2NkODFhMTFkMmIifX19'\nPUFFERFISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzNiMTk1NWQzYjZlYjQyZjUwZTUzNmMxYTMyODVhYjczZWQ3ZTJiZTA1MWIwOWIyMWUxNzgxMWYxYTZkIn19fQ=='\nRABBIT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmYxNTU5MTk0YTE3NTkzNWI4YjRmZWE2NjE0YmVjNjBiZjgxY2Y1MjRhZjZmNTY0MzMzYzU1NWU2NTdiYyJ9fX0='\nRAVAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2QyMGJmNTJlYzM5MGEwNzk5Mjk5MTg0ZmM2NzhiZjg0Y2Y3MzJiYjFiZDc4ZmQxYzRiNDQxODU4ZjAyMzVhOCJ9fX0='\nSALMON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmYzU3ZDA5MDU5ZTQ3OTlmYTkyYzE1ZTI4NTEyYmNmYWExMzE1NTc3ZmUzYTI3YWVkMzg5ZTRmNzUyMjg5YSJ9fX0='\nSHEEP: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjMxZjljY2M2YjNlMzJlY2YxM2I4YTExYWMyOWNkMzNkMThjOTVmYzczZGI4YTY2YzVkNjU3Y2NiOGJlNzAifX19'\nSHULKER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTM3YTI5NGY2YjdiNGJhNDM3ZTVjYjM1ZmIyMGY0Njc5MmU3YWMwYTQ5MGE2NjEzMmE1NTcxMjRlYzVmOTk3YSJ9fX0='\nSILVERFISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGE5MWRhYjgzOTFhZjVmZGE1NGFjZDJjMGIxOGZiZDgxOWI4NjVlMWE4ZjFkNjIzODEzZmE3NjFlOTI0NTQwIn19fQ=='\nSKELETON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ=='\nSKELETON_HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDdlZmZjZTM1MTMyYzg2ZmY3MmJjYWU3N2RmYmIxZDIyNTg3ZTk0ZGYzY2JjMjU3MGVkMTdjZjg5NzNhIn19fQ=='\nSLIME: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ=='\nSNIFFER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTViNjMxYjZhNDk5MDkxMGUwOTVmOGIzMThlYmQxMjE0MzI2YTRmMGY1OGQxYjQ4ZDQyZjk5NmMxZWNiYzk5NCJ9fX0='\nSNOW_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZkZmQxZjc1MzhjMDQwMjU4YmU3YTkxNDQ2ZGE4OWVkODQ1Y2M1ZWY3MjhlYjVlNjkwNTQzMzc4ZmNmNCJ9fX0='\nSNOWMAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZkZmQxZjc1MzhjMDQwMjU4YmU3YTkxNDQ2ZGE4OWVkODQ1Y2M1ZWY3MjhlYjVlNjkwNTQzMzc4ZmNmNCJ9fX0='\nSPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=='\nSQUID: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ=='\nSTRAY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmM1MDk3OTE2YmMwNTY1ZDMwNjAxYzBlZWJmZWIyODcyNzdhMzRlODY3YjRlYTQzYzYzODE5ZDUzZTg5ZWRlNyJ9fX0='\nSTRIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMThhOWFkZjc4MGVjN2RkNDYyNWM5YzA3NzkwNTJlNmExNWE0NTE4NjY2MjM1MTFlNGM4MmU5NjU1NzE0YjNjMSJ9fX0='\nTADPOLE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTg3MDM1ZjUzNTIzMzRjMmNiYTZhYzRjNjVjMmI5MDU5NzM5ZDZkMGU4MzljMWRkOThkNzVkMmU3Nzk1Nzg0NyJ9fX0='\nTRADER_LLAMA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQyNDc4MGIzYzVjNTM1MWNmNDlmYjViZjQxZmNiMjg5NDkxZGY2YzQzMDY4M2M4NGQ3ODQ2MTg4ZGI0Zjg0ZCJ9fX0='\nTROPICAL_FISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZkZDVlNmFkZGI1NmFjYmM2OTRlYTRiYTU5MjNiMWIyNTY4ODE3OGZlZmZhNzIyOTAyOTllMjUwNWM5NzI4MSJ9fX0='\nTURTLE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMGE0MDUwZTdhYWNjNDUzOTIwMjY1OGZkYzMzOWRkMTgyZDdlMzIyZjlmYmNjNGQ1Zjk5YjU3MThhIn19fQ=='\nVEX: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzJlYzVhNTE2NjE3ZmYxNTczY2QyZjlkNWYzOTY5ZjU2ZDU1NzVjNGZmNGVmZWZhYmQyYTE4ZGM3YWI5OGNkIn19fQ=='\nVILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODIyZDhlNzUxYzhmMmZkNGM4OTQyYzQ0YmRiMmY1Y2E0ZDhhZThlNTc1ZWQzZWIzNGMxOGE4NmU5M2IifX19'\nVINDICATOR: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmRlYWVjMzQ0YWIwOTViNDhjZWFkNzUyN2Y3ZGVlNjFiMDYzZmY3OTFmNzZhOGZhNzY2NDJjODY3NmUyMTczIn19fQ=='\nWANDERING_TRADER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzc5YTgyMjkwZDdhYmUxZWZhYWJiYzcwNzEwZmYyZWMwMmRkMzRhZGUzODZiYzAwYzkzMGM0NjFjZjkzMiJ9fX0='\nWARDEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmNmMzY3NGIyZGRjMGVmN2MzOWUzYjljNmI1ODY3N2RlNWNmMzc3ZDJlYjA3M2YyZjNmZTUwOTE5YjFjYTRjOSJ9fX0='\nWITCH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGRlZGJlZTQyYmU0NzJlM2ViNzkxZTdkYmRmYWYxOGM4ZmU1OTNjNjM4YmExMzk2YzllZjY4ZjU1NWNiY2UifX19'\nWITHER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2RmNzRlMzIzZWQ0MTQzNjk2NWY1YzU3ZGRmMjgxNWQ1MzMyZmU5OTllNjhmYmI5ZDZjZjVjOGJkNDEzOWYifX19'\nWITHER_SKELETON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk1M2I2YzY4NDQ4ZTdlNmI2YmY4ZmIyNzNkNzIwM2FjZDhlMWJlMTllODE0ODFlYWQ1MWY0NWRlNTlhOCJ9fX0='\nWOLF: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjlkMWQzMTEzZWM0M2FjMjk2MWRkNTlmMjgxNzVmYjQ3MTg4NzNjNmM0NDhkZmNhODcyMjMxN2Q2NyJ9fX0='\nZOGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTY3ZTE4NjAyZTAzMDM1YWQ2ODk2N2NlMDkwMjM1ZDg5OTY2NjNmYjllYTQ3NTc4ZDNhN2ViYmM0MmE1Y2NmOSJ9fX0='\nZOMBIE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ=='\nZOMBIE_HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTcxY2U0NjljYmE0NDI2YzgxMWY2OWJlNWQ5NThhMDliZmI5YjFiMmJiNjQ5ZDM1NzdhMGMyMTYxYWQyZjUyNCJ9fX0='\nZOMBIE_NAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmQ5YTkzMzM3NmRhNDRjMzM5MTMwN2NiOWY0Y2YwM2YxNmYzYTU0ZjQ5NWZkNWExMWJhZDhhMzczZjlkNTcyMCJ9fX0='\nZOMBIE_VILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTYyMjQ5NDEzMTRiY2EyZWJiYjY2YjEwZmZkOTQ2ODBjYzk4YzM0MzVlZWI3MWEyMjhhMDhmZDQyYzI0ZGIifX19'\nZOMBIFIED_PIGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1NGQwZDFjMjg2YzFiMzRmYjA5MTg0MWMwNmFlZDc0MWExYmY5YjY1YjlhNDMwZTRlNWNhMWQxYzRiOWY2ZiJ9fX0='"
  },
  {
    "path": "src/main/resources/interactables.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# A list of interactable blocks.\n# Only interactable blocks & stacked blocks will be blocked from being interacted.\n# The format of the file is as so:\n# <PRIVILEGE>:\n#   - BLOCK_TYPE\n#   - ...\n# You can create as many custom privileges as you want.\n\ninteractables:\n  - 'ACACIA_BUTTON'\n  - 'ACACIA_DOOR'\n  - 'ACACIA_FENCE'\n  - 'ACACIA_FENCE_GATE'\n  - 'ACACIA_HANGING_SIGN'\n  - 'ACACIA_PRESSURE_PLATE'\n  - 'ACACIA_SHELF'\n  - 'ACACIA_SIGN'\n  - 'ACACIA_TRAPDOOR'\n  - 'ACACIA_WALL_HANGING_SIGN'\n  - 'ACACIA_WALL_SIGN'\n  - 'ANVIL'\n  - 'BAMBOO_BUTTON'\n  - 'BAMBOO_DOOR'\n  - 'BAMBOO_FENCE'\n  - 'BAMBOO_FENCE_GATE'\n  - 'BAMBOO_HANGING_SIGN'\n  - 'BAMBOO_PRESSURE_PLATE'\n  - 'BAMBOO_SHELF'\n  - 'BAMBOO_SIGN'\n  - 'BAMBOO_TRAPDOOR'\n  - 'BAMBOO_WALL_HANGING_SIGN'\n  - 'BAMBOO_WALL_SIGN'\n  - 'BARREL'\n  - 'BEACON'\n  - 'BED_BLOCK'\n  - 'BEE_NEST'\n  - 'BEEHIVE'\n  - 'BELL'\n  - 'BIRCH_BUTTON'\n  - 'BIRCH_DOOR'\n  - 'BIRCH_FENCE'\n  - 'BIRCH_FENCE_GATE'\n  - 'BIRCH_HANGING_SIGN'\n  - 'BIRCH_PRESSURE_PLATE'\n  - 'BIRCH_SHELF'\n  - 'BIRCH_SIGN'\n  - 'BIRCH_TRAPDOOR'\n  - 'BIRCH_WALL_HANGING_SIGN'\n  - 'BIRCH_WALL_SIGN'\n  - 'BLACK_BED'\n  - 'BLACK_CANDLE'\n  - 'BLACK_SHULKER_BOX'\n  - 'BLAST_FURNACE'\n  - 'BLUE_BED'\n  - 'BLUE_CANDLE'\n  - 'BLUE_SHULKER_BOX'\n  - 'BREWING_STAND'\n  - 'BROWN_BED'\n  - 'BROWN_CANDLE'\n  - 'BROWN_SHULKER_BOX'\n  - 'BURNING_FURNACE'\n  - 'CAKE'\n  - 'CAKE_BLOCK'\n  - 'CAMPFIRE'\n  - 'CANDLE'\n  - 'CARTOGRAPHY_TABLE'\n  - 'CAULDRON'\n  - 'CAVE_VINES'\n  - 'CAVE_VINES_PLANT'\n  - 'CHAIN_COMMAND_BLOCK'\n  - 'CHERRY_BUTTON'\n  - 'CHERRY_DOOR'\n  - 'CHERRY_FENCE'\n  - 'CHERRY_FENCE_GATE'\n  - 'CHERRY_HANGING_SIGN'\n  - 'CHERRY_PRESSURE_PLATE'\n  - 'CHERRY_SHELF'\n  - 'CHERRY_SIGN'\n  - 'CHERRY_TRAPDOOR'\n  - 'CHERRY_WALL_HANGING_SIGN'\n  - 'CHERRY_WALL_SIGN'\n  - 'CHEST'\n  - 'CHIPPED_ANVIL'\n  - 'CHISELED_BOOKSHELF'\n  - 'COMMAND'\n  - 'COMMAND_BLOCK'\n  - 'COMMAND_CHAIN'\n  - 'COMMAND_REPEATING'\n  - 'COMPARATOR'\n  - 'COMPOSTER'\n  - 'COPPER_CHEST'\n  - 'COPPER_DOOR'\n  - 'COPPER_GOLEM_STATUE'\n  - 'COPPER_TRAPDOOR'\n  - 'CRAFTER'\n  - 'CRAFTING_TABLE'\n  - 'CRIMSON_BUTTON'\n  - 'CRIMSON_DOOR'\n  - 'CRIMSON_FENCE'\n  - 'CRIMSON_FENCE_GATE'\n  - 'CRIMSON_HANGING_SIGN'\n  - 'CRIMSON_PRESSURE_PLATE'\n  - 'CRIMSON_SHELF'\n  - 'CRIMSON_SIGN'\n  - 'CRIMSON_TRAPDOOR'\n  - 'CRIMSON_WALL_HANGING_SIGN'\n  - 'CRIMSON_WALL_SIGN'\n  - 'CYAN_BED'\n  - 'CYAN_CANDLE'\n  - 'CYAN_SHULKER_BOX'\n  - 'DAMAGED_ANVIL'\n  - 'DARK_OAK_BUTTON'\n  - 'DARK_OAK_DOOR'\n  - 'DARK_OAK_FENCE'\n  - 'DARK_OAK_FENCE_GATE'\n  - 'DARK_OAK_HANGING_SIGN'\n  - 'DARK_OAK_PRESSURE_PLATE'\n  - 'DARK_OAK_SHELF'\n  - 'DARK_OAK_SIGN'\n  - 'DARK_OAK_TRAPDOOR'\n  - 'DARK_OAK_WALL_HANGING_SIGN'\n  - 'DARK_OAK_WALL_SIGN'\n  - 'DAYLIGHT_DETECTOR'\n  - 'DAYLIGHT_DETECTOR_INVERTED'\n  - 'DECORATED_POT'\n  - 'DISPENSER'\n  - 'DRAGON_EGG'\n  - 'DROPPER'\n  - 'ENCHANTING_TABLE'\n  - 'ENCHANTMENT_TABLE'\n  - 'END_PORTAL_FRAME'\n  - 'ENDER_CHEST'\n  - 'ENDER_PORTAL_FRAME'\n  - 'EXPOSED_COPPER_CHEST'\n  - 'EXPOSED_COPPER_DOOR'\n  - 'EXPOSED_COPPER_GOLEM_STATUE'\n  - 'EXPOSED_COPPER_TRAPDOOR'\n  - 'FARMLAND'\n  - 'FENCE'\n  - 'FENCE_GATE'\n  - 'FLOWER_POT'\n  - 'FURNACE'\n  - 'GLOWING_REDSTONE_ORE'\n  - 'GOLD_PLATE'\n  - 'GRAY_BED'\n  - 'GRAY_CANDLE'\n  - 'GRAY_SHULKER_BOX'\n  - 'GREEN_BED'\n  - 'GREEN_CANDLE'\n  - 'GREEN_SHULKER_BOX'\n  - 'GRINDSTONE'\n  - 'HEAVY_WEIGHTED_PRESSURE_PLATE'\n  - 'HOPPER'\n  - 'IRON_PLATE'\n  - 'JIGSAW'\n  - 'JUKEBOX'\n  - 'JUNGLE_BUTTON'\n  - 'JUNGLE_DOOR'\n  - 'JUNGLE_FENCE'\n  - 'JUNGLE_FENCE_GATE'\n  - 'JUNGLE_HANGING_SIGN'\n  - 'JUNGLE_PRESSURE_PLATE'\n  - 'JUNGLE_SHELF'\n  - 'JUNGLE_SIGN'\n  - 'JUNGLE_TRAPDOOR'\n  - 'JUNGLE_WALL_HANGING_SIGN'\n  - 'JUNGLE_WALL_SIGN'\n  - 'KELP'\n  - 'LECTERN'\n  - 'LEVER'\n  - 'LIGHT_BLUE_BED'\n  - 'LIGHT_BLUE_CANDLE'\n  - 'LIGHT_BLUE_SHULKER_BOX'\n  - 'LIGHT_GRAY_BED'\n  - 'LIGHT_GRAY_CANDLE'\n  - 'LIGHT_GRAY_SHULKER_BOX'\n  - 'LIGHT_WEIGHTED_PRESSURE_PLATE'\n  - 'LIME_BED'\n  - 'LIME_CANDLE'\n  - 'LIME_SHULKER_BOX'\n  - 'LODESTONE'\n  - 'LOOM'\n  - 'MAGENTA_BED'\n  - 'MAGENTA_CANDLE'\n  - 'MAGENTA_SHULKER_BOX'\n  - 'MANGROVE_BUTTON'\n  - 'MANGROVE_DOOR'\n  - 'MANGROVE_FENCE'\n  - 'MANGROVE_FENCE_GATE'\n  - 'MANGROVE_HANGING_SIGN'\n  - 'MANGROVE_PRESSURE_PLATE'\n  - 'MANGROVE_SHELF'\n  - 'MANGROVE_SIGN'\n  - 'MANGROVE_TRAPDOOR'\n  - 'MANGROVE_WALL_HANGING_SIGN'\n  - 'MANGROVE_WALL_SIGN'\n  - 'MOB_SPAWNER'\n  - 'NETHER_BRICK_FENCE'\n  - 'NETHER_FENCE'\n  - 'NOTE_BLOCK'\n  - 'OAK_BUTTON'\n  - 'OAK_DOOR'\n  - 'OAK_FENCE'\n  - 'OAK_FENCE_GATE'\n  - 'OAK_HANGING_SIGN'\n  - 'OAK_PRESSURE_PLATE'\n  - 'OAK_SHELF'\n  - 'OAK_SIGN'\n  - 'OAK_TRAPDOOR'\n  - 'OAK_WALL_HANGING_SIGN'\n  - 'OAK_WALL_SIGN'\n  - 'ORANGE_BED'\n  - 'ORANGE_CANDLE'\n  - 'ORANGE_SHULKER_BOX'\n  - 'OXIDIZED_COPPER_CHEST'\n  - 'OXIDIZED_COPPER_DOOR'\n  - 'OXIDIZED_COPPER_GOLEM_STATUE'\n  - 'OXIDIZED_COPPER_TRAPDOOR'\n  - 'PALE_OAK_BUTTON'\n  - 'PALE_OAK_DOOR'\n  - 'PALE_OAK_FENCE'\n  - 'PALE_OAK_FENCE_GATE'\n  - 'PALE_OAK_HANGING_SIGN'\n  - 'PALE_OAK_PRESSURE_PLATE'\n  - 'PALE_OAK_SHELF'\n  - 'PALE_OAK_SIGN'\n  - 'PALE_OAK_TRAPDOOR'\n  - 'PALE_OAK_WALL_HANGING_SIGN'\n  - 'PALE_OAK_WALL_SIGN'\n  - 'PINK_BED'\n  - 'PINK_CANDLE'\n  - 'PINK_SHULKER_BOX'\n  - 'POLISHED_BLACKSTONE_BUTTON'\n  - 'POLISHED_BLACKSTONE_PRESSURE_PLATE'\n  - 'POTTED_ACACIA_SAPLING'\n  - 'POTTED_ALLIUM'\n  - 'POTTED_AZALEA_BUSH'\n  - 'POTTED_AZURE_BLUET'\n  - 'POTTED_BAMBOO'\n  - 'POTTED_BIRCH_SAPLING'\n  - 'POTTED_BLUE_ORCHID'\n  - 'POTTED_BROWN_MUSHROOM'\n  - 'POTTED_CACTUS'\n  - 'POTTED_CHERRY_SAPLING'\n  - 'POTTED_CLOSED_EYEBLOSSOM'\n  - 'POTTED_CORNFLOWER'\n  - 'POTTED_CRIMSON_FUNGUS'\n  - 'POTTED_CRIMSON_ROOTS'\n  - 'POTTED_DANDELION'\n  - 'POTTED_DARK_OAK_SAPLING'\n  - 'POTTED_DEAD_BUSH'\n  - 'POTTED_FERN'\n  - 'POTTED_FLOWERING_AZALEA_BUSH'\n  - 'POTTED_JUNGLE_SAPLING'\n  - 'POTTED_LILY_OF_THE_VALLEY'\n  - 'POTTED_MANGROVE_PROPAGULE'\n  - 'POTTED_OAK_SAPLING'\n  - 'POTTED_OPEN_EYEBLOSSOM'\n  - 'POTTED_ORANGE_TULIP'\n  - 'POTTED_OXEYE_DAISY'\n  - 'POTTED_PALE_OAK_SAPLING'\n  - 'POTTED_PINK_TULIP'\n  - 'POTTED_POPPY'\n  - 'POTTED_RED_MUSHROOM'\n  - 'POTTED_RED_TULIP'\n  - 'POTTED_SPRUCE_SAPLING'\n  - 'POTTED_TORCHFLOWER'\n  - 'POTTED_WARPED_FUNGUS'\n  - 'POTTED_WARPED_ROOTS'\n  - 'POTTED_WHITE_TULIP'\n  - 'POTTED_WITHER_ROSE'\n  - 'PUMPKIN'\n  - 'PURPLE_BED'\n  - 'PURPLE_CANDLE'\n  - 'PURPLE_SHULKER_BOX'\n  - 'RED_BED'\n  - 'RED_CANDLE'\n  - 'RED_SHULKER_BOX'\n  - 'REDSTONE_COMPARATOR_OFF'\n  - 'REDSTONE_COMPARATOR_ON'\n  - 'REDSTONE_ORE'\n  - 'REPEATER'\n  - 'REPEATING_COMMAND_BLOCK'\n  - 'RESPAWN_ANCHOR'\n  - 'ROOTED_DIRT'\n  - 'SHULKER_BOX'\n  - 'SIGN_POST'\n  - 'SMITHING_TABLE'\n  - 'SMOKER'\n  - 'SOIL'\n  - 'SOUL_CAMPFIRE'\n  - 'SPAWNER'\n  - 'SPRUCE_BUTTON'\n  - 'SPRUCE_DOOR'\n  - 'SPRUCE_FENCE'\n  - 'SPRUCE_FENCE_GATE'\n  - 'SPRUCE_HANGING_SIGN'\n  - 'SPRUCE_PRESSURE_PLATE'\n  - 'SPRUCE_SHELF'\n  - 'SPRUCE_SIGN'\n  - 'SPRUCE_TRAPDOOR'\n  - 'SPRUCE_WALL_HANGING_SIGN'\n  - 'SPRUCE_WALL_SIGN'\n  - 'STONE_BUTTON'\n  - 'STONE_PRESSURE_PLATE'\n  - 'STONECUTTER'\n  - 'STRUCTURE_BLOCK'\n  - 'SWEET_BERRY_BUSH'\n  - 'TARGET'\n  - 'TEST_BLOCK'\n  - 'TEST_INSTANCE_BLOCK'\n  - 'TNT'\n  - 'TRAP_DOOR'\n  - 'TRAPPED_CHEST'\n  - 'TURTLE_EGG'\n  - 'TWISTING_VINES'\n  - 'VAULT'\n  - 'WALL_SIGN'\n  - 'WARPED_BUTTON'\n  - 'WARPED_DOOR'\n  - 'WARPED_FENCE'\n  - 'WARPED_FENCE_GATE'\n  - 'WARPED_HANGING_SIGN'\n  - 'WARPED_PRESSURE_PLATE'\n  - 'WARPED_SHELF'\n  - 'WARPED_SIGN'\n  - 'WARPED_TRAPDOOR'\n  - 'WARPED_WALL_HANGING_SIGN'\n  - 'WARPED_WALL_SIGN'\n  - 'WAXED_COPPER_CHEST'\n  - 'WAXED_COPPER_DOOR'\n  - 'WAXED_COPPER_GOLEM_STATUE'\n  - 'WAXED_COPPER_TRAPDOOR'\n  - 'WAXED_EXPOSED_COPPER_CHEST'\n  - 'WAXED_EXPOSED_COPPER_DOOR'\n  - 'WAXED_EXPOSED_COPPER_GOLEM_STATUE'\n  - 'WAXED_EXPOSED_COPPER_TRAPDOOR'\n  - 'WAXED_OXIDIZED_COPPER_CHEST'\n  - 'WAXED_OXIDIZED_COPPER_DOOR'\n  - 'WAXED_OXIDIZED_COPPER_GOLEM_STATUE'\n  - 'WAXED_OXIDIZED_COPPER_TRAPDOOR'\n  - 'WAXED_WEATHERED_COPPER_CHEST'\n  - 'WAXED_WEATHERED_COPPER_DOOR'\n  - 'WAXED_WEATHERED_COPPER_GOLEM_STATUE'\n  - 'WAXED_WEATHERED_COPPER_TRAPDOOR'\n  - 'WEATHERED_COPPER_CHEST'\n  - 'WEATHERED_COPPER_DOOR'\n  - 'WEATHERED_COPPER_GOLEM_STATUE'\n  - 'WEATHERED_COPPER_TRAPDOOR'\n  - 'WEEPING_VINES'\n  - 'WHITE_BED'\n  - 'WHITE_CANDLE'\n  - 'WHITE_SHULKER_BOX'\n  - 'WOOD_BUTTON'\n  - 'WOODEN_DOOR'\n  - 'WORKBENCH'\n  - 'YELLOW_BED'\n  - 'YELLOW_CANDLE'\n  - 'YELLOW_SHULKER_BOX'\n"
  },
  {
    "path": "src/main/resources/lang/de-DE.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lInsel | &7Der Spieler {0} wurde erfolgreich zur Insel von {1}\n  hinzugefügt.'\nADMIN_ADD_PLAYER_NAME: '&e&lInsel | &7Der Spieler {0} wurde erfolgreich zur Insel\n  {1} ​​hinzugefügt.'\nADMIN_DEPOSIT_MONEY: '&e&lBank | &7Du hast $ {0} auf die Inselbank von {1} eingezahlt. '\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7Du hast {0} Citycoins auf die Bank der Insel\n  {1} ​​eingezahlt. '\nADMIN_HELP_FOOTER: '&e&lSkyblock &7Entwickelt von einem Entwickler'\nADMIN_HELP_HEADER: '&e&lSkyblock &7Admin Befehlsliste [{0} / {1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7 {1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Verwende /is admin {0} für die nächste Seite.'\nALREADY_IN_ISLAND: '&c&lError | &7Du bist bereits auf einer Insel. '\nALREADY_IN_ISLAND_OTHER: '&c&lFehler | &7Dieser Spieler ist bereits Mitglied deiner\n  Insel.'\nBAN_ANNOUNCEMENT: '&e&lIsland | &7{0} wurde von {1} von der Insel GEBANNT.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler mit einer niedrigeren\n  Inselrolle als deiner bannen.'\nBANK_DEPOSIT_CUSTOM: '&e&lBank | &7Gebe den Betrag ein, den du einzahlen möchtest:'\nBANK_DEPOSIT_COMPLETED: Einzahlung abgeschlossen\nBANK_LIMIT_EXCEED: '&c&lError | &7Du hast dein Banklimit überschritten.'\nBANK_WITHDRAW_CUSTOM: '&e&lBank | &7Gebe den Betrag ein, den du abheben möchtest:'\nBANK_WITHDRAW_COMPLETED: Auszahlung abgeschlossen\nBANNED_FROM_ISLAND: '&c&lError | &7Du bist von dieser Insel verbannt.'\nBLOCK_COUNT_CHECK: '&e&lInsel | &7Diese Insel hat x{0} {1}.'\nBLOCK_COUNTS_CHECK: |-\n  &e&lInsel | &7Diese Insel hat die folgenden Blöcke:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lInsel | &7Diese Insel hat keine verfolgten Blöcke.'\nBLOCK_COUNTS_CHECK_MATERIAL: x{0} {1}\nBLOCK_LEVEL: '&e&lLevel | &7Die Ebene des Blocks {0} ist {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Der Block {0} ist wertlos.'\nBLOCK_VALUE: '&e&lWert | &7Der Block {0} im Wert von {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lWert | &7Der Block {0} ist wertlos.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: Blau\nBORDER_PLAYER_COLOR_NAME_RED: Rot\nBORDER_PLAYER_COLOR_NAME_GREEN: Grün\nBORDER_PLAYER_COLOR_UPDATED: '&e&lGrenze | &7Dein persönlicher Border wurde erfolgreich\n  in {0} geändert.'\nBUILD_OUTSIDE_ISLAND: '&c&lError | &7Du kannst nicht außerhalb deiner Border bauen.'\nCANNOT_SET_ROLE: '&c&lError | &7Du kannst die Rolle des Spielers nicht auf {0} setzen.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7Du kannst Berechtigungen nur auf\n  eine niedrigere Inselrolle als deine ändern.'\nCHANGED_BANK_LIMIT: '&e&lUpgrades | &7Das Banklimit der Insel von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Das Banklimit aller Inseln wurde erfolgreich\n  aktualisiert.'\nCHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Das Banklimit von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_BIOME: '&e&lIsland | &7Biom erfolgreich in {0} geändert. Möglicherweise musst\n  du dich erneut mit dem Server verbinden, um die Änderungen anzuzeigen.'\nCHANGED_BIOME_ALL: '&e&lInsel | &7Biom für alle Inseln erfolgreich auf {0} geändert.'\nCHANGED_BIOME_NAME: '&e&lInsel | &7Biom erfolgreich auf {0} für Insel {1} ​​geändert.'\nCHANGED_BIOME_OTHER: '&e&lInsel | &7Das Biom wurde erfolgreich in {0} für die Insel\n  von {1} geändert.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Der Blockbetrag bei {0} wurde erfolgreich in\n  {1} geändert.'\nCHANGED_BLOCK_LIMIT: '&e&lUpgrades | &7Das {0} Blocklimit der Insel von {1} wurde\n  erfolgreich aktualisiert.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Das {0} Blocklimit aller Inseln wurde erfolgreich\n  aktualisiert.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Das {0} Blocklimit von {1} wurde erfolgreich\n  aktualisiert.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lChest | &7Die Zeilen von Seite #{0} wurden erfolgreich auf\n  {1} für die Insel von {2} aktualisiert.'\nCHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Die Zeilen der Seite #{0} wurden für alle Inseln\n  erfolgreich auf {1} aktualisiert.'\nCHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Die Zeilen von Seite #{0} wurden erfolgreich\n  auf {1} für {2} aktualisiert.'\nCHANGED_COOP_LIMIT: '&e&lUpgrades | &7Das Koop-Spielerlimit von {0}s Insel wurde erfolgreich\n  aktualisiert.'\nCHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Das Koop-Spielerlimit aller Inseln wurde\n  erfolgreich aktualisiert.'\nCHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Das Koop-Spielerlimit von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_CROP_GROWTH: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator der\n  Insel {0} wurde erfolgreich aktualisiert.'\nCHANGED_CROP_GROWTH_ALL: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator\n  aller Inseln wurde erfolgreich aktualisiert.'\nCHANGED_CROP_GROWTH_NAME: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator\n  von {0} wurde erfolgreich aktualisiert.'\nCHANGED_DISCORD: '&e&lIsland | &7Die Inseldisharmonie wurde erfolgreich in {0} geändert.'\nCHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Das Limit von {0} Entitys für die Insel von\n  {1} wurde erfolgreich aktualisiert.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Das Limit von {0} Entitys für alle Inseln\n  wurde erfolgreich aktualisiert.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Das Limit von {0} Entitys für {1} wurde\n  erfolgreich aktualisiert.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0} für\n  die Insel von {1} wurde erfolgreich aktualisiert.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0}\n  für alle Inseln erfolgreich aktualisiert.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0}\n  für {1} wurde erfolgreich aktualisiert.'\nCHANGED_ISLAND_SIZE: '&e&lUpgrades | &7Die Inselgröße der Insel von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Die Inselgröße aller Inseln wurde erfolgreich\n  aktualisiert.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lUpgrades | &7Die Inselgröße von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oSpieler können außerhalb ihrer Insel bauen,\n  daher hat die Inselgröße keinen Einfluss. Sie können diese Funktion in der Konfiguration\n  deaktivieren, damit sich die Inselgröße wieder auswirkt.'\nCHANGED_LANGUAGE: '&e&lSprache | &7Deine Sprache wurde erfolgreich auf Deutsch geändert.'\nCHANGED_MOB_DROPS: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator von {0}´s Insel wurde\n  erfolgreich aktualisiert.'\nCHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator aller Inseln wurde\n  erfolgreich aktualisiert.'\nCHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator von {0} wurde\n  erfolgreich aktualisiert.'\nCHANGED_NAME: '&e&lInsel | &7Du hast den Namen Ihrer Insel in {0}&7 geändert.'\nCHANGED_NAME_OTHER: '&e&lInsel | &7Du hast den Namen der Insel {0} in {1}&7 geändert.'\nCHANGED_NAME_OTHER_NAME: '&e&lInsel | &7Du hast den Namen von {0}&7 in {1}&7 geändert.'\nCHANGED_PAYPAL: '&e&lIsland | &7Island paypal erfolgreich auf {0} geändert.'\nCHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Das Limit der Rolle {0} für die Insel von {1}\n  wurde erfolgreich aktualisiert.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Das Limit der Rolle {0} für alle Inseln\n  erfolgreich aktualisiert.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Das Limit der Rolle {0} für {1} wurde erfolgreich\n  aktualisiert.'\nCHANGED_SPAWNER_RATES: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator der Insel\n  {0} wurde erfolgreich aktualisiert.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator aller\n  Inseln wurde erfolgreich aktualisiert.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator von\n  {0} wurde erfolgreich aktualisiert.'\nCHANGED_TEAM_LIMIT: '&e&lUpgrades | &7Das Teamlimit der Insel von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lUpgrades | &7Das Teamlimit aller Inseln wurde erfolgreich\n  aktualisiert.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lUpgrades | &7Das Teamlimit von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_TELEPORT_LOCATION: '&e&lInsel | &7Der Teleport-Standort wurde erfolgreich\n  aktualisiert.'\nCHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Das Warps-Limit der Insel von {0} wurde erfolgreich\n  aktualisiert.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Das Warps-Limit aller Inseln wurde erfolgreich\n  aktualisiert.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Das Warps-Limit von {0} wurde erfolgreich\n  aktualisiert.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: Betrag\nCOMMAND_ARGUMENT_BIOME: biom\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: Befehl...\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: Discord...\nCOMMAND_ARGUMENT_EFFECT: Trank-Effekt\nCOMMAND_ARGUMENT_EMAIL: E-Mail\nCOMMAND_ARGUMENT_ENTITY: Entität\nCOMMAND_ARGUMENT_ISLAND_NAME: Inselname\nCOMMAND_ARGUMENT_ISLAND_ROLE: Inselrolle\nCOMMAND_ARGUMENT_LEADER: Owner\nCOMMAND_ARGUMENT_LEVEL: Stufe\nCOMMAND_ARGUMENT_LIMIT: limit\nCOMMAND_ARGUMENT_MATERIAL: Material\nCOMMAND_ARGUMENT_MENU: Menüname\nCOMMAND_ARGUMENT_MESSAGE: Nachricht...\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: mission-name\nCOMMAND_ARGUMENT_MODULE_NAME: Modulname\nCOMMAND_ARGUMENT_MULTIPLIER: Multiplikator\nCOMMAND_ARGUMENT_NAME: name\nCOMMAND_ARGUMENT_NEW_LEADER: neuer Owner\nCOMMAND_ARGUMENT_PAGE: Seite\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: Berechtigung\nCOMMAND_ARGUMENT_PLAYER_NAME: Spielername\nCOMMAND_ARGUMENT_PRIVATE: privat\nCOMMAND_ARGUMENT_RATING: Bewertung\nCOMMAND_ARGUMENT_ROWS: Zeilen\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: schema-name\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: Einstellungen\nCOMMAND_ARGUMENT_SIZE: Größe\nCOMMAND_ARGUMENT_TIME: Zeit\nCOMMAND_ARGUMENT_TITLE_DURATION: Dauer\nCOMMAND_ARGUMENT_TITLE_FADE_IN: einblenden\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: Ausblenden\nCOMMAND_ARGUMENT_UPGRADE_NAME: Upgrade-Name\nCOMMAND_ARGUMENT_VALUE: Wert\nCOMMAND_ARGUMENT_WARP_NAME: Warp-Name\nCOMMAND_ARGUMENT_WARP_CATEGORY: Warp-Kategorie\nCOMMAND_ARGUMENT_WORLD: Welt\nCOMMAND_COOLDOWN_FORMAT: '&c&lError | &7Du darfst den Befehl nur in {0} verwenden.'\nCOMMAND_DESCRIPTION_ACCEPT: Eine Einladung von einem Spieler annehmen.\nCOMMAND_DESCRIPTION_ADMIN: Verwende die Admin-Befehle.\nCOMMAND_DESCRIPTION_ADMIN_ADD: Einen Benutzer zu einer Insel hinzufügen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Blocklimit für die Insel eines anderen\n  Spielers erhöhen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Einem Spieler einen Bonus hinzufügen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Koop-Spielerlimit für die Insel eines anderen\n  Spielers erhöhen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Erhöht den Multiplikator für das Pflanzenwachstum\n  für die Insel eines anderen Spielers.\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Einen Inseleffekt für die Insel eines anderen\n  Spielers hinzufügen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Entity-Limit für die Insel eines anderen\n  Spielers erhöhen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Prozentsatz eines Materials für den Kopfsteinpflaster-Generator\n  hinzufügen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Erhöhe den Mob-Drop-Multiplikator für die\n  Insel eines anderen Spielers.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Erweitere die Inselgröße eines anderen Spielers.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Erhöht den Spawner-Raten-Multiplikator\n  für die Insel eines anderen Spielers.\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Mitgliederlimit für die Insel eines anderen\n  Spielers erhöhen.\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Erhöht das Warps-Limit einer Insel.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: Einem Spieler einen Bonus gewähren.\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: Umgehungsmodus umschalten.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: Öffne die Truhe der Insel einer anderen Insel.\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Generatortarife für eine bestimmte Insel\n  löschen.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: Schließe eine Insel für die Öffentlichkeit.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: Führe einen Befehl für alle Mitglieder der Inseln\n  aus.\nCOMMAND_DESCRIPTION_ADMIN_COUNT: Überprüfe eine Blockanzahl auf einer bestimmten Insel.\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: Debug-Ausgaben umschalten.\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: Lösche einen Warp für eine Insel.\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: Ein Mitglied auf der Insel eines anderen Spielers\n  degradieren.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: Geld auf die Inselbank eines anderen Spielers einzahlen.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: Die Insel eines anderen Spielers dauerhaft auflösen.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Gib einem Spieler Auflösungen.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: Ignoriere eine Insel von den Top-Inseln.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: Treten Sie ohne Einladung einer Insel bei.\nCOMMAND_DESCRIPTION_ADMIN_KICK: Kick einen Spieler von seiner Insel.\nCOMMAND_DESCRIPTION_ADMIN_MODULES: Module des Plugins verwalten.\nCOMMAND_DESCRIPTION_ADMIN_MISSION: Ändere den Status einer Mission für einen Spieler.\nCOMMAND_DESCRIPTION_ADMIN_MSG: Sende einem Spieler eine Nachricht ohne Präfixe.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: An alle Inselmitglieder eine Nachricht ohne Präfixe\n  senden.\nCOMMAND_DESCRIPTION_ADMIN_NAME: Ändere den Namen einer Insel.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: Öffne eine Insel für die Öffentlichkeit.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Öffne ein benutzerdefiniertes Menü für einen\n  Spieler.\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: Ein Mitglied auf der Insel eines anderen Spielers\n  befördern.\nCOMMAND_DESCRIPTION_ADMIN_PURGE: Inseln säubern.\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: Rang ein Upgrade für eine Insel auf.\nCOMMAND_DESCRIPTION_ADMIN_RECALC: Berechnet den Wert einer Insel neu.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: Alle Konfigurationen und Aufgaben des Plugins neu\n  laden.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Entferne ein Blocklimit von einer Insel.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Alle Bewertungen eines Spielers entfernen.\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück.\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Schaltpläne für das Plugin erstellen.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: Lege das Biom einer Insel fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Blockierungsbetrag an einem bestimmten\n  Ort festlegen.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Blocklimit für die Insel eines anderen\n  Spielers festlegen.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Lege die Brustreihen für die Insel eines\n  anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Lege das Limit für Koop-Spieler für die\n  Insel eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Lege den Pflanzenwachstumsmultiplikator\n  für die Insel eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Bestimme die Anzahl der Inselauflösungen eines\n  Spielers.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Lege die Inseleffektstufe der Insel eines anderen\n  Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Entity-Limit für die Insel eines anderen\n  Spielers festlegen.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: Übertrage eine Insel an jemand anderen.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Lege den Mob-Drop-Multiplikator für die Insel\n  eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Lege eine erforderliche Rolle für eine Berechtigung\n  für alle Inseln fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: Lege die Wertung eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: Rollenlimit für die Insel eines anderen\n  Spielers festlegen.\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Einstellungen für eine bestimmte Insel umschalten.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Prozentsatz eines Materials für den Kopfsteinpflaster-Generator\n  ändern.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: Die Inselgröße eines anderen Spielers ändern.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Lege den Spawn-Standort des Servers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Lege den Spawner-Raten-Multiplikator\n  für die Insel eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Mitgliederlimit für die Insel eines anderen\n  Spielers festlegen.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Lege die Stufe eines Upgrades für die Insel\n  eines anderen Spielers fest.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Lege das Warps-Limit einer Insel fest.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: Öffne den Plugin-Einstellungseditor.\nCOMMAND_DESCRIPTION_ADMIN_SHOW: Informationen über eine Insel abrufen.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Teleport zum Spawn-Ort.\nCOMMAND_DESCRIPTION_ADMIN_SPY: Chat-Spionagemodus umschalten\nCOMMAND_DESCRIPTION_ADMIN_STATS: Statistiken über das Plugin anzeigen.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Upgrade-Werte für eine Insel synchronisieren.\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: Teleport zur anderen Inseln.\nCOMMAND_DESCRIPTION_ADMIN_TITLE: Sende einem Spieler einen Titel.\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: An alle Inselmitglieder einen Titel senden.\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: Ignoriere eine Insel von den Top-Inseln.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Schalte eine Welt für eine Insel frei.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: Geld von der Inselbank eines anderen Spielers\n  abheben.\nCOMMAND_DESCRIPTION_BALANCE: Überprüfe den Geldbetrag in der Bank einer Insel.\nCOMMAND_DESCRIPTION_BAN: Banne einen Spieler von deiner Insel.\nCOMMAND_DESCRIPTION_BANK: Öffne die Bank der Insel.\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: Ändere das Biom der Insel.\nCOMMAND_DESCRIPTION_BORDER: Ändere die Randfarbe der Inseln.\nCOMMAND_DESCRIPTION_CHEST: Öffne die Truhe der Insel.\nCOMMAND_DESCRIPTION_CLOSE: Schließe die Insel für die Öffentlichkeit.\nCOMMAND_DESCRIPTION_COOP: Füge einen Spieler als Coop zu deiner Insel hinzu.\nCOMMAND_DESCRIPTION_COOPS: Öffne das Coop-Menü.\nCOMMAND_DESCRIPTION_COUNTS: Siehe Blockanzahlen auf deiner Insel.\nCOMMAND_DESCRIPTION_CREATE: Erstelle eine neue Insel.\nCOMMAND_DESCRIPTION_DEL_WARP: Einen Insel-Warp löschen.\nCOMMAND_DESCRIPTION_DEMOTE: Ein Mitglied auf deiner Insel degradieren.\nCOMMAND_DESCRIPTION_DEPOSIT: Zahle Geld von deinem persönlichen Konto auf die Bank\n  der Insel ein.\nCOMMAND_DESCRIPTION_DISBAND: Lösche deine Insel für immer.\nCOMMAND_DESCRIPTION_EXPEL: Kick einen Besucher von deiner Insel.\nCOMMAND_DESCRIPTION_FLY: Inselfliegen umschalten.\nCOMMAND_DESCRIPTION_HELP: Liste aller Befehle.\nCOMMAND_DESCRIPTION_INVITE: Lade einen Spieler auf Ihre Insel ein.\nCOMMAND_DESCRIPTION_KICK: Kick einen Spieler von deiner Insel.\nCOMMAND_DESCRIPTION_LANG: Ändere deine persönliche Sprache.\nCOMMAND_DESCRIPTION_LEAVE: Verlasse deine Insel.\nCOMMAND_DESCRIPTION_MEMBERS: Öffne das Mitgliedermenü.\nCOMMAND_DESCRIPTION_MISSION: Beende eine Mission.\nCOMMAND_DESCRIPTION_MISSIONS: Öffne das Missionsmenü.\nCOMMAND_DESCRIPTION_NAME: Ändere den Namen deiner Insel.\nCOMMAND_DESCRIPTION_OPEN: Öffne die Insel für die Öffentlichkeit.\nCOMMAND_DESCRIPTION_PANEL: Insel-Panel öffnen.\nCOMMAND_DESCRIPTION_PARDON: Bann einen Spieler von deiner Insel auf.\nCOMMAND_DESCRIPTION_PERMISSIONS: Alle Berechtigungen für eine Inselrolle erhalten.\nCOMMAND_DESCRIPTION_PROMOTE: Bewerbe ein Mitglied auf Ihrer Insel.\nCOMMAND_DESCRIPTION_RANKUP: Ein Upgrade aufleveln.\nCOMMAND_DESCRIPTION_RATE: Bewerte eine Insel.\nCOMMAND_DESCRIPTION_RATINGS: Alle Inselbewertungen anzeigen.\nCOMMAND_DESCRIPTION_SETTINGS: Öffne das Einstellungsmenü.\nCOMMAND_DESCRIPTION_RECALC: Berechnet den Inselwert neu.\nCOMMAND_DESCRIPTION_SET_DISCORD: Lege den Discord der Insel für Inselauszahlungen\n  fest.\nCOMMAND_DESCRIPTION_SET_PAYPAL: Lege die Paypal-E-Mail der Insel für Inselauszahlungen\n  fest.\nCOMMAND_DESCRIPTION_SET_ROLE: Ändere die Rolle eines Spielers auf deiner Insel.\nCOMMAND_DESCRIPTION_SET_TELEPORT: Ändere den Teleportstandort deiner Insel.\nCOMMAND_DESCRIPTION_SET_WARP: Erstelle einen neuen Insel-Warp.\nCOMMAND_DESCRIPTION_SHOW: Erhalte Informationen über eine Insel.\nCOMMAND_DESCRIPTION_TEAM: Erhalte Informationen über den Status der Inselmitglieder.\nCOMMAND_DESCRIPTION_TEAM_CHAT: Team-Chat-Modus umschalten.\nCOMMAND_DESCRIPTION_TELEPORT: Teleportiere dich zu deiner Insel.\nCOMMAND_DESCRIPTION_TOGGLE: Inselgrenzen und Platzierung von gestapelten Blöcken umschalten.\nCOMMAND_DESCRIPTION_TOP: Oberes Inselfenster öffnen.\nCOMMAND_DESCRIPTION_TRANSFER: Übertrage die Führung deiner Insel.\nCOMMAND_DESCRIPTION_UNCOOP: Entferne einen Spieler aus dem Koop auf deiner Insel.\nCOMMAND_DESCRIPTION_UPGRADE: Upgrade-Panel öffnen.\nCOMMAND_DESCRIPTION_VALUE: Erhalte den Wert eines Blocks.\nCOMMAND_DESCRIPTION_VALUES: Öffne das Wertemenü.\nCOMMAND_DESCRIPTION_VISIT: Teleport zum Besucherstandort einer Insel.\nCOMMAND_DESCRIPTION_VISITORS: Öffne das Besuchermenü.\nCOMMAND_DESCRIPTION_WARP: Warp zu einem Insel-Warp.\nCOMMAND_DESCRIPTION_WARPS: Öffne das Warps-Menü.\nCOMMAND_DESCRIPTION_WITHDRAW: Geld von der Bank deiner Insel auf dein persönliches\n  Konto abheben.\nCOMMAND_USAGE: '&cUsage: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} als Genossenschaftsmitglied hinzugefügt.'\nCOOP_BANNED_PLAYER: '&c&lFehler | &7Dieser Spieler ist von der Insel gesperrt und\n  kann nicht kooperiert werden.'\nCOOP_LIMIT_EXCEED: '&c&lFehler | &7Du hast die maximale Anzahl an Koop-Spielern erreicht,\n  die die Insel haben kann.'\nCREATE_ISLAND: '&e&lInsel | &7Neue Insel bei {0} in {1}ms erstellt.'\nCREATE_ISLAND_FAILURE: '&c&lError | &7Beim Erstellen deiner Insel ist ein Fehler aufgetreten.\n  Bitte wende dich an den Administrator, um das Problem zu untersuchen.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Debug-Modus umgeschaltet &cOFF&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Debug-Modus &aON&7 umgeschaltet.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lInsel | &7Du hast den Warp {0} gelöscht.'\nDELETE_WARP_SIGN_BROKE: '&7&oEs gab ein Zeichen für diesen Warp, er ist gebrochen...'\nDEMOTE_LEADER: '&c&lError | &7Du kannst keine Inselanführer degradieren.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler mit einer niedrigeren\n  Inselrolle als deiner degradieren.'\nDEMOTED_MEMBER: '&e&lInsel | &7Du hast {0} auf seiner Insel zu einem {1} degradiert.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} hat ${1} auf die Inselbank eingezahlt!'\nDEPOSIT_ERROR: '&c&lError | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lError | &7Du darfst nicht außerhalb deiner Border abbauen.'\nDISBAND_ANNOUNCEMENT: '&e&lInsel | &7Deine Insel wurde von {0} aufgelöst.'\nDISBAND_GIVE: '&e&lInsel | &7Du hast {0} Auflösungen erhalten.'\nDISBAND_GIVE_ALL: '&e&lInsel | &7Du hast {0} allen Spielern aufgelöst.'\nDISBAND_GIVE_OTHER: '&e&lInsel | &7Du hast {1} {0} aufgelöst.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oDeine Insel wurde aufgelöst und ${0} Dollar wurden\n  deinem Konto von der Inselbank zurückerstattet'\nDISBAND_SET: '&e&lInsel | &7Deine Auflösungsanzahl wurde auf {0} gesetzt.'\nDISBAND_SET_ALL: '&e&lInsel | &7Du hast die Auflösungsanzahl aller Spieler auf {0}\n  gesetzt.'\nDISBAND_SET_OTHER: '&e&lInsel | &7Du hast den Auflösungszähler von {0} auf {1} gesetzt.'\nDISBANDED_ISLAND: '&e&lInsel | &7Du hast deine Insel aufgelöst.'\nDISBANDED_ISLAND_OTHER: '&e&lInsel | &7Du hast die Insel von {0} aufgelöst.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lInsel | &7Sie haben die Insel {0} aufgelöst.'\nENTER_PVP_ISLAND: '&7&oDu wurdest auf eine Insel mit aktiviertem PVP teleportiert.\n  Du bist für die nächsten 10 Sekunden immun gegen PVP...'\nEXPELLED_PLAYER: '&e&lInsel | &7{0} wurde von der Insel vertrieben.'\nFORMAT_QUAD: Q\nFORMAT_TRILLION: T\nFORMAT_BILLION: B\nFORMAT_MILLION: M\nFORMAT_THOUSANDS: K\nFORMAT_SECONDS_NAME: Sekunden\nFORMAT_SECOND_NAME: zweite\nFORMAT_MINUTES_NAME: Minuten\nFORMAT_MINUTE_NAME: Minute\nFORMAT_HOURS_NAME: Stunden\nFORMAT_HOUR_NAME: Stunde\nFORMAT_DAYS_NAME: Tage\nFORMAT_DAY_NAME: Tag\nGENERATOR_CLEARED: '&e&lInsel | &7Die Generator Anzahl für die Insel von {0} wurden\n  erfolgreich gelöscht.'\nGENERATOR_CLEARED_NAME: '&e&lInsel | &7Die Generator Anzahl für die Insel {0} wurden\n  erfolgreich ausgeglichen.'\nGENERATOR_CLEARED_ALL: '&e&lInsel | &7Erfolgreich die Generator Anzahl für alle Inseln\n  gelöscht.'\nGENERATOR_UPDATED: '&e&lInsel | &7Der Generator Anzahl von {0} wurde erfolgreich auf\n  die Insel von {1} aktualisiert.'\nGENERATOR_UPDATED_NAME: '&e&lInsel | &7Der Generator Anzahl von {0} wurde erfolgreich\n  auf die Insel {1} ​​aktualisiert.'\nGENERATOR_UPDATED_ALL: '&e&lInsel | &7Die Generator Anzahl von {0} wurde erfolgreich\n  auf alle Inseln aktualisiert.'\nGLOBAL_COMMAND_EXECUTED: '&e&lInsel | &7Der Befehl wurde erfolgreich auf den Inselelementen\n  von {0} ausgeführt!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lInsel | &7Der Befehl wurde erfolgreich auf den\n  Inselmitgliedern von {0} ausgeführt!'\nGLOBAL_MESSAGE_SENT: '&e&lInsel | &7Die Nachricht wurde erfolgreich an die Inselmitglieder\n  von {0} gesendet!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lInsel | &7Die Nachricht wurde erfolgreich an die Inselmitglieder\n  von {0} gesendet!'\nGLOBAL_TITLE_SENT: '&e&lInsel | &7Der Titel wurde erfolgreich an die Inselmitglieder\n  von {0} gesendet!'\nGLOBAL_TITLE_SENT_NAME: '&e&lInsel | &7Der Titel wurde erfolgreich an die Inselmitglieder\n  von {0} gesendet!'\nGOT_BANNED: '&e&lInsel | &7Du wurdest von {0}´s Insel GEBANNT.'\nGOT_DEMOTED: '&e&lIsland | &7Du wurdest auf dieser Insel zu einem {0} degradiert.'\nGOT_EXPELLED: '&e&lIsland | &7&oDu wurdest von {0} von der Insel vertrieben.'\nGOT_INVITE: '&e&lInsel | &7{0} hat dich auf seine Insel eingeladen.'\nGOT_INVITE_TOOLTIP: '&7Klicke auf die Nachricht, um die Einladung anzunehmen.'\nGOT_KICKED: '&e&lInsel | &7Du wurdest von {0} von seiner Insel geworfen.'\nGOT_PROMOTED: '&e&lInsel | &7Du wurdest auf seiner Insel zu einem {0} befördert.'\nGOT_REVOKED: '&e&lInsel | &7{0} hat deine Einladung zu dieser Insel widerrufen.'\nGOT_UNBANNED: '&e&lInsel | &7Du wurdest von {0}´s Insel ENTBANNT.'\nHIT_ISLAND_MEMBER: '&c&lError | &7Du kannst deine Inselmitglieder nicht treffen.'\nHIT_PLAYER_IN_ISLAND: '&c&lError | &7Du kannst keine Spieler innerhalb von Inseln\n  treffen.'\nIGNORED_ISLAND: '&e&lInsel | Die Insel von &7{0} wird jetzt von den oberen Inseln\n  ignoriert.'\nIGNORED_ISLAND_NAME: '&e&lInsel | &7Die Insel {0} wird jetzt von den oberen Inseln\n  ignoriert.'\nINTERACT_OUTSIDE_ISLAND: '&c&lError | &7Du kannst außerhalb der Border nicht interagieren.'\nINVALID_AMOUNT: '&c&lError | &7Ungültiger Betrag {0}.'\nINVALID_BIOME: '&c&lError | &7Ungültiges Biom {0}.'\nINVALID_BLOCK: '&c&lError | &7Ungültige Blockposition {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lError | &7Ungültige Wirkung {0}.'\nINVALID_ENTITY: '&c&lError | &7Ungültige Entität {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.'\nINVALID_ISLAND: '&c&lError | &7Du hast keine Insel.'\nINVALID_ISLAND_LOCATION: '&c&lError | &7An deinem Standort gibt es keine Insel.'\nINVALID_ISLAND_OTHER: '&c&lError | &7{0} hat keine Insel.'\nINVALID_ISLAND_OTHER_NAME: '&c&lFehler | &7Es gibt keine Insel mit dem Namen {0}.'\nINVALID_ISLAND_PERMISSION: |-\n  &c&lFehler | &7Die Inselberechtigung {0} konnte nicht gefunden werden.\n  &c&lFehler | &7Inselberechtigungen: {1}\nINVALID_LEVEL: '&c&lError | &7Ungültige Ebene {0}.'\nINVALID_LIMIT: '&c&lError | &7Ungültiges Limit {0}.'\nINVALID_MATERIAL: '&c&lError | &7Ungültiges Material {0}.'\nINVALID_MATERIAL_DATA: '&c&lError | &7Ungültige Materialdaten {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lError | &7Ungültige Mission {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lError | &7Ungültiges Modul {0}.'\nINVALID_MULTIPLIER: '&c&lError | &7Ungültiger Multiplikator {0}.'\nINVALID_PAGE: '&c&lError | &7Ungültige Seite {0}.'\nINVALID_PERCENTAGE: '&c&lError | &7Der Prozentsatz muss zwischen 0 und 100 liegen.'\nINVALID_PLAYER: '&c&lError | &7Kann keinen Spieler namens {0} finden'\nINVALID_RATE: |-\n  &c&lFehler | &7Keine Bewertung mit dem Namen {0} gefunden.\n  &c&lFehler | &7Inselbewertungen: {1}\nINVALID_ROWS: '&c&lError | &7Ungültige Anzahl von Zeilen: {0}'\nINVALID_ROLE: |-\n  &c&lFehler | &7Die Inselrolle {0} konnte nicht gefunden werden.\n  &c&lFehler | &7Inselrollen: {1}\nINVALID_SCHEMATIC: '&c&lError | &7Die Shematic mit dem Namen {0} konnte nicht gefunden\n  werden.'\nINVALID_SETTINGS: |-\n  &c&lFehler | &7Die Inseleinstellungen {0} konnten nicht gefunden werden.\n  &c&lFehler | &7Inseleinstellungen: {1}\nINVALID_SIZE: '&c&lError | &7Ungültige Größe {0}.'\nINVALID_SLOT: '&c&lError | &7Ungültiger Slot {0}.'\nINVALID_TITLE: '&c&lError | &7Ungültigen Titel eingegeben.'\nINVALID_TOGGLE_MODE: '&c&lFehler | &7Kann {0} nicht umschalten.'\nINVALID_UPGRADE: |-\n  &c&lFehler | &7Ein Upgrade namens {0} konnte nicht gefunden werden.\n  &c&lFehler | &7Upgrades: {1}\nINVALID_VISIT_LOCATION: '&c&lFehler | &7Diese Insel hat keinen Besucherstandort.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oDu hast den Bypass-Modus, der dich auf die Insel\n  teleportiert...'\nINVALID_WARP: '&c&lError | &7Ungültiger Warp {0}.'\nINVALID_WORLD: '&c&lError | &7Ungültige Welt {0}.'\nINVITE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} auf die Insel eingeladen.'\nINVITE_BANNED_PLAYER: '&c&lError | &7Dieser Spieler ist von der Insel gesperrt und\n  kann nicht eingeladen werden.'\nINVITE_TO_FULL_ISLAND: '&c&lError | &7Du kannst keine weiteren Mitglieder auf Ihre\n  Insel einladen.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lError | &7Eine Insel mit diesem Namen existiert bereits.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBank | &7Inselbank ist leer.'\nISLAND_BANK_SHOW: '&e&lBank | &7Deine Insel hat ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBank | Die Insel von &7{0} hat ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7Die Insel {0} hat ${1}.'\nISLAND_BEING_CALCULATED: '&c&lError | &7Du kannst nicht mit Blöcken interagieren,\n  wenn die Insel neu berechnet wird!'\nISLAND_CLOSED: '&e&lInsel | &7Die Insel wurde erfolgreich für die Öffentlichkeit geschlossen.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Du hast eine bereits laufende Inselerstellungsaufgabe.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lInsel | &7Deine Anfrage wird bearbeitet...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lFly | &7Inselflug wurde automatisch &cdeaktiviert&7.'\nISLAND_FLY_ENABLED: '&e&lFly | &7Inselflug wurde automatisch &aktiviert&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lInsel | &7&oDu warst auf einer Insel, die aufgelöst\n  wurde, also wurdest du zurück zum Spawn teleportiert...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lInsel | &7&oDu warst auf einer Insel, die\n  PvP aktiviert hatte, also wurdest du zurück zum Spawnen teleportiert...'\nISLAND_HELP_FOOTER: '&e&lSkyblock &7Entwickelt von einem Entwickler'\nISLAND_HELP_HEADER: '&e&lSkyblock &7Befehlsliste [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Verwende /is help {0} für die nächste Seite.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lInsel | &7Banklimit: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |-\n  &e&lInsel | &7Blockgrenzen:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lInsel | &7Coop-Limit: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lInsel | &7Crops-Multiplikator: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lInsel | &7Tropfen-Multiplikator: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |-\n  &e&lInsel | &7Inseleffekte:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lInsel | &7 {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |-\n  &e&lInsel | &7Entity Grenze:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |-\n  &e&lInsel | &7Generator Preise ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lInsel | &7 {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |-\n  &e&lInsel | &7Rollenbeschränkungen:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lInsel | &7Insel Größe: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lInsel | &7Spawner-Multiplikator: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lInsel | &7Teamlimit: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |-\n  &e&lInsel | &7Upgrades:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lInsel | &7 {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lInsel | &7Warps-Limit: {0}'\nISLAND_INFO_BANK: '&e&lInsel | &7Bank: {0}'\nISLAND_INFO_BONUS: '&e&lInsel | &7Wert-Bonus: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lInsel | &7Level Bonus: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lInsel | &7Erstellungszeit: {0}'\nISLAND_INFO_DISCORD: '&e&lInsel | &7Discord: {0}'\nISLAND_INFO_FOOTER: Citycrafting\nISLAND_INFO_HEADER: Servernetzwerk seit 2020\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lInsel | &7Letzte Aktualisierung: vor {0}'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lInsel | &7Letzte Aktualisierung:\n  &aDerzeit aktiv'\nISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}'\nISLAND_INFO_LOCATION: '&e&lInsel | &7Heimat: {0}'\nISLAND_INFO_NAME: '&e&lInsel | &7Name: {0}'\nISLAND_INFO_OWNER: '&e&lIsland | &7Besitzer: {0}'\nISLAND_INFO_PAYPAL: '&e&lInsel | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lInsel | &7 - {0}'\nISLAND_INFO_RATE: '&e&lInsel | &7Rate: {0} &7({1}/5) - {2} Gesamtbewertungen.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |-\n  &e&lInsel | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lInsel | &7Besucheranzahl: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lInsel | &7Wert: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit zugänglich\n  gemacht.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVorschau | &7Du hast sich zu weit entfernt und\n  befindest dich nicht mehr im Vorschaumodus.'\nISLAND_PREVIEW_CANCEL: '&e&lVorschau | &7Du hast den Vorschaumodus abgebrochen.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'BESTÄTIGEN'\nISLAND_PREVIEW_CANCEL_TEXT: 'ABBRECHEN'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lVorschau | &7Du hast den Vorschaumodus für den Schaltplan {0} gestartet.\n  &e&lVorschau | &7Gebe &a&lBESTÄTIGEN &7 ein, um eine neue Insel zu erstellen, oder &c&lABBRECHEN &7, um den Vorschaumodus abzubrechen.\n  &e&lVorschau | &7Du kannst das Inselgebiet nicht verlassen, sonst wird der Vorschaumodus automatisch abgebrochen.\nISLAND_PROTECTED: '&c&lError | &7Diese Insel ist geschützt.'\nISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lInsel | &7Mitglieder von {0}´s Insel &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Online)'\nISLAND_TEAM_STATUS_ROLES: '&e&lInsel | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TOP_STATUS_ONLINE: '&a(Online)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Privat]'\nISLAND_WAS_CLOSED: '&e&lInsel | &7&oDie Insel, auf der du warst, wurde geschlossen\n  und du wurdest zurück zum Spawnen teleportiert...'\nISLAND_WORTH_ERROR: '&c&lError | &7Bei der Berechnung Ihrer Insel ist ein unerwarteter\n  Fehler aufgetreten. Wende dich an die Administratoren, wenn das Problem weiterhin\n  besteht.'\nISLAND_WORTH_RESULT: '&e&lInsel | &7Dein Inselwert ist {0} [Level {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lFehler | &7Die Berechnungstask ist abgelaufen. Versuche\n  es später noch einmal...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lInsel | &7{0} ist deiner Insel beigetreten.'\nJOIN_ANNOUNCEMENT: '&e&lInsel | &7{0} ist deiner Insel beigetreten.'\nJOIN_FULL_ISLAND: '&c&lError | &7Diese Insel hat die maximal zulässige Anzahl von\n  Mitgliedern erreicht.'\nJOIN_WHILE_IN_ISLAND: '&c&lError | &7Du befindest dich bereits auf einer Insel.'\nJOINED_ISLAND: '&e&lInsel | &7Du bist der Insel von {0} beigetreten.'\nJOINED_ISLAND_NAME: '&e&lInsel | &7Sie sind der Insel {0} beigetreten.'\nJOINED_ISLAND_AS_COOP: '&e&lIsland | &7Du bist jetzt ein Koop-Mitglied auf der Insel\n  von {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lInsel | &7Du bist jetzt ein Koop-Mitglied der Insel\n  {0}.'\nKICK_ANNOUNCEMENT: '&e&lInsel | &7{0} wurde von {1} von der Insel geworfen.'\nKICK_ISLAND_LEADER: '&c&lError | &7Du kannst den Besitzer der Insel nicht kicken,\n  verwende stattdessen /is admin disband.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Du kannst nur Spieler mit einer niedrigeren\n  Inselrolle als deiner kicken.'\nLACK_CHANGE_PERMISSION: '&c&lError | &7Du musst diese Berechtigung haben, um sie in\n  andere Rollen zu ändern.'\nLAST_ROLE_DEMOTE: '&c&lError | &7Du kannst diesen Spieler nicht mehr zurückstufen.'\nLAST_ROLE_PROMOTE: '&c&lError | &7Du kannst diesen Spieler nicht mehr befördern.'\nLEAVE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat die Insel verlassen.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lFehler | &7Du kannst deine Insel nicht verlassen, wenn sie dir gehört.\n  &c&lFehler | &7Du kannst das Eigentum mit /is transfer übertragen.\nLEFT_ISLAND: '&e&lInsel | &7Du hast deine Insel verlassen.'\nLEFT_ISLAND_COOP: '&e&lInsel | &7Du bist kein Koop-Mitglied mehr auf der Insel von\n  {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lInsel | &7Du bist kein Genossenschaftsmitglied der Insel\n  {0} mehr.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lError | &7Du musst festes Material bereitstellen.'\nMAXIMUM_LEVEL: '&c&lError | &7Die maximale Stufe für dieses Upgrade ist {0}.'\nMESSAGE_SENT: '&e&lIsland | &7Die Nachricht wurde erfolgreich an {0} gesendet!'\nMISSION_CANNOT_COMPLETE: '&c&lError | &7Du kannst diese Mission noch nicht abschließen.'\nMISSION_NO_AUTO_REWARD: '&e&lMission | &7Du hast alle erforderlichen Materialien,\n  um {0} abzuschließen - verwende /is missions, um sie abzuschließen!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7Du musst {0} abschließen, bevor\n  du diese Mission abschließen kannst.'\nMISSION_STATUS_COMPLETE: '&e&lMission | &7Der Status der Mission {0} wurde für {1}\n  in \"Abgeschlossen\" geändert.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Der Status aller Missionen wurde auf\n  abgeschlossen für {0} geändert.'\nMISSION_STATUS_RESET: '&e&lMission | &7Setze den Status der Mission {0} für {1} zurück.'\nMISSION_STATUS_RESET_ALL: '&e&lMission | &7Setze den Status aller Missionen für {0}\n  zurück.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7Dieses Modul ist bereits geladen.'\nMODULE_INFO: |-\n  &e&lModul | &7{0} von {1}\n  &e&lModul | &7&m--------------------\n  &e&lModul | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Das Modul {0} wurde erfolgreich geladen.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Das Modul {0} konnte nicht geladen werden.\n  Weitere Informationen finden Sie in der Konsole.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Das Modul wurde erfolgreich entladen.'\nMODULES_LIST: '&fModule ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lInsel | &7{0} hat seinen Inselnamen in {1}&7 geändert.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lError | &7Du kannst diesen Namen nicht verwenden.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lFehler | &7Du kannst keine Spielernamen als Inselnamen verwenden.'\nNAME_TOO_LONG: '&c&lError | &7Inselnamen dürfen nicht länger als {0} Zeichen sein.'\nNAME_TOO_SHORT: '&c&lError | &7Inselnamen dürfen nicht kürzer als {0} Zeichen sein.'\nNO_BAN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu bannen.'\nNO_CLOSE_BYPASS: '&c&lError | &7Diese Insel ist nicht für die Öffentlichkeit zugänglich.'\nNO_CLOSE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für\n  die Öffentlichkeit zu schließen.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler als Koop-Mitglieder\n  hinzuzufügen.'\nNO_DELETE_WARP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Warps zu\n  löschen.'\nNO_DEMOTE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler herabstufen\n  zu können.'\nNO_DEPOSIT_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Geld auf die\n  Inselbank einzuzahlen.'\nNO_DISBAND_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Ihre Insel\n  aufzulösen.'\nNO_EXPEL_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler von deiner\n  Insel zu vertreiben.'\nNO_INVITE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler einzuladen.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um auf die\n  Truhe der Insel zugreifen zu können.'\nNO_ISLAND_INVITE: '&c&lError | &7Es konnten keine Einladungen von dieser Insel gefunden\n  werden.'\nNO_ISLANDS_TO_PURGE: '&c&lError | &7Es gab keine Inseln zum Säubern.'\nNO_KICK_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu kicken.'\nNO_MORE_DISBANDS: '&c&lError | &7Du kannst keine Inseln mehr auflösen.'\nNO_MORE_WARPS: '&c&lError | &7Ihre Insel kann keine Warps mehr haben.'\nNO_NAME_PERMISSION: '&c&lError | &7Sie können den Namen Ihrer Insel nicht ändern.'\nNO_OPEN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für\n  die Öffentlichkeit zugänglich zu machen.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Informationen\n  über Berechtigungen zu erhalten.'\nNO_PROMOTE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu\n  befördern.'\nNO_RANKUP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Upgrades aufzuwerten.'\nNO_RATINGS_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Bewertungen\n  zu überprüfen.'\nNO_SET_BIOME_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um das Inselbiom\n  zu ändern.'\nNO_SET_DISCORD_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Inseldisharmonie\n  zu ändern.'\nNO_SET_HOME_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um den Teleportort\n  der Insel festzulegen.'\nNO_SET_PAYPAL_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Paypal-E-Mail-Adresse\n  der Insel zu ändern.'\nNO_SET_ROLE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Rollen für\n  Spieler festzulegen.'\nNO_SET_SETTINGS_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Inseleinstellungen\n  zu ändern.'\nNO_SET_WARP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Island Warps\n  zu setzen.'\nNO_TRANSFER_PERMISSION: '&c&lError | &7Du musst der Anführer der Insel sein, um die\n  Führung zu übertragen.'\nNO_UNCOOP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler aus\n  Koop-Mitgliedern zu entfernen.'\nNO_UPGRADE_PERMISSION: '&c&lError | &7Sie haben nicht die Berechtigung zum Upgrade\n  auf eine andere Ebene.'\nNO_WITHDRAW_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Geld von der\n  Inselbank abzuheben.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7Du hast nicht genug Geld, um {0} Dollar\n  auf die Bank Ihrer Insel einzuzahlen.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7Du hast nicht genug Geld.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7Du hast nicht genug Geld, um Island Warps\n  zu benutzen.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oDu´ bist zu müde, um mit Menüs zu interagieren, findest\n  du nicht auch?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Inselpanel umgeschaltet &cOFF&7.\n  &e&lPanel | &7Das Ausführen von /is wird dich zur Insel teleportieren.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Inselpanel umgeschaltet &aON&7.\n  &e&lPanel | &7Ausführen von /is öffnet das GUI.\nPERMISSION_CHANGED: '&e&lInsel | &7Die Berechtigung {0} der Insel von {1} wurde erfolgreich\n  aktualisiert.'\nPERMISSION_CHANGED_NAME: '&e&lInsel | &7Die Berechtigung {0} der Insel {1} ​​wurde\n  erfolgreich aktualisiert.'\nPERMISSION_CHANGED_ALL: '&e&lInsel | &7Die Berechtigung {0} für alle Inseln erfolgreich\n  aktualisiert.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lInsel | &7Alle Berechtigungen für {0} erfolgreich auf\n  Standardwerte zurückgesetzt!'\nPERMISSIONS_RESET_ROLES: '&e&lInsel | &7Alle Berechtigungen der Insel erfolgreich\n  auf Standardwerte zurücksetzen!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lFehler | &7Dieser Spieler ist bereits gesperrt.'\nPLAYER_ALREADY_COOP: '&c&lError | &7Dieser Spieler ist bereits kooperativ.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lError | &7Dieser Spieler befindet sich bereits auf\n  einer Insel.'\nPLAYER_ALREADY_IN_ROLE: '&c&lFehler | &7{0} ist bereits ein {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lError | &7Dieser Benutzer kann nicht von der Insel ausgeschlossen\n  werden.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} ist dem Server beigetreten.'\nPLAYER_NOT_BANNED: '&c&lFehler | &7Dieser Spieler ist nicht gesperrt.'\nPLAYER_NOT_COOP: '&c&lError | &7Dieser Spieler ist nicht kooperativ.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7Dieser Spieler befindet sich nicht auf deiner\n  Insel.'\nPLAYER_NOT_ONLINE: '&c&lError | &7Dieser Spieler ist nicht online!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lInsel | &7{0} hat den Server verlassen.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler befördern,\n  die eine niedrigere Inselrolle als deine haben.'\nPROMOTED_MEMBER: '&e&lIsland | &7Du hast {0} zu einem {1} auf seiner Insel befördert.'\nPURGE_CLEAR: '&e&lIsland | &7Alle Inseln in der Warteschlange zum Löschen erfolgreich\n  gelöscht.'\nPURGED_ISLANDS: |-\n  &e&lIsland | &7{0} islands will be purged when server restarts.\n  &e&lIsland | &7You can cancel it anytime using /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIsland | &7Das Upgrade-Level {0} für die Insel von {1} wurde\n  erfolgreich aktualisiert.'\nRANKUP_SUCCESS_ALL: '&e&lInsel | &7Das Upgrade-Level {0} für alle Inseln erfolgreich\n  aktualisiert.'\nRANKUP_SUCCESS_NAME: '&e&lInsel | &7Die Aktualisierungsstufe {0} für {1} wurde erfolgreich\n  aktualisiert.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat deine Insel mit {1} von 5 Punkten bewertet!.'\nRATE_CHANGE_OTHER: '&e&lInsel | &7Du hast die Bewertung von {0} in {1} geändert.'\nRATE_OWN_ISLAND: '&c&lError | &7Du kannst deine eigene Insel nicht bewerten.'\nRATE_REMOVE_ALL: '&e&lInsel | &7Alle Bewertungen von {0} wurden erfolgreich entfernt.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lInsel | &7Alle Bewertungen aller Inseln wurden erfolgreich\n  entfernt.'\nRATE_SUCCESS: '&e&lInsel | &7Du hast diese Insel mit {0} Sternen bewertet!'\nREACHED_BLOCK_LIMIT: '&e&lUpgrades | &7Du hast das Limit der Insel für {0} Block erreicht.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lError | &7Deine Insel wird bereits neu berechnet.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lFehler | &7Diese Insel wird bereits neu berechnet.'\nRECALC_ALL_ISLANDS: '&e&lInsel | &7Alle Inseln neu berechnen...'\nRECALC_ALL_ISLANDS_DONE: '&e&lInsel | &7Neuberechnung aller Inseln erfolgreich abgeschlossen.'\nRECALC_PROCCESS_REQUEST: '&e&lInsel | &7Deine Anfrage wird bearbeitet...'\nRELOAD_COMPLETED: '&e&lInsel | &7Neuladen ist beendet!'\nRELOAD_PROCCESS_REQUEST: '&e&lInsel | &7Starte das Neuladen von Konfigurationen...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat die Einladung von {1} auf die Insel\n  widerrufen.'\nRESET_WORLD_SUCCEED: '&e&lInsel | &7Die Welt {0} für die Insel von {1} erfolgreich\n  zurückgesetzt.'\nRESET_WORLD_SUCCEED_ALL: '&e&lInsel | &7Die Welt {0} für alle Inseln erfolgreich zurückgesetzt.'\nRESET_WORLD_SUCCEED_NAME: '&e&lInsel | &7Die Welt {0} für {1} erfolgreich zurückgesetzt.'\nSAME_NAME_CHANGE: '&c&lError | &7Du musst einen anderen Namen als dein aktuellen Inselnamen\n  eingeben.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Ausgewählte Position #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lError | &7Du hast keine zwei Stellen ausgewählt.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Deine Anfrage wird bearbeitet...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematics | &7You have selected two positions. Run /is admin schematic <name> to create a new schematic.\n  &e&lSchematics | &7Make sure you stand at the teleportion location when executing the command.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Ausgewählte Position Nr. 1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematics | &7Schaltplan erfolgreich gespeichert!'\nSELF_ROLE_CHANGE: '&c&lError | &7Du kannst deine Rolle nicht ändern.'\nSET_UPGRADE_LEVEL: '&e&lUpgrades | &7Die Ebene von {0} für die Insel von {1} wurde\n  erfolgreich aktualisiert.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Die Ebene von {0} für {1} wurde erfolgreich\n  aktualisiert.'\nSET_WARP: '&e&lInsel | &7Erzeugt erfolgreich einen neuen Warp am {0}.'\nSET_WARP_OUTSIDE: '&c&lError | &7Du kannst keine Warps außerhalb Ihrer Insel setzen.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf die\n  Insel von {1} aktualisiert.'\nSETTINGS_UPDATED_NAME: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf\n  die Insel {1} ​​aktualisiert.'\nSETTINGS_UPDATED_ALL: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich für\n  alle Inseln aktualisiert.'\nSIZE_BIGGER_MAX: '&c&lError | &7Du kannst keine Größe festlegen, die größer als die\n  maximale Inselgröße ist.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Erfolgreich teleportiert {0} zum Spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Der Spawn-Speicherort wurde erfolgreich auf {0}\n  aktualisiert.'\nSPY_TEAM_CHAT_FORMAT: '&7[Spion] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lUpgrades | &7Alle Upgrade-Werte der Insel von {0} wurden erfolgreich\n  synchronisiert.'\nSYNC_UPGRADES_ALL: '&e&lUpgrades | &7Alle Upgrade-Werte aller Inseln erfolgreich synchronisiert.'\nSYNC_UPGRADES_NAME: '&e&lUpgrades | &7Alle Upgrade-Werte von {0} wurden erfolgreich\n  synchronisiert.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7Du befindest dich nicht auf deiner\n  Insel.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lError | &7Du kannst dich nicht außerhalb Ihres Schutzbereichs\n  teleportieren.'\nTELEPORT_WARMUP: '&7&oDu wirst in {0} teleportiert... Nicht bewegen!'\nTELEPORT_WARMUP_CANCEL: '&7&oDu bist umgezogen und deshalb wurde die Teleportation\n  abgebrochen.'\nTITLE_SENT: '&e&lIsland | &7Der Titel wurde erfolgreich an {0} gesendet!'\nTELEPORTED_FAILED: '&e&lIsland | &7Anscheinend hat diese Insel keine sicheren Blöcke.\n  Bitte wenden dich an einen Supporter.'\nTELEPORTED_SUCCESS: '&e&lIsland | &7Du wurdest auf deine Insel teleportiert.'\nTELEPORTED_TO_WARP: '&e&lInsel | &7Erfolgreich zu diesem Inselwarp teleportiert.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lInsel | &7Der Spieler {0} hat sich zum Inselwarp\n  {1} teleportiert.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Umgehungsmodus &cOFF&7 umgeschaltet.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Umgehungsmodus &aON&7 umgeschaltet.'\nTOGGLED_FLY_OFF: '&e&lFly | &7Inselflug umgeschaltet &cOFF&7.'\nTOGGLED_FLY_ON: '&e&lFly | &7Inselflug umgeschaltet &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Schematicsmodus &cOFF&7 umschalten.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchaltpläne | &7Schematicsmodus umschalten &aON&7.\n  &e&lSchaltpläne | &7Wähle einen Bereich mit einer goldenen Axt aus.\nTOGGLED_SPY_OFF: '&e&lSpy | &7Spionage-Chat umgeschaltet &cOFF&7.'\nTOGGLED_SPY_ON: '&e&lSpy | &7Spionage-Chat umgeschaltet &aON&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Blöcke Stacker &cOFF&7 umschalten.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Blöcke Stacker &aON&7 umschalten.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Teamchat umschalten &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Teamchat umschalten &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lGrenze | &7Umschalten der Weltgrenze &cOFF&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lGrenze | &7Umschalten der Weltgrenze &aON&7.'\nTRANSFER_ADMIN: '&e&lInsel | &7Du hast die Führung von {0} an {1} übertragen.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} ist bereits der Anführer seiner\n  Insel.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7Diese Spieler sind nicht auf den selben\n  Inseln.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7Dieser Spieler ist kein Anführer einer Insel.'\nTRANSFER_ALREADY_LEADER: '&c&lError | &7Du bist bereits der Anführer dieser Insel.'\nTRANSFER_BROADCAST: '&e&lInsel | &7Die Führung der Insel wurde auf {0} übertragen.'\nUNBAN_ANNOUNCEMENT: '&e&lInsel | &7{0} wurde von {1} von der Insel ENTFERNT.'\nUNCOOP_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} als Genossenschaftsmitglied entfernt.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lInsel | &7{0} hat das Spiel verlassen und ist kein\n  Koop-Mitglied mehr.'\nUNIGNORED_ISLAND: '&e&lInsel | Die Insel von &7{0} wird jetzt nicht mehr von den Top-Inseln\n  ignoriert.'\nUNIGNORED_ISLAND_NAME: '&e&lInsel | &7Die Insel {0} wird jetzt von den Top-Inseln\n  nicht mehr ignoriert.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lInsel | &7&oAnscheinend ist dieser Warp unsicher. Bitte versuche\n  es mit einem anderen Warp.'\nUPDATED_PERMISSION: '&e&lInsel | &7Aktualisierte Berechtigungen für {0}.'\nUPDATED_SETTINGS: '&e&lInsel | &7Die Inseleinstellungen {0} aktualisiert.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Du kannst erst in {0} erneut ein Upgrade durchführen.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lError | &7Du kannst diesen Befehl nicht auf anderen Inseln\n  verwenden.'\nWARP_ALREADY_EXIST: '&c&lError | &7Es existiert bereits ein Warp mit diesem Namen.'\nWARP_CATEGORY_ICON_NEW_LORE: |-\n  &e&lWarps | &7Gebe eine neue Beschreibung ein (Gebe \"-cancel\" ein, um abzubrechen):\n  &e&lWarps | &7Du kannst Zeilen mit \"\\n\" trennen.\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Gebe einen Namen ein (gebe \"-cancel\" ein,\n  um abzubrechen):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Gebe  eine neue Materialart ein (Gebe\n  \"-cancel\" ein, um abzubrechen):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Das Symbol der Kategorie wurde erfolgreich\n  aktualisiert.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lFehler | &7Du kannst nur alphabetische Buchstaben,\n  Zahlen und ''_'' für Warp-Kategorienamen verwenden.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Gebe einen neuen Slot ein (Gebe \"-cancel\" ein,\n  um abzubrechen):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lFehler | &7Dieser Slot ist bereits von einer\n  anderen Kategorie belegt.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Der Slot der Kategorie wurde erfolgreich\n  in {0} geändert.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Gebe einen neuen Namen ein (gebe zum Abbrechen\n  \"-cancel\" ein):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lFehler | &7Dieser Name wird bereits von einer\n  anderen Kategorie verwendet.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Die Kategorie wurde erfolgreich in {0}\n  umbenannt.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Gebe eine neue Beschreibung ein (Gebe \"-cancel\" ein, um abzubrechen):\n  &e&lWarps | &7Du kannst Zeilen mit \"\\n\" trennen.\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Gebe einen Namen ein (gebe \"-cancel\" ein, um abzubrechen):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Gebe eine neue Materialart ein (Gebe \"-cancel\"\n  ein, um abzubrechen):'\nWARP_ICON_UPDATED: '&e&lWarps | &7Das Warp-Icon wurde erfolgreich aktualisiert.'\nWARP_ILLEGAL_NAME: '&c&lError | &7Du kannst nur alphabetische Buchstaben, Zahlen und\n  ''_'' für Warp-Namen verwenden.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Der Standort des Warps wurde erfolgreich auf\n  deinen Standort aktualisiert.'\nWARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Der Warp wurde erfolgreich für die Öffentlichkeit\n  geöffnet.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Der Warp wurde erfolgreich für die Öffentlichkeit\n  geschlossen.'\nWARP_RENAME: '&e&lWarps | &7Gebe einen neuen Namen ein (gebe zum Abbrechen \"-cancel\"\n  ein):'\nWARP_RENAME_ALREADY_EXIST: '&c&lFehler | &7Dieser Name wird bereits von einem anderen\n  Warp verwendet.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Der Warp wurde erfolgreich in {0} umbenannt.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBank | &7Insel Bank hat nur {0} Dollar drin.\n  &e&lBank | &7&oAlles Geld abheben...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!'\nWITHDRAW_ERROR: '&c&lError | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!'\nWITHDRAWN_MONEY_NAME: '&e&lBank | &7Du hast ${0} von der Inselbank von {1} abgehoben!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lWorlds | &7Die Welt {0} ist noch nicht freigeschaltet!'"
  },
  {
    "path": "src/main/resources/lang/en-US.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIsland | &7Successfully added the player {0} to {1}''s island.'\nADMIN_ADD_PLAYER_NAME: '&e&lIsland | &7Successfully added the player {0} to the island {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBank | &7You deposited ${0} into {1}''s island bank.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7You deposited ${0} into the bank of the island {1}.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Developed by Ome_R'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Admin Commands List [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Use /is admin {0} for the next page.'\nALREADY_IN_ISLAND: '&c&lError | &7You are already in an island.'\nALREADY_IN_ISLAND_OTHER: '&c&lError | &7This player is already a member of your island.'\nBAN_ANNOUNCEMENT: '&e&lIsland | &7{0} was BANNED from the island by {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only ban players with a lower island role than yours.'\nBANK_DEPOSIT_CUSTOM: '&e&lBank | &7Type the amount you want to deposit:'\nBANK_DEPOSIT_COMPLETED: 'Deposit Completed'\nBANK_LIMIT_EXCEED: '&c&lError | &7You have exceeded your bank limit.'\nBANK_WITHDRAW_CUSTOM: '&e&lBank | &7Type the amount you want to withdraw:'\nBANK_WITHDRAW_COMPLETED: 'Withdraw Completed'\nBANNED_FROM_ISLAND: '&c&lError | &7You are banned from this island.'\nBLOCK_COUNT_CHECK: '&e&lIsland | &7This island has x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIsland | &7This island has the following blocks:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIsland | &7This island has no tracked blocks.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lLevel | &7The block {0}''s level is {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7The block {0} is worthless.'\nBLOCK_VALUE: '&e&lWorth | &7The block {0} worth {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lWorth | &7The block {0} is worthless.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Blue'\nBORDER_PLAYER_COLOR_NAME_RED: 'Red'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Green'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBorder | &7Successfully changed your personal border color to {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lError | &7You cannot build outside of your protection range.'\nCANNOT_SET_ROLE: '&c&lError | &7You cannot set the player''s role to {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7You can only change permissions to lower island role than yours.'\nCHANGED_BANK_LIMIT: '&e&lUpgrades | &7Successfully updated the bank limit of {0}''s island.'\nCHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the bank limit of all the islands.'\nCHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the bank limit of {0}.'\nCHANGED_BIOME: '&e&lIsland | &7Successfully changed biome to {0}. You might need to reconnect to the server to see changes.'\nCHANGED_BIOME_ALL: '&e&lIsland | &7Successfully changed biome to {0} for all the islands.'\nCHANGED_BIOME_NAME: '&e&lIsland | &7Successfully changed biome to {0} for the island {1}.'\nCHANGED_BIOME_OTHER: '&e&lIsland | &7Successfully changed biome to {0} for {1}''s island.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at {0} to {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}''s island.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the {0} Block limit of all the islands.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.'\nCHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.'\nCHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.'\nCHANGED_COOP_LIMIT: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}''s island.'\nCHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the coop players limit of all the islands.'\nCHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}.'\nCHANGED_CROP_GROWTH: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of {0}''s island.'\nCHANGED_CROP_GROWTH_ALL: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of all the islands.'\nCHANGED_CROP_GROWTH_NAME: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of {0}.'\nCHANGED_DISCORD: '&e&lIsland | &7Successfully changed island discord to {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}''s island.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for all the islands.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}''s island.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for all the islands.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}.'\nCHANGED_ISLAND_SIZE: '&e&lUpgrades | &7Successfully updated the island size of {0}''s island.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Successfully updated the island size of all the islands.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lUpgrades | &7Successfully updated the island size of {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oPlayers are able to build outside their island, so the island size has no affect. You can toggle that feature off in the config so island size will have affect again.'\nCHANGED_LANGUAGE: '&e&lLanguage | &7Successfully changed your language to English.'\nCHANGED_MOB_DROPS: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}''s island.'\nCHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of all the islands.'\nCHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}.'\nCHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.'\nCHANGED_PAYPAL: '&e&lIsland | &7Successfully changed island paypal to {0}.'\nCHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.'\nCHANGED_SPAWNER_RATES: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of {0}''s island.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of all the islands.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of {0}.'\nCHANGED_TEAM_LIMIT: '&e&lUpgrades | &7Successfully updated the team limit of {0}''s island.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the team limit of all the islands.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the team limit of {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lIsland | &7Successfully updated teleport location.'\nCHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Successfully updated the warps limit of {0}''s island.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the warps limit of all the islands.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the warps limit of {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: 'amount'\nCOMMAND_ARGUMENT_BIOME: 'biome'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: 'command...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: 'discord...'\nCOMMAND_ARGUMENT_EFFECT: 'potion-effect'\nCOMMAND_ARGUMENT_EMAIL: 'email'\nCOMMAND_ARGUMENT_ENTITY: 'entity'\nCOMMAND_ARGUMENT_ISLAND_NAME: 'island-name'\nCOMMAND_ARGUMENT_ISLAND_ROLE: 'island-role'\nCOMMAND_ARGUMENT_LEADER: 'leader'\nCOMMAND_ARGUMENT_LEVEL: 'level'\nCOMMAND_ARGUMENT_LIMIT: 'limit'\nCOMMAND_ARGUMENT_MATERIAL: 'material'\nCOMMAND_ARGUMENT_MENU: 'menu-name'\nCOMMAND_ARGUMENT_MESSAGE: 'message...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: 'mission-name'\nCOMMAND_ARGUMENT_MODULE_NAME: 'module-name'\nCOMMAND_ARGUMENT_MULTIPLIER: 'multiplier'\nCOMMAND_ARGUMENT_NAME: 'name'\nCOMMAND_ARGUMENT_NEW_LEADER: 'new-leader'\nCOMMAND_ARGUMENT_PAGE: 'page'\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: 'permission'\nCOMMAND_ARGUMENT_PLAYER_NAME: 'player-name'\nCOMMAND_ARGUMENT_PRIVATE: 'private'\nCOMMAND_ARGUMENT_RATING: 'rating'\nCOMMAND_ARGUMENT_ROWS: 'rows'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: 'schematic-name'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: 'settings'\nCOMMAND_ARGUMENT_SIZE: 'size'\nCOMMAND_ARGUMENT_TIME: 'time'\nCOMMAND_ARGUMENT_TITLE_DURATION: 'duration'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out'\nCOMMAND_ARGUMENT_UPGRADE_NAME: 'upgrade-name'\nCOMMAND_ARGUMENT_VALUE: 'value'\nCOMMAND_ARGUMENT_WARP_NAME: 'warp-name'\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category'\nCOMMAND_ARGUMENT_WORLD: 'world'\nCOMMAND_COOLDOWN_FORMAT: '&c&lError | &7You may only use the command in {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: 'Accept an invitation from a player.'\nCOMMAND_DESCRIPTION_ADMIN: 'Use the admin commands.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Increase the crop growth multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Add an island effect for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Increase entity limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Add percentage of a material for the cobblestone generator.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Increase the mob drops multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expand another player''s island size.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Increase the spawner rates multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Increase members limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Increase the warps limit of an island.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: 'Grant a bonus to a player.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: 'Toggle bypass mode.'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Open island''s chest of another island.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Clear generator rates for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: 'Close an island to the public.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Check a block count on a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Toggle debug outputs.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Demote a member in another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposit money into another player''s island bank.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: 'Disband another player''s island permanently.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Give disbands to a player.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignore an island from top islands.'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: 'Join an island without an invitation.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Kick a player from his island.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: 'Change the status of a mission for a player.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: 'Send a player a message without any prefixes.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Send to all island members a message without any prefixes.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: 'Change the name of an island.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: 'Open an island to the public.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Open a custom menu for a player.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promote a member in another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: 'Purge islands.'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: 'Re-calculates the worth of an island.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: 'Reload all configurations and tasks of the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remove all ratings given by a player.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Create schematics for the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Set block limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Set the chest rows for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Set coop players limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Set the crop growth multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Set a player''s amount of island disbands.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Set entity limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfer an island to someone else.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Set the mob drops multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Set a required role for a permission for all the islands.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Set the rating of another player.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Toggle settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Change percentage of a material for the cobblestone generator.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Change another player''s island size.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Set the spawn location of the server.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Set the spawner rates multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Set members limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Set the level of an upgrade for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Set the warps limit of an island.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Open the plugin settings editor.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: 'Get information about an island.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teleport to the spawn location.'\nCOMMAND_DESCRIPTION_ADMIN_SPY: 'Toggle chat spy mode'\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Show stats about the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sync upgrade values for an island.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teleport to other islands.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Unignore an island from top islands.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Unlock a world for an island.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Withdraw money from another player''s island bank.'\nCOMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.'\nCOMMAND_DESCRIPTION_BAN: 'Ban a player from your island.'\nCOMMAND_DESCRIPTION_BANK: 'Open the island''s bank.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: 'Change the biome of the island.'\nCOMMAND_DESCRIPTION_BORDER: 'Change the border color of the islands.'\nCOMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.'\nCOMMAND_DESCRIPTION_CLOSE: 'Close the island to the public.'\nCOMMAND_DESCRIPTION_COOP: 'Add a player as a co-op to your island.'\nCOMMAND_DESCRIPTION_COOPS: 'Open the coops menu.'\nCOMMAND_DESCRIPTION_COUNTS: 'See block counts in your island.'\nCOMMAND_DESCRIPTION_CREATE: 'Create a new island.'\nCOMMAND_DESCRIPTION_DEL_WARP: 'Delete an island warp.'\nCOMMAND_DESCRIPTION_DEMOTE: 'Demote a member in your island.'\nCOMMAND_DESCRIPTION_DEPOSIT: 'Deposit money from your personal account into the island''s bank.'\nCOMMAND_DESCRIPTION_DISBAND: 'Disband your island permanently.'\nCOMMAND_DESCRIPTION_EXPEL: 'Kick a visitor from your island.'\nCOMMAND_DESCRIPTION_FLY: 'Toggle island fly.'\nCOMMAND_DESCRIPTION_HELP: 'List of all commands.'\nCOMMAND_DESCRIPTION_INVITE: 'Invite a player to your island.'\nCOMMAND_DESCRIPTION_KICK: 'Kick a player from your island.'\nCOMMAND_DESCRIPTION_LANG: 'Change your personal language.'\nCOMMAND_DESCRIPTION_LEAVE: 'Leave your island.'\nCOMMAND_DESCRIPTION_MEMBERS: 'Open the members menu.'\nCOMMAND_DESCRIPTION_MISSION: 'Complete a mission.'\nCOMMAND_DESCRIPTION_MISSIONS: 'Open the missions menu.'\nCOMMAND_DESCRIPTION_NAME: 'Change the name of your island.'\nCOMMAND_DESCRIPTION_OPEN: 'Open the island to the public.'\nCOMMAND_DESCRIPTION_PANEL: 'Open island panel.'\nCOMMAND_DESCRIPTION_PARDON: 'Unban a player from your island.'\nCOMMAND_DESCRIPTION_PERMISSIONS: 'Get all permissions for an island role.'\nCOMMAND_DESCRIPTION_PROMOTE: 'Promote a member in your island.'\nCOMMAND_DESCRIPTION_RANKUP: 'Level up an upgrade.'\nCOMMAND_DESCRIPTION_RATE: 'Rate an island.'\nCOMMAND_DESCRIPTION_RATINGS: 'Show all island ratings.'\nCOMMAND_DESCRIPTION_SETTINGS: 'Open the settings menu.'\nCOMMAND_DESCRIPTION_RECALC: 'Re-calculates the island worth.'\nCOMMAND_DESCRIPTION_SET_DISCORD: 'Set the discord of the island for island payouts.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: 'Set the paypal email of the island for island payouts.'\nCOMMAND_DESCRIPTION_SET_ROLE: 'Change the role of a player in your island.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: 'Change the teleport location of your island.'\nCOMMAND_DESCRIPTION_SET_WARP: 'Create a new island warp.'\nCOMMAND_DESCRIPTION_SHOW: 'Get information about an island.'\nCOMMAND_DESCRIPTION_TEAM: 'Get information about island members status.'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'Toggle team chat mode.'\nCOMMAND_DESCRIPTION_TELEPORT: 'Teleport to your island.'\nCOMMAND_DESCRIPTION_TOGGLE: 'Toggle island borders and stacked blocks placements.'\nCOMMAND_DESCRIPTION_TOP: 'Open top islands panel.'\nCOMMAND_DESCRIPTION_TRANSFER: 'Transfer your island''s leadership.'\nCOMMAND_DESCRIPTION_UNCOOP: 'Remove a player from being a co-op in your island.'\nCOMMAND_DESCRIPTION_UPGRADE: 'Open upgrades panel.'\nCOMMAND_DESCRIPTION_VALUE: 'Get the worth value of a block.'\nCOMMAND_DESCRIPTION_VALUES: 'Open the values menu.'\nCOMMAND_DESCRIPTION_VISIT: 'Teleport to the visitors location of an island.'\nCOMMAND_DESCRIPTION_VISITORS: 'Open the visitors menu.'\nCOMMAND_DESCRIPTION_WARP: 'Warp to an island warp.'\nCOMMAND_DESCRIPTION_WARPS: 'Open the warps menu.'\nCOMMAND_DESCRIPTION_WITHDRAW: 'Withdraw money from your island''s bank into your personal account.'\nCOMMAND_USAGE: '&cUsage: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lIsland | &7{0} added {1} as a co-op member.'\nCOOP_BANNED_PLAYER: '&c&lError | &7This player is banned from the island and cannot be coop.'\nCOOP_LIMIT_EXCEED: '&c&lError | &7You reached the maximum amount of coop players the island can have.'\nCREATE_ISLAND: '&e&lIsland | &7Created a new island at {0} in {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lError | &7An error occurred while creating your island. Please contact the administrator to investigate the issue.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Toggled debug mode &cOFF&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Toggled debug mode &aON&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lIsland | &7You deleted the warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oThere was a sign for that warp, it got broken...'\nDEMOTE_LEADER: '&c&lError | &7You cannot demote island leaders.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only demote players with a lower island role than yours.'\nDEMOTED_MEMBER: '&e&lIsland | &7You demoted {0} to a {1} in his island.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} deposited ${1} into the island bank!'\nDEPOSIT_ERROR: '&c&lError | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lError | &7You cannot destroy outside of your protection range.'\nDISBAND_ANNOUNCEMENT: '&e&lIsland | &7Your island was disbanded by {0}.'\nDISBAND_GIVE: '&e&lIsland | &7You received {0} disbands.'\nDISBAND_GIVE_ALL: '&e&lIsland | &7You gave {0} disbands to all players.'\nDISBAND_GIVE_OTHER: '&e&lIsland | &7You gave {0} disbands to {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank'\nDISBAND_SET: '&e&lIsland | &7Your disband count was set to {0}.'\nDISBAND_SET_ALL: '&e&lIsland | &7You set the disband count of all players to {0}.'\nDISBAND_SET_OTHER: '&e&lIsland | &7You set {0}''s disband count to {1}.'\nDISBANDED_ISLAND: '&e&lIsland | &7You disbanded your island.'\nDISBANDED_ISLAND_OTHER: '&e&lIsland | &7You disbanded {0}''s island.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lIsland | &7You disbanded the island {0}.'\nENTER_PVP_ISLAND: '&7&oYou were teleported into an island that has PVP enabled. You are immuned to PVP for the next 10 seconds...'\nEXPELLED_PLAYER: '&e&lIsland | &7{0} was expelled from the island.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: 'seconds'\nFORMAT_SECOND_NAME: 'second'\nFORMAT_MINUTES_NAME: 'minutes'\nFORMAT_MINUTE_NAME: 'minute'\nFORMAT_HOURS_NAME: 'hours'\nFORMAT_HOUR_NAME: 'hour'\nFORMAT_DAYS_NAME: 'days'\nFORMAT_DAY_NAME: 'day'\nGENERATOR_CLEARED: '&e&lIsland | &7Successfully cleared the generator amounts for {0}''s island.'\nGENERATOR_CLEARED_NAME: '&e&lIsland | &7Successfully cleared the generator amounts for the island of {0}.'\nGENERATOR_CLEARED_ALL: '&e&lIsland | &7Successfully cleared the generator amounts for all the islands.'\nGENERATOR_UPDATED: '&e&lIsland | &7Successfully updated the generator amount of {0} to {1}''s island.'\nGENERATOR_UPDATED_NAME: '&e&lIsland | &7Successfully updated the generator amount of {0} to the island of {1}.'\nGENERATOR_UPDATED_ALL: '&e&lIsland | &7Successfully updated the generator amount of {0} to all the islands.'\nGLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the message!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the message!'\nGLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!'\nGLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!'\nGOT_BANNED: '&e&lIsland | &7You were BANNED from {0}''s island.'\nGOT_DEMOTED: '&e&lIsland | &7You were demoted to a {0} in your island.'\nGOT_EXPELLED: '&e&lIsland | &7&oYou were expelled from the island by {0}.'\nGOT_INVITE: '&e&lIsland | &7{0} invited you to his island.'\nGOT_INVITE_TOOLTIP: '&7Click the message in order to accept the invite.'\nGOT_KICKED: '&e&lIsland | &7You were kicked from your island by {0}.'\nGOT_PROMOTED: '&e&lIsland | &7You were promoted to a {0} in your island.'\nGOT_REVOKED: '&e&lIsland | &7{0} revoked your invitation to his island.'\nGOT_UNBANNED: '&e&lIsland | &7You were UNBANNED from {0}''s island.'\nHIT_ISLAND_MEMBER: '&c&lError | &7You cannot hit your island members.'\nHIT_PLAYER_IN_ISLAND: '&c&lError | &7You cannot hit players inside islands.'\nIGNORED_ISLAND: '&e&lIsland | &7{0}''s island is now ignored from top islands.'\nIGNORED_ISLAND_NAME: '&e&lIsland | &7The island {0} is now ignored from top islands.'\nINTERACT_OUTSIDE_ISLAND: '&c&lError | &7You cannot interact outside of your protection range.'\nINVALID_AMOUNT: '&c&lError | &7Invalid amount {0}.'\nINVALID_BIOME: '&c&lError | &7Invalid biome {0}.'\nINVALID_BLOCK: '&c&lError | &7Invalid block location {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lError | &7Invalid effect {0}.'\nINVALID_ENTITY: '&c&lError | &7Invalid entity {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.'\nINVALID_ISLAND: '&c&lError | &7You don''t have an island.'\nINVALID_ISLAND_LOCATION: '&c&lError | &7There is no island in your location.'\nINVALID_ISLAND_OTHER: '&c&lError | &7{0} doesn''t have an island.'\nINVALID_ISLAND_OTHER_NAME: '&c&lError | &7There is no island with the name {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lError | &7Couldn't find the island permission {0}.\n  &c&lError | &7Island Permissions: {1}\nINVALID_LEVEL: '&c&lError | &7Invalid level {0}.'\nINVALID_LIMIT: '&c&lError | &7Invalid limit {0}.'\nINVALID_MATERIAL: '&c&lError | &7Invalid material {0}.'\nINVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lError | &7Invalid mission {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lError | &7Invalid module {0}.'\nINVALID_MULTIPLIER: '&c&lError | &7Invalid multiplier {0}.'\nINVALID_PAGE: '&c&lError | &7Invalid page {0}.'\nINVALID_PERCENTAGE: '&c&lError | &7Percentage must be between 0 and 100.'\nINVALID_PLAYER: '&c&lError | &7Cannot find a player called {0}'\nINVALID_RATE: |\n  &c&lError | &7Couldn't find a rating with the name {0}.\n  &c&lError | &7Island Ratings: {1}\nINVALID_ROWS: '&c&lError | &7Invalid amount of rows: {0}'\nINVALID_ROLE: |\n  &c&lError | &7Couldn't find the island role {0}.\n  &c&lError | &7Island Roles: {1}\nINVALID_SCHEMATIC: '&c&lError | &7Couldn''t find a schematic with the name {0}.'\nINVALID_SETTINGS: |\n  &c&lError | &7Couldn't find the island settings {0}.\n  &c&lError | &7Island Settings: {1}\nINVALID_SIZE: '&c&lError | &7Invalid size {0}.'\nINVALID_SLOT: '&c&lError | &7Invalid slot {0}.'\nINVALID_TITLE: '&c&lError | &7Invalid title entered.'\nINVALID_TOGGLE_MODE: '&c&lError | &7Cannot toggle {0}.'\nINVALID_UPGRADE: |\n  &c&lError | &7Couldn't find an upgrade called {0}.\n  &c&lError | &7Upgrades: {1}\nINVALID_VISIT_LOCATION: '&c&lError | &7This island has no visitors location.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oYou have bypass mode, teleporting you to the island...'\nINVALID_WARP: '&c&lError | &7Invalid warp {0}.'\nINVALID_WORLD: '&c&lError | &7Invalid world {0}.'\nINVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} invited {1} to the island.'\nINVITE_BANNED_PLAYER: '&c&lError | &7This player is banned from the island and cannot get invited.'\nINVITE_TO_FULL_ISLAND: '&c&lError | &7You cannot invite more members to your island.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lError | &7An island with that name already exists.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBank | &7Island bank is empty.'\nISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7The island {0} has ${1}.'\nISLAND_BEING_CALCULATED: '&c&lError | &7You cannot interact with blocks when island is being recalculated!'\nISLAND_CLOSED: '&e&lIsland | &7Successfully closed the island to the public.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lFly | &7Island fly was automatically &cdisabled&7.'\nISLAND_FLY_ENABLED: '&e&lFly | &7Island fly was automatically &aenabled&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsland | &7&oYou had been inside an island that been disbanded, so you were teleported back to spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIsland | &7&oYou had been inside an island that had turned pvp on, so you were teleported back to spawn...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Developed by Ome_R'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Commands List [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Use /is help {0} for the next page.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsland | &7Bank Limit: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lIsland | &7Blocks Limits:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsland | &7Coop Limit: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsland | &7Crops Multiplier: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsland | &7Drops Multiplier: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIsland | &7Island Effects:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIsland | &7Entities Limits:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lIsland | &7Generator Rates ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsland | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIsland | &7Role Limits:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lIsland | &7Border Size: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsland | &7Spawners Multiplier: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsland | &7Team Limit: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lIsland | &7Upgrades:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsland | &7Warps Limit: {0}'\nISLAND_INFO_BANK: '&e&lIsland | &7Bank: {0}'\nISLAND_INFO_BONUS: '&e&lIsland | &7Worth Bonus: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIsland | &7Level Bonus: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIsland | &7Creation Time: {0}'\nISLAND_INFO_DISCORD: '&e&lIsland | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lIsland | &7Last Time Updated: {0} ago'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsland | &7Last Time Updated: &aCurrently Active'\nISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}'\nISLAND_INFO_LOCATION: '&e&lIsland | &7Home: {0}'\nISLAND_INFO_NAME: '&e&lIsland | &7Name: {0}'\nISLAND_INFO_OWNER: '&e&lIsland | &7Leader: {0}'\nISLAND_INFO_PAYPAL: '&e&lIsland | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lIsland | &7 - {0}'\nISLAND_INFO_RATE: '&e&lIsland | &7Rate: {0} &7({1}/5) - {2} total ratings.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lIsland | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lIsland | &7Worth: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIsland | &7Successfully opened the island to the public.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.'\nISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM'\nISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lPreview | &7You started the preview mode for the schematic {0}.\n  &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode.\n  &e&lPreview | &7You cannot leave the area of the island, otherwise the preview mode will be cancelled automatically.\nISLAND_PROTECTED: '&c&lError | &7This island is protected.'\nISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lIsland | &7Members of {0}''s Island &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Online)'\nISLAND_TEAM_STATUS_ROLES: '&e&lIsland | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TOP_STATUS_ONLINE: '&a(Online)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Private]'\nISLAND_WAS_CLOSED: '&e&lIsland | &7&oThe island you were in was closed and you were teleported back to spawn...'\nISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.'\nISLAND_WORTH_RESULT: '&e&lIsland | &7Your island worth is {0} [Level {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lIsland | &7{0} has joined your island.'\nJOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} has joined your island.'\nJOIN_FULL_ISLAND: '&c&lError | &7This island reached the maximum amount of allowed members.'\nJOIN_WHILE_IN_ISLAND: '&c&lError | &7You are already inside an island.'\nJOINED_ISLAND: '&e&lIsland | &7You joined {0}''s island.'\nJOINED_ISLAND_NAME: '&e&lIsland | &7You joined the island {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lIsland | &7You are now a co-op member of {0}''s island.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lIsland | &7You are now a co-op member of the island {0}.'\nKICK_ANNOUNCEMENT: '&e&lIsland | &7{0} was kicked from the island by {1}.'\nKICK_ISLAND_LEADER: '&c&lError | &7You cannot kick the leader of the island, use /is admin disband instead.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only kick players with a lower island role than yours.'\nLACK_CHANGE_PERMISSION: '&c&lError | &7You must have this permission in order to change it to other roles.'\nLAST_ROLE_DEMOTE: '&c&lError | &7You cannot demote this player anymore.'\nLAST_ROLE_PROMOTE: '&c&lError | &7You cannot promote this player anymore.'\nLEAVE_ANNOUNCEMENT: '&e&lIsland | &7{0} left the island.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lError | &7You cannot leave your island when you own it.\n  &c&lError | &7You can transfer the ownership using /is transfer.\nLEFT_ISLAND: '&e&lIsland | &7You left your island.'\nLEFT_ISLAND_COOP: '&e&lIsland | &7You are no longer a co-op member of {0}''s island.'\nLEFT_ISLAND_COOP_NAME: '&e&lIsland | &7You are no longer a co-op member of the island {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lError | &7You must provide a solid material.'\nMAXIMUM_LEVEL: '&c&lError | &7The maximum level for this upgrade is {0}.'\nMESSAGE_SENT: '&e&lIsland | &7Successfully sent {0} the message!'\nMISSION_CANNOT_COMPLETE: '&c&lError | &7You cannot complete this mission yet.'\nMISSION_NO_AUTO_REWARD: '&e&lMission | &7You have all the required materials to finish {0} - use /is missions to complete!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7You must complete {0} before completing this mission.'\nMISSION_STATUS_COMPLETE: '&e&lMission | &7Changed the status of the mission {0} to completed for {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Changed the status of all the missions to completed for {0}.'\nMISSION_STATUS_RESET: '&e&lMission | &7Reset the status of the mission {0} for {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMission | &7Reset the status of all the missions for {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.'\nMODULE_INFO: |\n  &e&lModule | &7{0} by {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.'\nMODULES_LIST: '&fModules ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lError | &7You cannot use that name.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.'\nNAME_TOO_LONG: '&c&lError | &7Island names cannot be more than {0} chars long.'\nNAME_TOO_SHORT: '&c&lError | &7Island names cannot be less than {0} chars long.'\nNO_BAN_PERMISSION: '&c&lError | &7You must be at least {0} in order to ban players.'\nNO_CLOSE_BYPASS: '&c&lError | &7This island is not opened to the public.'\nNO_CLOSE_PERMISSION: '&c&lError | &7You must be at least {0} in order to close the island to the public.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lError | &7You must be at least {0} in order to add players as co-op members.'\nNO_DELETE_WARP_PERMISSION: '&c&lError | &7You must be at least {0} in order to delete warps.'\nNO_DEMOTE_PERMISSION: '&c&lError | &7You must be at least {0} in order to demote players.'\nNO_DEPOSIT_PERMISSION: '&c&lError | &7You must be at least {0} in order to deposit money to island bank.'\nNO_DISBAND_PERMISSION: '&c&lError | &7You must be at least {0} in order to disband your island.'\nNO_EXPEL_PERMISSION: '&c&lError | &7You must be at least {0} in order to expel players from your island.'\nNO_INVITE_PERMISSION: '&c&lError | &7You must be at least {0} in order to invite players.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lError | &7You must be at least {0} in order to access the island''s chest.'\nNO_ISLAND_INVITE: '&c&lError | &7Could not find any invites from this island.'\nNO_ISLANDS_TO_PURGE: '&c&lError | &7There were no islands to purge.'\nNO_KICK_PERMISSION: '&c&lError | &7You must be at least {0} in order to kick players.'\nNO_MORE_DISBANDS: '&c&lError | &7You can''t disband any more islands.'\nNO_MORE_WARPS: '&c&lError | &7Your island can''t have any more warps.'\nNO_NAME_PERMISSION: '&c&lError | &7You cannot change the name of your island.'\nNO_OPEN_PERMISSION: '&c&lError | &7You must be at least {0} in order to open the island to the public.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7You must be at least {0} in order to get information about permissions.'\nNO_PROMOTE_PERMISSION: '&c&lError | &7You must be at least {0} in order to promote players.'\nNO_RANKUP_PERMISSION: '&c&lError | &7You must be at least {0} in order to rankup upgrades.'\nNO_RATINGS_PERMISSION: '&c&lError | &7You must be at least {0} in order to check ratings.'\nNO_SET_BIOME_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island biome.'\nNO_SET_DISCORD_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island discord.'\nNO_SET_HOME_PERMISSION: '&c&lError | &7You must be at least {0} in order to set the teleport location of the island.'\nNO_SET_PAYPAL_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island paypal email.'\nNO_SET_ROLE_PERMISSION: '&c&lError | &7You must be at least {0} in order to set roles for players.'\nNO_SET_SETTINGS_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island settings.'\nNO_SET_WARP_PERMISSION: '&c&lError | &7You must be at least {0} in order to set island warps.'\nNO_TRANSFER_PERMISSION: '&c&lError | &7You must be the island''s leader in order to transfer the leadership.'\nNO_UNCOOP_PERMISSION: '&c&lError | &7You must be at least {0} in order to remove players from being co-op members.'\nNO_UPGRADE_PERMISSION: '&c&lError | &7You are lacking the permission to upgrade into another level.'\nNO_WITHDRAW_PERMISSION: '&c&lError | &7You must be at least {0} in order to withdraw money from island bank.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7You don''t have enough money to deposit {0} dollars into your island''s bank.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7You don''t have enough money.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oYou''re too tired to interact with menus, don''t you think?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Toggled island panel &cOFF&7.\n  &e&lPanel | &7Running /is will teleport you to the island.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Toggled island panel &aON&7.\n  &e&lPanel | &7Running /is will open the panel for you.\nPERMISSION_CHANGED: '&e&lIsland | &7Successfully updated the permission {0} of {1}''s island.'\nPERMISSION_CHANGED_NAME: '&e&lIsland | &7Successfully updated the permission {0} of the island {1}.'\nPERMISSION_CHANGED_ALL: '&e&lIsland | &7Successfully updated the permission {0} for all the islands.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!'\nPERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lError | &7This player is already banned.'\nPLAYER_ALREADY_COOP: '&c&lError | &7This player is already coop.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lError | &7This player is already inside an island.'\nPLAYER_ALREADY_IN_ROLE: '&c&lError | &7{0} is already a {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lError | &7This user cannot be expelled from the island.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} joined the server.'\nPLAYER_NOT_BANNED: '&c&lError | &7This player is not banned.'\nPLAYER_NOT_COOP: '&c&lError | &7This player is not co-op.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7This player is not inside your island.'\nPLAYER_NOT_ONLINE: '&c&lError | &7This player is not online!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lIsland | &7{0} left the server.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only promote players with a lower island role than yours.'\nPROMOTED_MEMBER: '&e&lIsland | &7You promoted {0} to a {1} in his island.'\nPURGE_CLEAR: '&e&lIsland | &7Successfully cleared all the queued islands to be purged.'\nPURGED_ISLANDS: |-\n  &e&lIsland | &7{0} islands will be purged when server restarts.\n  &e&lIsland | &7You can cancel it anytime using /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.'\nRANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.'\nRANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lIsland | &7{0} has rated your island {1} out of 5!.'\nRATE_CHANGE_OTHER: '&e&lIsland | &7You changed the rating of {0} to {1}.'\nRATE_OWN_ISLAND: '&c&lError | &7You can''t rate your own island.'\nRATE_REMOVE_ALL: '&e&lIsland | &7Successfully removed all ratings of {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.'\nRATE_SUCCESS: '&e&lIsland | &7You rated this island with {0} stars!'\nREACHED_BLOCK_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for {0} Block.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lError | &7Your island is already being recalculated.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7This island is already being recalculated.'\nRECALC_ALL_ISLANDS: '&e&lIsland | &7Recalculating all islands...'\nRECALC_ALL_ISLANDS_DONE: '&e&lIsland | &7Successfully finished recalculating all islands.'\nRECALC_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...'\nRELOAD_COMPLETED: '&e&lIsland | &7Reload is finished!'\nRELOAD_PROCCESS_REQUEST: '&e&lIsland | &7Starting to reload configurations...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} revoked the invitation of {1} to the island.'\nRESET_SETTINGS: '&e&lIsland | &7Successfully reset island settings for {0}''s island.'\nRESET_SETTINGS_ALL: '&e&lIsland | &7Successfully reset island settings for all the islands.'\nRESET_SETTINGS_NAME: '&e&lIsland | &7Successfully reset island settings for all the islands.'\nRESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.'\nSAME_NAME_CHANGE: '&c&lError | &7You must enter a different name from your current island name.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Selected position #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lError | &7You haven''t selected two positions.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Processing your request...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematics | &7You have selected two positions. Run /is admin schematic <name> to create a new schematic.\n  &e&lSchematics | &7Make sure you stand at the teleportation location when executing the command.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Selected position #1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematics | &7Successfully saved schematic!'\nSELF_ROLE_CHANGE: '&c&lError | &7You cannot change the role of yourself.'\nSET_UPGRADE_LEVEL: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}''s island.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}.'\nSET_WARP: '&e&lIsland | &7Successfully created a new warp at {0}.'\nSET_WARP_OUTSIDE: '&c&lError | &7You cannot set warps outside your island.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lIsland | &7Successfully updated the settings {0} to {1}''s island.'\nSETTINGS_UPDATED_NAME: '&e&lIsland | &7Successfully updated the settings {0} to the island {1}.'\nSETTINGS_UPDATED_ALL: '&e&lIsland | &7Successfully updated the settings {0} to all the islands.'\nSIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}''s island.'\nSYNC_UPGRADES_ALL: '&e&lUpgrades | &7Successfully synced all upgrade values of all the islands.'\nSYNC_UPGRADES_NAME: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7You are not inside your island.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lError | &7You cannot teleport outside of your protection range.'\nTELEPORT_WARMUP: '&7&oYou will be teleported in {0}... Do not move!'\nTELEPORT_WARMUP_CANCEL: '&7&oYou moved and so the teleportation was cancelled.'\nTITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!'\nTELEPORTED_FAILED: '&e&lIsland | &7It seems like this island has no safe blocks. Please contact a staff member.'\nTELEPORTED_SUCCESS: '&e&lIsland | &7You were teleported to your island.'\nTELEPORTED_TO_WARP: '&e&lIsland | &7Successfully teleported to this island warp.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Toggled bypass mode &cOFF&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Toggled bypass mode &aON&7.'\nTOGGLED_FLY_OFF: '&e&lFly | &7Toggled island fly &cOFF&7.'\nTOGGLED_FLY_ON: '&e&lFly | &7Toggled island fly &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Toggling schematic mode &cOFF&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchematics | &7Toggling schematic mode &aON&7.\n  &e&lSchematics | &7Select an area using a golden axe.\nTOGGLED_SPY_OFF: '&e&lSpy | &7Toggled spy chat &cOFF&7.'\nTOGGLED_SPY_ON: '&e&lSpy | &7Toggled spy chat &aON&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Toggling blocks stacker &cOFF&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Toggling blocks stacker &aON&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Toggling team chat &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Toggling team chat &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Toggling world border &cOFF&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Toggling world border &aON&7.'\nTRANSFER_ADMIN: '&e&lIsland | &7You transferred {0}''s leadership to {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} is already the leader of his island.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7These players are not in the same islands.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7This player is not a leader of any islands.'\nTRANSFER_ALREADY_LEADER: '&c&lError | &7You''re already the leader of this island.'\nTRANSFER_BROADCAST: '&e&lIsland | &7The island''s leadership has been transferred to {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lIsland | &7{0} was UNBANNED from the island by {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lIsland | &7{0} removed {1} from being a co-op member.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsland | &7{0} left the game and is no longer a co-op member.'\nUNIGNORED_ISLAND: '&e&lIsland | &7{0}''s island is now un-ignored from top islands.'\nUNIGNORED_ISLAND_NAME: '&e&lIsland | &7The island {0} is now un-ignored from top islands.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lIsland | &7&oLooks like this warp is unsafe. Please try another warp.'\nUPDATED_PERMISSION: '&e&lIsland | &7Updated permissions for {0}.'\nUPDATED_SETTINGS: '&e&lIsland | &7Updated the island settings {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lError | &7You cannot use that command on other islands.'\nWARP_ALREADY_EXIST: '&c&lError | &7There is already a warp with this name.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.'\nWARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.'\nWARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.'\nWARP_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBank | &7Island bank has only {0} dollars inside it.\n  &e&lBank | &7&oWithdrawing all money...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!'\nWITHDRAW_ERROR: '&c&lError | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!'\nWITHDRAWN_MONEY_NAME: '&e&lBank | &7You withdrawn ${0} from the island bank of {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lWorlds | &7The {0} world is not unlocked yet!'\n"
  },
  {
    "path": "src/main/resources/lang/es-ES.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##              Desarrollado por Ome_R              ##\n##                Traducido por Aymac               ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIsla | &7Añadiste al jugador {0} a la isala de {1}'\nADMIN_ADD_PLAYER_NAME: '&e&lIsla | &7Añadiste al jugador {0} a la isala de {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBanco | &7Has depositado ${0} en el banco de la isla de {1}'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBanco | &7Has depositado${0} en el banco de la isla de {1}.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desarrollado por Ome_R - Traducido al español por: Aymac'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de comandos de administrador [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is admin {0} para la página siguiente.'\nALREADY_IN_ISLAND: '&c&lError | &7Ya estas en una isla.'\nALREADY_IN_ISLAND_OTHER: '&c&lError | &7Este jugador ya es miembro de tu isla.'\nBAN_ANNOUNCEMENT: '&e&lIsla | &7{0} fue baneado de la isla por: {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes banear jugadores con un rol de isla más bajo que el tuyo.'\nBANK_DEPOSIT_CUSTOM: '&e&lBanco | &7Escriba la cantidad que desea depositar:'\nBANK_DEPOSIT_COMPLETED: 'Depósito completado'\nBANK_LIMIT_EXCEED: '&c&lError | &7Has excedido tu límite bancario.'\nBANK_WITHDRAW_CUSTOM: '&e&lBanco | &7Escriba la cantidad que desea retirar:'\nBANK_WITHDRAW_COMPLETED: 'Retiro completado'\nBANNED_FROM_ISLAND: '&c&lError | &7Estás prohibido en esta isla.'\nBLOCK_COUNT_CHECK: '&e&lIsla | &7Esta isla tiene x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIsla | &7Esta isla tiene los siguientes bloques:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIsla | &7Esta isla no tiene bloques comprobados.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lNivel | &7El nivel del bloque {0} es {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lNivel | &7El bloque {0} no tiene valor.'\nBLOCK_VALUE: '&e&lValor | &7El bloque {0} vale {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lValor | &7El bloque {0} no tiene valor.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Blue'\nBORDER_PLAYER_COLOR_NAME_RED: 'Red'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Green'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBorde | &7Cambió con éxito el color de su borde personal a {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lError | &7No puede construir fuera de su rango de protección.'\nCANNOT_SET_ROLE: '&c&lError | &7No puedes establecer el rol del jugador en {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7Solo puedes cambiar los permisos a un rol de isla más bajo que el suyo.'\nCHANGED_BANK_LIMIT: '&e&lMejoras| &7Se actualizó correctamente el límite bancario de la isla de {0} '\nCHANGED_BANK_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite bancario de todas las islas.'\nCHANGED_BANK_LIMIT_NAME: '&e&lMejoras| &7Se actualizó con éxito el límite bancario de {0}.'\nCHANGED_BIOME: '&e&lIsla | &7Bioma cambiado correctamente a {0}. Es posible que deba volver a conectarse al servidor para ver los cambios.'\nCHANGED_BIOME_ALL: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para todas las islas.'\nCHANGED_BIOME_NAME: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para la isla {1}.'\nCHANGED_BIOME_OTHER: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para la isla de {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBloques | &7Cambió correctamente la cantidad de bloques en {0} a {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lMejoras| &Se actualizó correctamente el límitede bloques de {1} a {0}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lMejoras| &7Se actualizó correctamente el límitede bloques de todas las islas a {0}.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de bloques de {1} a {0}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para la isla de {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para todas las islas.'\nCHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para {2}.'\nCHANGED_COOP_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de la isla de {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de todas las islas.'\nCHANGED_COOP_LIMIT_NAME: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de {0}.'\nCHANGED_CROP_GROWTH: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de crecimiento de cultivos de la isla de {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de crecimiento de cultivos de todas las islas.'\nCHANGED_CROP_GROWTH_NAME: '&e&lMejoras| &7Se actualizó correctamente el multiplicador de crecimiento de cultivos de {0}.'\nCHANGED_DISCORD: '&e&lIsla | &7Se cambió la discord de la isla a {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para la isla de {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para todas las islas.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lMejoras| &7Se actualizó con éxito el nivel del efecto de isla {0} para la isla de {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lMejoras| &7Se actualizó con éxito el nivel del efecto de isla {0} para todas las islas.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel del efecto isla {0} para {1}.'\nCHANGED_ISLAND_SIZE: '&e&lMejoras| &7Se actualizó correctamente el tamaño de la isla de {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lMejoras| &7Se actualizó con éxito el tamaño de la isla de todas las islas.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lMejoras| &7Se actualizó correctamente el tamaño de la isla de {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oLos jugadores pueden construir fuera de su isla, por lo que el tamaño de la isla no afecta. Puede desactivar esa función en la configuración para que el tamaño de la isla tenga efecto nuevamente.'\nCHANGED_LANGUAGE: '&e&lIdioma/Language | &7Cambió correctamente su idioma al inglés/Successfully changed your language to English.'\nCHANGED_MOB_DROPS: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de la isla de {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de todas las islas.'\nCHANGED_MOB_DROPS_NAME: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de {0}.'\nCHANGED_NAME: '&e&lIsla | &7Cambiaste el nombre de tu isla a {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIsla | &7Cambiaste el nombre de la {0} isla a {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIsla | &7Cambiaste el nombre de {0}&7 a {1}&7.'\nCHANGED_PAYPAL: '&e&lIsla | &7Se cambió el PayPal de la isla {0}.'\nCHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.'\nCHANGED_SPAWNER_RATES: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de la isla de {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de todas las islas.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de {0}.'\nCHANGED_TEAM_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de equipo de la isla de {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de equipo de todas las islas..'\nCHANGED_TEAM_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de equipo de {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lIsla | &7Ubicación de teletransporte actualizada con éxito.'\nCHANGED_WARPS_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de la isla de {0}.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de todas las islas.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de warps de {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: 'cantidad'\nCOMMAND_ARGUMENT_BIOME: 'bioma'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: 'command...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: 'discord...'\nCOMMAND_ARGUMENT_EFFECT: 'pefecto-de-poción'\nCOMMAND_ARGUMENT_EMAIL: 'email'\nCOMMAND_ARGUMENT_ENTITY: 'entidad'\nCOMMAND_ARGUMENT_ISLAND_NAME: 'nombre-de-isla'\nCOMMAND_ARGUMENT_ISLAND_ROLE: 'rol-de-isla'\nCOMMAND_ARGUMENT_LEADER: 'líder'\nCOMMAND_ARGUMENT_LEVEL: 'nivel'\nCOMMAND_ARGUMENT_LIMIT: 'límite'\nCOMMAND_ARGUMENT_MATERIAL: 'material'\nCOMMAND_ARGUMENT_MENU: 'nombre-del-menu'\nCOMMAND_ARGUMENT_MESSAGE: 'mensaje...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: 'nombre-de-misión'\nCOMMAND_ARGUMENT_MODULE_NAME: 'module-name'\nCOMMAND_ARGUMENT_MULTIPLIER: 'multiplicador'\nCOMMAND_ARGUMENT_NAME: 'nombre'\nCOMMAND_ARGUMENT_NEW_LEADER: 'nuevo-lider'\nCOMMAND_ARGUMENT_PAGE: 'página'\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: 'permiso'\nCOMMAND_ARGUMENT_PLAYER_NAME: 'nombre-de-jugador'\nCOMMAND_ARGUMENT_PRIVATE: 'privado'\nCOMMAND_ARGUMENT_RATING: 'clasificacion'\nCOMMAND_ARGUMENT_ROWS: 'fila'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: 'nombre-schematic'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: 'configuracion'\nCOMMAND_ARGUMENT_SIZE: 'tamaño'\nCOMMAND_ARGUMENT_TIME: 'tiempo'\nCOMMAND_ARGUMENT_TITLE_DURATION: 'duration'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out'\nCOMMAND_ARGUMENT_UPGRADE_NAME: 'nombre-de-mejora'\nCOMMAND_ARGUMENT_VALUE: 'valor'\nCOMMAND_ARGUMENT_WARP_NAME: 'nombre-delwarp'\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category'\nCOMMAND_ARGUMENT_WORLD: 'mundo'\nCOMMAND_COOLDOWN_FORMAT: '&c&lError | &7Solo puede usar el comando en {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: 'Aceptar una invitación de un jugador.'\nCOMMAND_DESCRIPTION_ADMIN: 'Utilice los comandos de administrador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Añadir un usuario a una isla.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumenta el límite de bloques para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Añadir un bono a un jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumentar el límite de jugadores cooperativos para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Aumenta el multiplicador de crecimiento de cultivos para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Agrega un efecto de isla para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Aumentar el límite de entidades para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Agregue porcentaje de un material para el generador de adoquines.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Aumenta el multiplicador de drop de los mobs para la isla de otro jugador..'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expande el tamaño de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Aumenta el multiplicador de las tasas de spawn de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Aumentar el límite de miembros para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Aumentar el límite de warps de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: 'Otorga una bonificación a un jugador.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: 'Alternar el modo de bypass'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Cofre de isla abierta de otra isla.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Limpia las tasas de spawn para una isla específica.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: 'Cerrar una isla al público.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Verifique un recuento de bloques en una isla específica.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Alternar debug outputs.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Elimina un warp de una isla'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Degradar a un miembro en la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposite dinero en el banco de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: 'Borra la isla de otro jugador de forma permanente.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Permite que un jugador borre la isla.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: 'Hace que la isla ingnore el Top Islas'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: 'Únete a una isla sin invitación.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Echa a un jugador de su isla'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: 'Cambiar el estado de una misión para un jugador.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: 'Envía un mensaje a un jugador sin prefijos/prefix.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Envíe a todos los miembros de la isla un mensaje sin prefijos/prefixes.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: 'Cambia el nombre de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: 'Abrir una isla al público.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Abre un menú personalizado para un jugador..'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promocionar a un miembro en la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: 'Purgar islas &7(&cCuidado!&7)'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir de rango una mejora para una isla.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: 'Vuelve a calcular el valor de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarga todas las configuraciones y tareas del plugin/complemento.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Eliminar el límite de bloques de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Eliminar todas las calificaciones dadas por un jugador.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Cree schematics para el plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Establecer el bioma de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Establece una cantidad de bloques en una ubicación específica.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Establecer límite de bloques para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Establece las filas de los cofres para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Establece un límite de jugadores cooperativos para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Establezca el multiplicador de crecimiento de cultivos para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Establece la cantidad de islas disueltas de un jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Establece el nivel de efecto de isla de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Establece límite de entidades para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfiere una isla a otra persona.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Establece el multiplicador de drop de los mobs para la isla de otro jugador'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Establezca un rol obligatorio para obtener un permiso para todas las islas.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Establece la calificación de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Alternar la configuración de una isla específica.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Cambiar el porcentaje de un material para el generador de adoquines.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Cambia el tamaño de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Establezca la ubicación de spawn del servidor.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Establezca el multiplicador de tasas de spawn para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Establecer límite de miembros para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Establece el nivel de una mejora para la isla de otro jugador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Establece el límite de warps de una isla.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Abra el editor de configuración del plugin'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: 'Obtén información sobre una isla.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teletransportarse a la ubicación de spawn'\nCOMMAND_DESCRIPTION_ADMIN_SPY: 'Alternar el modo espía de chat'\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Mostrar estadísticas sobre el plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sincronizar valores de actualización para una isla.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teletransportarse a otras islas.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Ignora una isla de las islas superiores.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Desbloquea un mundo para una isla.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinero del banco de la isla de otro jugador.'\nCOMMAND_DESCRIPTION_BALANCE: 'Verifique la cantidad de dinero dentro del banco de una isla.'\nCOMMAND_DESCRIPTION_BAN: 'Prohibir a un jugador de tu isla.'\nCOMMAND_DESCRIPTION_BANK: 'Abre el banco de la isla.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: 'Cambia el bioma de la isla.'\nCOMMAND_DESCRIPTION_BORDER: 'Cambia el color del borde de las islas.'\nCOMMAND_DESCRIPTION_CHEST: 'Abre el cofre de la isla.'\nCOMMAND_DESCRIPTION_CLOSE: 'Cerrar la isla al público.'\nCOMMAND_DESCRIPTION_COOP: 'Agrega un jugador como cooperativo a tu isla.'\nCOMMAND_DESCRIPTION_COOPS: 'Abre el menú cooperativo.'\nCOMMAND_DESCRIPTION_COUNTS: 'Ver la cantidad de bloques de tu isla.'\nCOMMAND_DESCRIPTION_CREATE: 'Crea una nueva isla.'\nCOMMAND_DESCRIPTION_DEL_WARP: 'Elimina un warp de la isla'\nCOMMAND_DESCRIPTION_DEMOTE: 'Degradar a un miembro en tu isla.'\nCOMMAND_DESCRIPTION_DEPOSIT: 'Deposite dinero de su cuenta personal en el banco de la isla.'\nCOMMAND_DESCRIPTION_DISBAND: 'Disuelve tu isla de forma permanente.'\nCOMMAND_DESCRIPTION_EXPEL: 'Echa un visitante de tu isla.'\nCOMMAND_DESCRIPTION_FLY: 'Alternar el vuelo dentro de la isla.'\nCOMMAND_DESCRIPTION_HELP: 'Lista de todos los comandos.'\nCOMMAND_DESCRIPTION_INVITE: 'Invita a un jugador a tu isla.'\nCOMMAND_DESCRIPTION_KICK: 'Echa un jugador de tu isla.'\nCOMMAND_DESCRIPTION_LANG: 'Cambia tu idioma personal.'\nCOMMAND_DESCRIPTION_LEAVE: 'Deja tu isla.'\nCOMMAND_DESCRIPTION_MEMBERS: 'Abra el menú de miembros.'\nCOMMAND_DESCRIPTION_MISSION: 'Completa una misión.'\nCOMMAND_DESCRIPTION_MISSIONS: 'Abre el menú de misiones'\nCOMMAND_DESCRIPTION_NAME: 'Cambia el nombre de tu isla.'\nCOMMAND_DESCRIPTION_OPEN: 'Abra la isla al público.'\nCOMMAND_DESCRIPTION_PANEL: 'Abre el panel de la isla.'\nCOMMAND_DESCRIPTION_PARDON: 'Elimina la prohibición de un jugador de tu isla.'\nCOMMAND_DESCRIPTION_PERMISSIONS: 'Obtenga todos los permisos para un rol de isla.'\nCOMMAND_DESCRIPTION_PROMOTE: 'Asciende a un miembro en tu isla.'\nCOMMAND_DESCRIPTION_RANKUP: 'Sube de nivel una mejora.'\nCOMMAND_DESCRIPTION_RATE: 'Califica una isla.'\nCOMMAND_DESCRIPTION_RATINGS: 'Mostrar todas las clasificaciones de islas.'\nCOMMAND_DESCRIPTION_SETTINGS: 'Abre el menú de configuración.'\nCOMMAND_DESCRIPTION_RECALC: 'Vuelve a calcular el valor de la isla.'\nCOMMAND_DESCRIPTION_SET_DISCORD: 'Establece el discord de la isla para los pagos.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: 'Configure el correo electrónico de PayPal de la isla para los pagos.'\nCOMMAND_DESCRIPTION_SET_ROLE: 'Cambia el papel de un jugador en tu isla.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: 'Cambia la ubicación del teletransporte de tu isla.'\nCOMMAND_DESCRIPTION_SET_WARP: 'Crea una nueva deformación de isla.'\nCOMMAND_DESCRIPTION_SHOW: 'Obtén información sobre una isla.'\nCOMMAND_DESCRIPTION_TEAM: 'Obtenga información sobre el estado de los miembros de la isla.'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'Alternar el modo de chat de equipo.'\nCOMMAND_DESCRIPTION_TELEPORT: 'Teletransportarse a su isla.'\nCOMMAND_DESCRIPTION_TOGGLE: 'Alternar el borde de la isla y ubicaciones del apilador de bloques.'\nCOMMAND_DESCRIPTION_TOP: 'Abre el panel de Top Islas.'\nCOMMAND_DESCRIPTION_TRANSFER: 'Transfiera el liderazgo de su isla.'\nCOMMAND_DESCRIPTION_UNCOOP: 'Elimina a un jugador cooperativo de tu isla.'\nCOMMAND_DESCRIPTION_UPGRADE: 'Abre el panel de actualizaciones.'\nCOMMAND_DESCRIPTION_VALUE: 'Obtenga el valor de un bloque.'\nCOMMAND_DESCRIPTION_VALUES: 'Abrir el menú de valores.'\nCOMMAND_DESCRIPTION_VISIT: 'Teletransportarse a la ubicación de los visitantes de una isla..'\nCOMMAND_DESCRIPTION_VISITORS: 'Abrir el menú de visitantes.'\nCOMMAND_DESCRIPTION_WARP: 'Teletransportarse al warp de una isla.'\nCOMMAND_DESCRIPTION_WARPS: 'Abre el menu de warps'\nCOMMAND_DESCRIPTION_WITHDRAW: 'Retire dinero del banco de su isla a su cuenta personal.'\nCOMMAND_USAGE: '&cUsa: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lIsla | &7{0} agregado {1} como miembro de la cooperativa.'\nCOOP_BANNED_PLAYER: '&c&lError | &7Este jugador está prohibido de la isla y no puede ser cooperativo.'\nCOOP_LIMIT_EXCEED: '&c&lError | &7Alcanzaste la cantidad máxima de jugadores cooperativos que puede tener la isla.'\nCREATE_ISLAND: '&e&lIsla | &7Creó una nueva isla en {0} en {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lError | &7Se produjo un error al crear su isla. Comuníquese con el administrador para investigar el problema.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Modo de depuración &cAPAGADO&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Modo de depuración  &aENCENDIDO&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lIsla | &7Eliminaste el warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oHabía un letrero para esa warp, pero se rompió...'\nDEMOTE_LEADER: '&c&lError | &7No se puede degradar a los líderes de las islas.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes degradar a jugadores con un rol de isla más bajo que el tuyo.'\nDEMOTED_MEMBER: '&e&lIsla | &7Has degradado a {0} a {1} en su isla.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBanco | &7{0} depositó $ {1} en el banco de la isla.'\nDEPOSIT_ERROR: '&c&lError | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lError | &7No puede destruir fuera de su rango de protección.'\nDISBAND_ANNOUNCEMENT: '&e&lIsla | &7Tu isla fue disuelta por {0}.'\nDISBAND_GIVE: '&e&lIsla | &7Recibiste {0} disoluciones.'\nDISBAND_GIVE_ALL: '&e&lIsla | &7Le diste {0} disoluciones a todos los jugadores.'\nDISBAND_GIVE_OTHER: '&e&lIsla | & 7Diste {0} disoluciones a {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank'\nDISBAND_SET: '&e&lIsla | &7Su recuento de disoluciones se estableció en {0}.'\nDISBAND_SET_ALL: '&e&lIsla | &7Establece el recuento de disolución de todos los jugadores en {0}.'\nDISBAND_SET_OTHER: '&e&lIsla | &7Establece el recuento de disolución de {0} en {1}.'\nDISBANDED_ISLAND: '&e&lIsla | &7You disbanded your island.'\nDISBANDED_ISLAND_OTHER: '&e&lIsla | &7Disolviste la isla de {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lIsla | &7Disolviste la isla {0}.'\nENTER_PVP_ISLAND: '&7&oSeras teletransportado a una isla con PVP habilitado. Seras inmune por 10 segundos...'\nEXPELLED_PLAYER: '&e&lIsla | &7{0} fue expulsado de la isla.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: 'segundos'\nFORMAT_SECOND_NAME: 'segundo'\nFORMAT_MINUTES_NAME: 'minutos'\nFORMAT_MINUTE_NAME: 'minuto'\nFORMAT_HOURS_NAME: 'horas'\nFORMAT_HOUR_NAME: 'hora'\nFORMAT_DAYS_NAME: 'dias'\nFORMAT_DAY_NAME: 'dia'\nGENERATOR_CLEARED: '&e&lIsla | &7Se borraron con éxito las cantidades del generador para la isla de {0}.'\nGENERATOR_CLEARED_NAME: '&e&lIsla | &7Borró con éxito las cantidades del generador para la isla de {0}.'\nGENERATOR_CLEARED_ALL: '&e&lIsla | &7Limpió con éxito las cantidades del generador para todas las islas.'\nGENERATOR_UPDATED: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} a la isla de {1}.'\nGENERATOR_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} a la isla de {1}.'\nGENERATOR_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} en todas las islas.'\nGLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lIsla | &7Se envió correctamente el mensaje a los miembros de la isla de {0}'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lIsla | &7¡Se envió correctamente el mensaje a los miembros de la isla de {0}!'\nGLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!'\nGLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!'\nGOT_BANNED: '&e&lIsla | &7Fuiste PROHIBIDO de la isla de {0}.'\nGOT_DEMOTED: '&e&lIsla | &7Fuiste degradado a {0} en tu isla.'\nGOT_EXPELLED: '&e&lIsla | &7&o{0} te expulsó de la isla.'\nGOT_INVITE: '&e&lIsla | &7{0} te invitó a su isla.'\nGOT_INVITE_TOOLTIP: '&7Haga click en el mensaje para aceptar la invitación.'\nGOT_KICKED: '&e&lIsla | &7{0} te echó de tu isla.'\nGOT_PROMOTED: '&e&lIsla | &7Te ascendieron a {0} en tu isla.'\nGOT_REVOKED: '&e&lIsla | &7{0} revocó su invitación a su isla.'\nGOT_UNBANNED: '&e&lIsla | &7Estas PERMTIDO nuevamente en la isla de {0}.'\nHIT_ISLAND_MEMBER: '&c&lError | &7No puedes golpear a los miembros de tu isla.'\nHIT_PLAYER_IN_ISLAND: '&c&lError | &7No puedes golpear a los jugadores dentro de las islas.'\nIGNORED_ISLAND: '&e&lIsla | &7La isla de {0} ahora ignora el TOP ISLAS '\nIGNORED_ISLAND_NAME: '&e&lIsla | &7La isla de {0} ahora ignora el TOP ISLAS'\nINTERACT_OUTSIDE_ISLAND: '&c&lError | &7No puede interactuar fuera de su rango de protección.'\nINVALID_AMOUNT: '&c&lError | &7Cantidad no válida {0}.'\nINVALID_BIOME: '&c&lError | &7Bioma no válido {0}.'\nINVALID_BLOCK: '&c&lError | &7Ubicación de bloque no válida {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lError | &7Efecto no válido {0}.'\nINVALID_ENTITY: '&c&lError | &7Entidad no válida {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.'\nINVALID_ISLAND: '&c&lError | &7No tienes una isla.'\nINVALID_ISLAND_LOCATION: '&c&lError | &7No hay ninguna isla en tu ubicación.'\nINVALID_ISLAND_OTHER: '&c&lError | &7{0} no tiene una isla.'\nINVALID_ISLAND_OTHER_NAME: '&c&lError | &7No hay ninguna isla con el nombre {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lError | &7No se pudo encontrar el permiso de la isla {0}.\n  &c&lError | &7Permisos de la isla: {1}\nINVALID_LEVEL: '&c&lError | &7Nivel {0} no válido.'\nINVALID_LIMIT: '&c&lError | &7Límite no válido {0}.'\nINVALID_MATERIAL: '&c&lError | &7Material no válido {0}.'\nINVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lError | &7Misión no válida {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lError | &7Invalid module {0}.'\nINVALID_MULTIPLIER: '&c&lError | &7Multiplicador no válido {0}.'\nINVALID_PAGE: '&c&lError | &7Página no válida {0}.'\nINVALID_PERCENTAGE: '&c&lError | &7El porcentaje debe estar entre 0 y 100.'\nINVALID_PLAYER: '&c&lError | &7No se puede encontrar un jugador llamado {0}'\nINVALID_RATE: |\n  &c&lError | &7No pudimos encontrar un rating {0}.\n  &c&lError | &7Rating de la isla: {1}\nINVALID_ROWS: '&c&lError | &7Cantidad de filas no válida: {0}'\nINVALID_ROLE: |\n  &c&lError | &7No se pudo encontrar el rol {0}.\n  &c&lError | &7Roles de la isla: {1}\nINVALID_SCHEMATIC: '&c&lError | &7No se pudo encontrar una esquematica/schematic con el nombre {0}.'\nINVALID_SETTINGS: |\n  &c&lError | &7No se pudo encontrar la configuración de la isla {0}.\n  &c&lError | &7Configuración de la isla: {1}\nINVALID_SIZE: '&c&lError | &7Tamaño no válido {0}.'\nINVALID_SLOT: '&c&lError | &7Invalid slot {0}.'\nINVALID_TITLE: '&c&lError | &7Invalid title entered.'\nINVALID_TOGGLE_MODE: '&c&lError | &7No se puede alternar {0}.'\nINVALID_UPGRADE: |\n  &c&lError | &7No se pudo encontrar una mejora llamada {0}.\n  &c&lError | &7Mejoras: {1}\nINVALID_VISIT_LOCATION: '&c&lError | &7Esta isla no tiene ubicación para visitantes.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oTienes modo bypass, teletransportándote a la isla...'\nINVALID_WARP: '&c&lError | &7Warp invalido {0}.'\nINVALID_WORLD: '&c&lError | &7Mundo invalido {0}.'\nINVITE_ANNOUNCEMENT: '&e&lIsla | &7{0} ha invitado a {1} a la isla.'\nINVITE_BANNED_PLAYER: '&c&lError | &7Este jugador está PROHIBIDO de la isla y no puede ser invitado.'\nINVITE_TO_FULL_ISLAND: '&c&lError | &7No puedes invitar a más miembros a tu isla.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lError | &7Ya existe una isla con ese nombre.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBanco | &7El banco de la isla está vacío.'\nISLAND_BANK_SHOW: '&e&lBanco | &7Tu isla tiene ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7La isla de {0} tiene ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanco | &7La isla {0} tiene ${1}.'\nISLAND_BEING_CALCULATED: '&c&lError | &7¡No puedes interactuar con bloques cuando se calcula la isla!'\nISLAND_CLOSED: '&e&lIsla | &7Cerró con éxito la isla al público.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Ya tienes una tarea de creación de islas en curso.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsla | &7Procesando su solicitud...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &cdesactivado&7.'\nISLAND_FLY_ENABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &aactivado&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsla | &7&oEstabas dentro de una isla que se disolvio, por lo que se te teletransporto de regreso al spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIsla | &7&oEstabas dentro de una isla que habilito el PVP, por seguridad se te teletransporto de regreso al spawn...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desarrollado por Ome_R - Traducido al español por: Aymac'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de comandos [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Usa /is help {0} para la siguiente pagina.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsla | &7Límite bancario: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lIsla | &7Límites de bloques:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsla | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsla | &7Límite de juegadores coop: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsla | &7Multiplicador de cultivos: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsla | &7Multiplicador de drops: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIsla | &7Efectos de la isla:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsla | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIsla | &7Límites de entidades:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsla | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lIsla | &7Tasas de generación ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsla | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIsland | &7Role Limits:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lIsla | &7Tamaño del borde: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsla | &7Multiplicador de Spawners: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsla | &7Límite de equipo: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lIsla | &7Mejoras:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsla | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsla | &7Limite de Warps: {0}'\nISLAND_INFO_BANK: '&e&lIsla | &7Banco: {0}'\nISLAND_INFO_BONUS: '&e&lIsla | &7Valor de Bonus: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIsla | &7Nivel de Bonus: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIsla | &7Tiempo de creación: {0}'\nISLAND_INFO_DISCORD: '&e&lIsla | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lIsla | &7Última actualización: {0} ago'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsla | &7Última actualización: &aActualmente activo'\nISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}'\nISLAND_INFO_LOCATION: '&e&lIsla | &7Casa: {0}'\nISLAND_INFO_NAME: '&e&lIsla | &7Nombre: {0}'\nISLAND_INFO_OWNER: '&e&lIsla | &7Lider: {0}'\nISLAND_INFO_PAYPAL: '&e&lIsla | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lIsla | &7 - {0}'\nISLAND_INFO_RATE: '&e&lIsla | &7Calificación: {0} &7({1}/5) - {2} calificaciones totales.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lIsla | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIsla | &7Número de visitantes: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lIsla | &7Valor: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVista Previa | &7Fuiste demasiado lejos y ya no estás en modo de vista previa.'\nISLAND_PREVIEW_CANCEL: '&e&lVista Previa | &7Cancelaste el modo de vista previa.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM'\nISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lVista Previa | &7Ha iniciado el modo de vista previa de la esquematica/schematic {0}...\n  &e&lVista Previa | &7Type &a&lCONFIRM &7para crear una nueva isla, o &c&lCANCELAR &7para cancelar el modo de vista previa.\n  &e&lVista Previa | &7No puede salir del área de la isla, de lo contrario el modo de vista previa se cancelará automáticamente.\nISLAND_PROTECTED: '&c&lError | &7Esta isla está protegida.'\nISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lIsla | &7Miembros de la isla de {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Desconectado)'\nISLAND_TEAM_STATUS_ONLINE: '&a(En línea)'\nISLAND_TEAM_STATUS_ROLES: '&e&lIsla | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Desconectado)'\nISLAND_TOP_STATUS_ONLINE: '&a(En línea)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Privado]'\nISLAND_WAS_CLOSED: '&e&lIsla | &7&oLa isla en la que estabas fue cerrada y te teletransportaron de regreso al spawn...'\nISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.'\nISLAND_WORTH_RESULT: '&e&lIsla | &7El valor de tu isla es {0} [Nivel {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se ha unido a tu isla.'\nJOIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se ha unido a tu isla.'\nJOIN_FULL_ISLAND: '&c&lError | &7Esta isla alcanzó la cantidad máxima de miembros permitidos.'\nJOIN_WHILE_IN_ISLAND: '&c&lError | &7Ya estás dentro de una isla.'\nJOINED_ISLAND: '&e&lIsla | &7Te uniste a la isla de {0}.'\nJOINED_ISLAND_NAME: '&e&lIsla | &7Te uniste a la isla {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lIsla | &7Ahora eres un miembro cooperativo de la isla de {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lIsla | &7Ahora eres miembro cooperativo de la isla {0}.'\nKICK_ANNOUNCEMENT: '&e&lIsla | &7{0} fue expulsado de la isla por {1}.'\nKICK_ISLAND_LEADER: '&c&lError | &7No puedes expulsar al líder de la isla.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes expulsar a jugadores con un rol de isla más bajo que el tuyo.'\nLACK_CHANGE_PERMISSION: '&c&lError | &7Debe tener este permiso para poder cambiarlo a otros roles.'\nLAST_ROLE_DEMOTE: '&c&lError | &7Ya no puedes degradar a este jugador.'\nLAST_ROLE_PROMOTE: '&c&lError | &7Ya no puedes promocionar a este jugador.'\nLEAVE_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó la isla.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lError | &7No puedes dejar tu isla cuando eres el lider.\n  &c&lError | &7Puede transferir el lider utilizando /is transfer.\nLEFT_ISLAND: '&e&lIsla | &7Dejaste tu isla.'\nLEFT_ISLAND_COOP: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lError | &7Debe proporcionar un material sólido.'\nMAXIMUM_LEVEL: '&c&lError | &7El nivel máximo para esta actualización es {0}.'\nMESSAGE_SENT: '&e&lIsla | &7Se envió correctamente {0} el mensaje.!'\nMISSION_CANNOT_COMPLETE: '&c&lError | &7Aún no puedes completar esta misión.'\nMISSION_NO_AUTO_REWARD: '&e&lMisiones | &7Tienes todos los materiales necesarios para terminar la mision: {0}, usa /is missions para completar!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7Debes completar {0} antes de completar esta misión.'\nMISSION_STATUS_COMPLETE: '&e&lMisiones | &7Se cambió el estado de la misión {0} a completada para {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMisiones | &7Se cambió el estado de todas las misiones a completadas para {0}.'\nMISSION_STATUS_RESET: '&e&lMisiones | &7Se restablecio el estado de la misión {0} para {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMisiones | &7Se restableció el estado de todas misiones para {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.'\nMODULE_INFO: |\n  &e&lModule | &7{0} by {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.'\nMODULES_LIST: '&fModules ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIsla | &7{0} cambió el nombre de su isla a {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lError | &7No puedes usar ese nombre.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lError | &7No puedes usar nombres de jugadores como nombres de islas.'\nNAME_TOO_LONG: '&c&lError | &7Los nombres de las islas no pueden tener más de {0} caracteres.'\nNAME_TOO_SHORT: '&c&lError | &7Los nombres de las islas no pueden tener menos de {0} caracteres.'\nNO_BAN_PERMISSION: '&c&lError | &7Debes ser al menos {0} para prohibir a los jugadores'\nNO_CLOSE_BYPASS: '&c&lError | &7Esta isla no está abierta al público.'\nNO_CLOSE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder cerrar la isla al público.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder agregar jugadores como miembros cooperativos.'\nNO_DELETE_WARP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para eliminar warps.'\nNO_DEMOTE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para degradar jugadores.'\nNO_DEPOSIT_PERMISSION: '&c&lError | &7Debe tener al menos {0} para depositar dinero en el banco de la isla.'\nNO_DISBAND_PERMISSION: '&c&lError | &7Debes tener al menos {0} para disolver tu isla.'\nNO_EXPEL_PERMISSION: '&c&lError | &7Debes tener al menos {0} para expulsar a los jugadores de tu isla.'\nNO_INVITE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder invitar jugadores.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lError | &7Debes tener al menos {0} para acceder al cofre de la isla.'\nNO_ISLAND_INVITE: '&c&lError | &7No se pudieron encontrar invitaciones de esta isla.'\nNO_ISLANDS_TO_PURGE: '&c&lError | &7No había islas que purgar.'\nNO_KICK_PERMISSION: '&c&lError | &7Debes tener al menos {0} para patear a los jugadores.'\nNO_MORE_DISBANDS: '&c&lError | &7No puedes disolver más islas.'\nNO_MORE_WARPS: '&c&lError | &7Tu isla no puede tener más warps.'\nNO_NAME_PERMISSION: '&c&lError | &7No puedes cambiar el nombre de tu isla.'\nNO_OPEN_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder abrir la isla al público.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7Debe tener al menos {0} para obtener información sobre permisos.'\nNO_PROMOTE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para promocionar jugadores.'\nNO_RANKUP_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder subir de rango en las mejoras.'\nNO_RATINGS_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder verificar las calificaciones.'\nNO_SET_BIOME_PERMISSION: '&c&lError | &7Debes tener al menos {0} para cambiar el bioma de la isla.'\nNO_SET_DISCORD_PERMISSION: '&c&lError | &7Debes tener al menos {0} para cambiar el discord de la isla'\nNO_SET_HOME_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer la ubicación de teletransporte de la isla.'\nNO_SET_PAYPAL_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder cambiar el correo electrónico de PayPal de la isla.'\nNO_SET_ROLE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer roles para los jugadores.'\nNO_SET_SETTINGS_PERMISSION: '&c&lError | &7Debe tener al menos {0} para cambiar la configuración de la isla.'\nNO_SET_WARP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer warps en la isla.'\nNO_TRANSFER_PERMISSION: '&c&lError | &7Debes ser el líder de la isla para transferir el liderazgo.'\nNO_UNCOOP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para remover jugadores cooperativos.'\nNO_UPGRADE_PERMISSION: '&c&lError | &7No tiene permiso para actualizar a otro nivel.'\nNO_WITHDRAW_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder retirar dinero del banco de la isla.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7No tienes suficiente dinero para depositar ${0} en el banco de tu isla.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7No tienes suficiente dinero.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oEstás demasiado cansado para interactuar con los menús, ¿no crees?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Panel de la isla &cAPAGADO&7.\n  &e&lPanel | &7Usa /is para teletransportarse a la isla.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Panel de la isla &aENCENDIDO&7.\n  &e&lPanel | &7Usa /is para abrir el panel.\nPERMISSION_CHANGED: '&e&lIsla | &7Se actualizó correctamente el permiso {0} de la isla de {1}.'\nPERMISSION_CHANGED_NAME: '&e&lIsla | &7Se actualizó correctamente el permiso {0} de la isla {1}.'\nPERMISSION_CHANGED_ALL: '&e&lIsla | &7Se actualizó correctamente el permiso {0} para todas las islas.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIsla | &7¡Restableció correctamente todos los permisos de {0} a los valores predeterminados!'\nPERMISSIONS_RESET_ROLES: '&e&lIsla | &7¡Restableció con éxito todos los permisos de la isla a los valores predeterminados!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lError | &7Este jugador ya está prohibido.'\nPLAYER_ALREADY_COOP: '&c&lError | &7Este jugador ya es coop.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lError | &7Este jugador ya está dentro de una isla.'\nPLAYER_ALREADY_IN_ROLE: '&c&lError | &7{0} ya es un {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lError | &7Este usuario no puede ser expulsado de la isla.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se unió al servidor.'\nPLAYER_NOT_BANNED: '&c&lError | &7Este jugador no está prohibido.'\nPLAYER_NOT_COOP: '&c&lError | &7Este jugador no es cooperativo.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7Este jugador no está dentro de tu isla.'\nPLAYER_NOT_ONLINE: '&c&lError | &7Este jugador no está en línea!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó el servidor.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes promover jugadores con un rol de isla menor que el tuyo.'\nPROMOTED_MEMBER: '&e&lIsla | &7Ascendiste a {0} a {1} en su isla.'\nPURGE_CLEAR: '&e&lIsla | &7Limpió con éxito todas las islas en cola para purgar.'\nPURGED_ISLANDS: |-\n  &e&lIsla | &7{0} las islas se purgarán cuando se reinicie el servidor.\n  &e&lIsla | &7Puede cancelarlo en cualquier momento usando /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIsla | &7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.'\nRANKUP_SUCCESS_ALL: '&e&lIsla | &7e actualizó correctamente el nivel de la mejora {0} para todas las islas.'\nRANKUP_SUCCESS_NAME: '&e&lIsla | &7&7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lIsla | &7¡{0} ha calificado tu isla con un {1} de 5 !'\nRATE_CHANGE_OTHER: '&e&lIsla | &7Cambiaste la calificación de {0} a {1}.'\nRATE_OWN_ISLAND: '&c&lError | &7No puedes calificar tu propia isla.'\nRATE_REMOVE_ALL: '&e&lIsla | &7Se eliminaron con éxito todas las calificaciones de {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.'\nRATE_SUCCESS: '&e&lIsla | &7¡Calificaste esta isla con {0} estrellas!'\nREACHED_BLOCK_LIMIT: '&e&lMejoras| &7Has alcanzado el límite de {0} bloques de la isla.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lError | &7Tu isla ya está siendo calculada.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7Esta isla ya está siendo calculada.'\nRECALC_ALL_ISLANDS: '&e&lIsla | &7Volviendo a calcular todas las islas...'\nRECALC_ALL_ISLANDS_DONE: '&e&lIsla | &7Terminado con éxito de recalcular todas las islas.'\nRECALC_PROCCESS_REQUEST: '&e&lIsla | &7Procesando su solicitud...'\nRELOAD_COMPLETED: '&e&lIsla | &7Plugin recargado correctamente!'\nRELOAD_PROCCESS_REQUEST: '&e&lIsla | &7Empezando a recargar las configuraciones...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lIsla | &7{0} revocó la invitación de {1} a la isla.'\nRESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.'\nSAME_NAME_CHANGE: '&c&lError | &7Debes ingresar un nombre diferente al nombre de tu isla actual.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posición seleccionada #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lError | &7No ha seleccionado dos posiciones.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Procesando su solicitud...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematics | &7Ha seleccionado dos posiciones. Ejecute /is admin schematic <nombre> para crear una nueva Schematic/Esquematica.\n  &e&lSchematics | &7Asegúrese de estar parado en la ubicación de teletransportación al ejecutar el comando.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posición seleccionada #1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematics | &7Schematic/Esquematica guardada correctamente!'\nSELF_ROLE_CHANGE: '&c&lError | &7No puedes cambiar tu rol.'\nSET_UPGRADE_LEVEL: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para la isla de {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para {1}.'\nSET_WARP: '&e&lIsla | &7Se creó con éxito una nuevo warp en {0}.'\nSET_WARP_OUTSIDE: '&c&lError | &7No puedes establecer warps fuera de tu isla.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lIsla | &7Se actualizó correctamente la configuración {0} a la isla de {1}.'\nSETTINGS_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la configuración {0} de la isla {1}.'\nSETTINGS_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la configuración {0} en todas las islas.'\nSIZE_BIGGER_MAX: '&c&lError | &7No puede establecer un tamaño más grande que el tamaño máximo de la isla.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado exitosamente a {0} al spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Se actualizó correctamente la ubicación de spawn a {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Espía] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lMejoras| &7Se sincronizaron correctamente todos los valores de actualización de la isla de {0}.'\nSYNC_UPGRADES_ALL: '&e&lMejoras| &7Se sincronizaron con éxito todos los valores de actualización de todas las islas.'\nSYNC_UPGRADES_NAME: '&e&lMejoras| &7Se sincronizaron correctamente todos los valores de actualización de {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7No estás dentro de tu isla.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lError | &7No puedes teletransportarte fuera de tu rango de protección.'\nTELEPORT_WARMUP: '&7&oSerás teletransportado en {0}... ¡No te muevas!'\nTELEPORT_WARMUP_CANCEL: '&7&oTe moviste y la teletransportación fue cancelada.'\nTITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!'\nTELEPORTED_FAILED: '&e&lIsla | &7Parece que esta isla no tiene seguridad bloqueada. Póngase en contacto con un miembro del staff.'\nTELEPORTED_SUCCESS: '&e&lIsla | &7Fuiste teletransportado a tu isla.'\nTELEPORTED_TO_WARP: '&e&lIsla | &7Teletransportado con éxito al warp de esta isla'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Modo de bypass &cAPAGADO&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Modo de bypass &aENCENDIDO&7.'\nTOGGLED_FLY_OFF: '&e&lVuelo | &7Vuelo en la isla &cAPAGADO&7.'\nTOGGLED_FLY_ON: '&e&lVuelo | &7Vuelo en la isla &aENCENDIDO&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Alternar el modo schematic/esquematica &cAPAGADO&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchematics | &7Alterna el modo schematic/esquematica a &aENCENDIDO&7.\n  &e&lSchematics | &7Seleccione un área con un hacha de oro.\nTOGGLED_SPY_OFF: '&e&lEspía | &7Alternar Chat espía &cAPAGADO&7.'\nTOGGLED_SPY_ON: '&e&lEspía | &7Alternar Chat espía &aENCENDIDO&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lApilador | &7Alternar Apilador de bloques &cAPAGADO&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lApilador | &7Alternar Apilador de bloques &aENCENDIDO&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Alternar chat de equipo &cAPAGADO&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Alternar chat de equipo &aENCENDIDO&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBorde | &7Alternar borde de isla &cAPAGADO&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBorde | &7Alternar borde de isla &aENCENDIDO&7.'\nTRANSFER_ADMIN: '&e&lIsla | &7Transfirió el liderazgo de {0} a {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} ya es el líder de su isla.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7Estos jugadores no están en las mismas islas.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7Este jugador no es líder de ninguna isla.'\nTRANSFER_ALREADY_LEADER: '&c&lError | &7Ya eres el líder de esta isla.'\nTRANSFER_BROADCAST: '&e&lIsla | &7El liderazgo de la isla se ha transferido a {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lIsla | &7{0} esta PERMITIDO nuevamente en la isla {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lIsla | &7{0} eliminado {1} de ser miembro cooperativo.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó el juego y ya no es miembro cooperativo.'\nUNIGNORED_ISLAND: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas'\nUNIGNORED_ISLAND_NAME: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lIsla | &7&oParece que este warp no es seguro. Intente con otro warp.'\nUPDATED_PERMISSION: '&e&lIsla | &7Permisos actualizados para {0}.'\nUPDATED_SETTINGS: '&e&lIsla | &7Se actualizó la configuración de la isla {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lError | &7No puedes usar ese comando en otras islas.'\nWARP_ALREADY_EXIST: '&c&lError | &7Ya existe un warp con este nombre.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.'\nWARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.'\nWARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.'\nWARP_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBanco | &7El banco de la isla sólo tiene {0} dólares dentro.\n  &e&lBanco | &7&oRetirando todo el dinero...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} esta retirado ${1} del banco de la isla!'\nWITHDRAW_ERROR: '&c&lError | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lMundos | &7¡El mundo {0} aún no está desbloqueado!'\n"
  },
  {
    "path": "src/main/resources/lang/fr-FR.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Développé par Ome_R               ##\n##                                                  ##\n######################################################\n\n# Si vous souhaitez créer un nouveau fichier de langue, vous pouvez copier ce fichier, ou vous servir du fichier anglais.\n# Assurez-vous d'attribuer à votre fichier le nom correct en vous référant au lien ci-dessous.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# Un tutoriel sur la customisation des messages est disponnible à cette adresse :\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIle | &7{0} a été ajouté à l''île de {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lIle | &e{0} a été ajouté à l''île {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBanque | &7Vous avez déposé {0}$ à la banque d''île de {1}.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBanque | &7Vous avez déposé {0}$ sur la banque de l''île {1}.'\nADMIN_HELP_FOOTER: '&e&lSkyblock'\nADMIN_HELP_HEADER: '&e&lSkyblock | &7Liste des Commandes Admin [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSkyblock | &7Utilisez /is admin {0} pour la page suivante.'\nALREADY_IN_ISLAND: '&c&lErreur | &7Vous êtes déjà membre d''une île.'\nALREADY_IN_ISLAND_OTHER: '&c&lErreur | &7Ce joueur est déjà membre de votre île.'\nBAN_ANNOUNCEMENT: '&e&lIle | &7{0} a été BANNI de l''île par {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez bannir que les joueurs d''un rôle d''île inférieur au votre.'\nBANK_DEPOSIT_CUSTOM: '&e&lBanque | &7Entrez le montant que vous souhaitez déposer:'\nBANK_DEPOSIT_COMPLETED: Dépot Effectué\nBANK_LIMIT_EXCEED: '&c&lErreur | &7Vous avez dépassé votre cota bancaire.'\nBANK_WITHDRAW_CUSTOM: '&e&lBanque | &7Entrez le montant que vous souhaitez retirer:'\nBANK_WITHDRAW_COMPLETED: Retrait Effectué\nBANNED_FROM_ISLAND: '&c&lErreur | &7Vous êtes banni de cette île.'\nBLOCK_COUNT_CHECK: '&e&lIle | &7Cette île possède x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIle | &7Cette île possède les blocs suivants:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIle | &7Cette île ne possède aucun bloc comptant dans les statistiques.'\nBLOCK_COUNTS_CHECK_MATERIAL: x{0} {1}\nBLOCK_LEVEL: '&e&lNiveau | &7Le le niveau du bloc {0} est de {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lNiveau | &7Le bloc {0} n''a pas de valeur.'\nBLOCK_VALUE: '&e&lValeur | &7La valeur du bloc {0} est de {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lValeur | &7Le bloc {0} n''a pas de valeur.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Bleue'\nBORDER_PLAYER_COLOR_NAME_RED: 'Rouge'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Verte'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBordure | &7Votre bordure d''île personnelle est désormais {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas construire en dehors de votre zone de protection.'\nCANNOT_SET_ROLE: '&c&lErreur | &7Vous ne pouvez pas définir le rôle de ce joueur sur {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErreur | &7Vous pouvez uniquement changer les permissions des rôles d''île inférieurs au votre.'\nCHANGED_BANK_LIMIT: '&e&lAméliorations | &7Mise à jour de la limite bancaire de l''île de {0}.'\nCHANGED_BANK_LIMIT_ALL: '&e&lAméliorations | &7Mise à jour de la limite bancaire de toutes les îles.'\nCHANGED_BANK_LIMIT_NAME: '&e&lAméliorations | &7Mise à jour de la limite bancaire de {0}.'\nCHANGED_BIOME: '&e&lIle | &7Le biome a été modifié sur {0}. Vous devez vous reconnecter au serveur afin de voir les modifications.'\nCHANGED_BIOME_ALL: '&e&lIle | &7Biome de toutes les îles défini sur {0}.'\nCHANGED_BIOME_NAME: '&e&lIle | &7Biome de l''île {1} défini sur {0}.'\nCHANGED_BIOME_OTHER: '&e&lIle | &7Biome de l''île de {1} défini sur {0}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocs | &7La quantité de blocs aux coordonnées {0} a été modifiée pour {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour l''île de {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour toutes les îles.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour l''île de {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour toutes les îles.'\nCHANGED_CHEST_SIZE_NAME: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour {2}.'\nCHANGED_COOP_LIMIT: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour l''île de {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour toutes les îles.'\nCHANGED_COOP_LIMIT_NAME: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour l''île {0}.'\nCHANGED_CROP_GROWTH: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de l''île de {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de toutes les îles.'\nCHANGED_CROP_GROWTH_NAME: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de {0}.'\nCHANGED_DISCORD: '&e&lIle | &7Vous avez changé le Discord de l''île sur {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lAméliorations | &7Limite de {0} entities modifiée pour l''île de {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lAméliorations | &7Limite de {0} modifiée pour toutes les îles.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lAméliorations | &7Limite de {0} modifiée pour l''île {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour l''île de {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour toutes les îles.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour l''île {1}.'\nCHANGED_ISLAND_SIZE: '&e&lAméliorations | &7Vous avez changé la taille de l''île de {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lAméliorations | &7Vous avez changé la taille de toutes les îles.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lAméliorations | &7Vous avez changé la taille de l''île {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oLes joueurs peuvent construire en dehors de leurs îles, la taille d''île n''est donc plus effective. Vous pouvez désactiver cette fonctionnalité dans le fichier de configuration, afin que la taille d''île soit de nouveau effective.'\nCHANGED_LANGUAGE: '&e&lLangage | &7Langue définie sur: Français.'\nCHANGED_MOB_DROPS: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de l''île de {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de toutes les îles.'\nCHANGED_MOB_DROPS_NAME: '&e&lAméliorations | &7Vous avez changé le multiplacteur de drops des mobs de {0}.'\nCHANGED_NAME: '&e&lIle | &7Vous avez changé le nom de votre île pour {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIle | &7Vous avez changé le nom de l''île de {0} pour {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIle | &7Vous avez changé le nom de {0}&7 pour {1}&7.'\nCHANGED_PAYPAL: '&e&lIle | &7Vous avez changé le paypal de l''île pour {0}.'\nCHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.'\nCHANGED_SPAWNER_RATES: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de l''île de {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de toutes les îles.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de {0}.'\nCHANGED_TEAM_LIMIT: '&e&lAméliorations | &7Vous avez changé la limité de membres d''île pour l''île de {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de membres d''île pour toutes les îles.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de membres d''île de {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lIle | &7Vous avez changé la position de téléportation de votre île.'\nCHANGED_WARPS_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de warps de l''île de {0}.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de warps de toutes les îles.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de warps d''île de {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: quantité\nCOMMAND_ARGUMENT_BIOME: biome\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: 'commande...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: discord\nCOMMAND_ARGUMENT_EFFECT: effet-de-potion\nCOMMAND_ARGUMENT_EMAIL: email\nCOMMAND_ARGUMENT_ENTITY: entité\nCOMMAND_ARGUMENT_TIME: temps\nCOMMAND_ARGUMENT_TITLE_DURATION: 'durée'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'apparition-graduelle'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'disparition-graduelle'\nCOMMAND_ARGUMENT_ISLAND_NAME: nom-de-l'ile\nCOMMAND_ARGUMENT_ISLAND_ROLE: rôle-sur-l'île\nCOMMAND_ARGUMENT_LEADER: chef\nCOMMAND_ARGUMENT_LEVEL: niveau\nCOMMAND_ARGUMENT_LIMIT: limite\nCOMMAND_ARGUMENT_MATERIAL: matériau\nCOMMAND_ARGUMENT_MENU: nom-du-menu\nCOMMAND_ARGUMENT_MESSAGE: message\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: nom-de-la-mission\nCOMMAND_ARGUMENT_MODULE_NAME: 'nom-du-module'\nCOMMAND_ARGUMENT_MULTIPLIER: multiplicateur\nCOMMAND_ARGUMENT_NAME: nom\nCOMMAND_ARGUMENT_NEW_LEADER: nouveau-chef\nCOMMAND_ARGUMENT_PAGE: page\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: permission\nCOMMAND_ARGUMENT_PLAYER_NAME: nom-du-joueur\nCOMMAND_ARGUMENT_PRIVATE: privé\nCOMMAND_ARGUMENT_RATING: note\nCOMMAND_ARGUMENT_ROWS: lignes\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: nom-du-schémas\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: paramètres\nCOMMAND_ARGUMENT_SIZE: taille\nCOMMAND_ARGUMENT_UPGRADE_NAME: nom-de-l'amélioration\nCOMMAND_ARGUMENT_VALUE: valeur\nCOMMAND_ARGUMENT_WARP_NAME: nom-du-warp\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'catégorie-de-warp'\nCOMMAND_ARGUMENT_WORLD: monde\nCOMMAND_COOLDOWN_FORMAT: '&c&lErreur | &7Vous devez patienter {0} avant de réutiliser cette commande.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: Activer ou désactiver les informations de débogage.\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: Delete a warp for an island.\nCOMMAND_DESCRIPTION_ACCEPT: Accepter l'invitation d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN: Utiliser les commandes admin.\nCOMMAND_DESCRIPTION_ADMIN_ADD: Ajouter un joueur comme membre d'une île.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Augmenter la limite de blocs pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Attribuer un bonus au joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Augmenter la limite de coopérateurs pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Augmenter le multiplicateur de croissance des cultures pour le joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Ajouter un effet d'île à l'île du spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Augmenter la limite d'entités pour l'île spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Ajouter un poucentage de chance pour un block au générateur de cobblestone.\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Augmenter le multiplicateur de butin des monstres pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Aggrandir l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Augmenter le multiplicateur de taux des spawners pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Augmenter la limite de membres pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Augmenter la limite de warps pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: Se téléporter sur l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Envoyer un titre au joueur.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Envoyer un titre à tous les membres de l''île.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: Purger les îles.\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: Augmenter une amélioration pour l'île spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: Octroyer un bonus à un joueur.\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: Activer/Désactiver le mode bypass.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: Ouvrir le stockage de l'île spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Réinitialiser le taux des générateurs pour l'île spécifié.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: Fermer une île au public.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Executer une commande pour tous les membres d''une île.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: Vérifier le nombre de blocs sur lîle spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: Dégrader un membre de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: Déposer de l'argent sur le compte de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: Supprimer l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Donner des suppressions d'île à un joueur.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: Masquer une île du top des îles.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: Rejoindre une île sans invitation.\nCOMMAND_DESCRIPTION_ADMIN_KICK: Éjecter un joueur de son île.\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Gérer les modules du plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: Changer le statut d'une mission pour un joueur.\nCOMMAND_DESCRIPTION_ADMIN_MSG: Envoyer un message sans aucun préfixe au joueur.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: Envoyer un message sans aucun préfixe à tous les membres de lîle.\nCOMMAND_DESCRIPTION_ADMIN_NAME: Changer le nom d'une île.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: Ouvrir une île au public.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Ouvrir un menu personnalisé au joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: Promouvoir un membre d'une île.\nCOMMAND_DESCRIPTION_ADMIN_RECALC: Re-calculer la valeur d'une île.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: Recharger toutes les configurations du plugin.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Retirer la limite de bloc d'une île.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Suppimer toutes les notes attribuées par un joueur.\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Créer des schematics pour le plugin.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: Définir le biome de l'île spécifiée.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Définir la quantité de blocs sur une position spécifique.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Définir une limite de blocs pour l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Définir les lignes du stockage communautaire de l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Définir la limite de coopérateurs pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Définir le multiplicateur de croissance des cultures de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Définir le nombre de suppression d'îles d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Définir le niveau d'un effet d'île sur l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Définir la limite d'entités pour l'île du joueur spécifié.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: Transférer une île à quelqu'un d'autre.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Définir le multiplicateur de drops de mobs de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Définir un rôle nécéssaire à une permission pour toutes les îles.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: Définir une note à la place d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Activer/Désactiver les paramètres pour une île spécifique.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Changer le poucentage d'un matériau pour le générateur de cobble.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: Changer la taille de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Définir l'emplacement de spawn du serveur.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Définir le multiplicateur de taux des spawners pour l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Définir une limite de membres pour l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Définir le niveau d'une amélioration de l'île d'un joueur.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Définir la limite de warps d'une île.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: Ouvrir l'éditeur des options du plugin.\nCOMMAND_DESCRIPTION_ADMIN_SHOW: Obtenir des informations sur une île.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Se téléporter à l'emplacement de spawn.\nCOMMAND_DESCRIPTION_ADMIN_SPY: Activer/Désactiver le mode espion du chat\nCOMMAND_DESCRIPTION_ADMIN_STATS: Afficher les statistiques du plugin.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Synchroniser les valeurs des améliorations d'une île.\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: Réafficher une île dans le top des îles.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Dévérouiller un mode pour une île.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: Retirer de l'argent de la banque d'île d'un joueur.\nCOMMAND_DESCRIPTION_BALANCE: Vérifier la quantité d'argent dans le coffre de l'île spécifiée.\nCOMMAND_DESCRIPTION_BAN: Bannir un joueur de votre île.\nCOMMAND_DESCRIPTION_BANK: Ouvrir la banque de l'île.\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: Changer le biome de l'île.\nCOMMAND_DESCRIPTION_BORDER: Changer la couleur de la bordure de l'île.\nCOMMAND_DESCRIPTION_CHEST: Ouvrir le stockage communautaire de l'île.\nCOMMAND_DESCRIPTION_CLOSE: Fermer l'île au public.\nCOMMAND_DESCRIPTION_COOP: Ajouter un joueur en tant que coopérateur de votre île.\nCOMMAND_DESCRIPTION_COOPS: Ouvrir le menu des coopérateurs.\nCOMMAND_DESCRIPTION_COUNTS: Afficher le compteur de blocs de votre île.\nCOMMAND_DESCRIPTION_CREATE: Créer une nouvelle île.\nCOMMAND_DESCRIPTION_DEL_WARP: Supprimer un warp de son île.\nCOMMAND_DESCRIPTION_DEMOTE: Rétrograder un membre de votre île.\nCOMMAND_DESCRIPTION_DEPOSIT: Déposer de l'argent de votre compte personnel sur le compte de l'île.\nCOMMAND_DESCRIPTION_DISBAND: Supprimer votre île.\nCOMMAND_DESCRIPTION_EXPEL: Éjecter un visiteur de votre île.\nCOMMAND_DESCRIPTION_FLY: Activer/Désactiver le mode vol de l'île.\nCOMMAND_DESCRIPTION_HELP: Liste de toutes les commandes.\nCOMMAND_DESCRIPTION_INVITE: Inviter un joueur sur votre île.\nCOMMAND_DESCRIPTION_KICK: Éjecter un membre de votre île.\nCOMMAND_DESCRIPTION_LANG: Changer votre langue personnelle.\nCOMMAND_DESCRIPTION_LEAVE: Quitter votre île.\nCOMMAND_DESCRIPTION_MEMBERS: Ouvrir le menu des membres.\nCOMMAND_DESCRIPTION_MISSION: Completer une mission.\nCOMMAND_DESCRIPTION_MISSIONS: Ouvrir le menu des missions.\nCOMMAND_DESCRIPTION_NAME: Changer le nom de votre île.\nCOMMAND_DESCRIPTION_OPEN: Ouvrir votre île au public.\nCOMMAND_DESCRIPTION_PANEL: Ouvrir le menu d'île.\nCOMMAND_DESCRIPTION_PARDON: Débannir un joueur de votre île.\nCOMMAND_DESCRIPTION_PERMISSIONS: Obtenir toutes les permissions d'un rôle d'île.\nCOMMAND_DESCRIPTION_PROMOTE: Promouvoir un membre de votre île.\nCOMMAND_DESCRIPTION_RANKUP: Augmenter une amélioration.\nCOMMAND_DESCRIPTION_RATE: Noter une île.\nCOMMAND_DESCRIPTION_RATINGS: Afficher toutes les notes d'une île.\nCOMMAND_DESCRIPTION_SETTINGS: Ouvrir le menu des paramètres.\nCOMMAND_DESCRIPTION_RECALC: Re-calculer la valeur d'une île.\nCOMMAND_DESCRIPTION_SET_DISCORD: Définir le discord d'une île.\nCOMMAND_DESCRIPTION_SET_PAYPAL: Définir le paypal d'une île.\nCOMMAND_DESCRIPTION_SET_ROLE: Changer le rôle d'un membre de votre île.\nCOMMAND_DESCRIPTION_SET_TELEPORT: Changer la position de téléportation de votre île.\nCOMMAND_DESCRIPTION_SET_WARP: Créer un nouveau warp d'île.\nCOMMAND_DESCRIPTION_SHOW: Obtenir des informations à propos d'une île.\nCOMMAND_DESCRIPTION_TEAM: Obtenir des informations sur le status des membres de l'île.\nCOMMAND_DESCRIPTION_TEAM_CHAT: Activer/Désactiver le mode de chat d'île.\nCOMMAND_DESCRIPTION_TELEPORT: Se téléporter sur votre île.\nCOMMAND_DESCRIPTION_TOGGLE: Activer/Désactiver les bordures d'île et les stack de blocs.\nCOMMAND_DESCRIPTION_TOP: Ouvrir l'interface de top des îles.\nCOMMAND_DESCRIPTION_TRANSFER: Transferer la direction de votre île.\nCOMMAND_DESCRIPTION_UNCOOP: Supprimer un joueur coopérateur de votre île.\nCOMMAND_DESCRIPTION_UPGRADE: Ouvrir le menu des améliorations.\nCOMMAND_DESCRIPTION_VALUE: Obtenir la valeur d'une bloc.\nCOMMAND_DESCRIPTION_VALUES: Ouvrir le menu des valeurs.\nCOMMAND_DESCRIPTION_VISIT: Se téléporter sur la zone visiteurs d'une île.\nCOMMAND_DESCRIPTION_VISITORS: Ouvrir le menu des visiteurs.\nCOMMAND_DESCRIPTION_WARP: Se téléporter au warp d'une île.\nCOMMAND_DESCRIPTION_WARPS: Ouvrir le menu des Warps.\nCOMMAND_DESCRIPTION_WITHDRAW: Transférer de l'argent du compte de votre île à votre compte personnel.\nCOMMAND_USAGE: '&cUtilisation: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lIle | &7{0} a ajouté {1} en tant que coopérateur.'\nCOOP_BANNED_PLAYER: '&c&lErreur | &7Ce joueur est banni de l''île et ne peut pas être coopérateur.'\nCOOP_LIMIT_EXCEED: '&c&lErreur | &7Vous avez atteint le nombre maximal de coopérateurs d''île.'\nCREATE_ISLAND: '&e&lIle | &7Création d''une nouvelle île aux coordonnées {0} en {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lErreur | &7Une erreur est survenue ors de la création de votre île. Veuillez contacter un administrateur et le notifier de ce problème.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Débogage &cDÉSACTIVÉ&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Débogage &aACTIVÉ&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lIle | &7Vous avez supprimé le warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oIl y avait une pancarte pour ce warp, mais elle a été détruite...'\nDEMOTE_LEADER: '&c&lErreur | &7Vous ne pouvez pas rétrograder le propriétaire de l''île.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous pouvez uniquement rétrograder des joueurs ayant un rôle d''île inférieur au votre.'\nDEMOTED_MEMBER: '&e&lIle | &7Vous avez rétrogradé {0} au rôle de {1} sur son île.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBanque | &7{0} a déposé {1}$ sur le compte de l''île !'\nDEPOSIT_ERROR: '&c&lErreur | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez rien casser en dehors de votre île.'\nDISBAND_ANNOUNCEMENT: '&e&lIle | &7Votre île a été supprimée par {0}.'\nDISBAND_GIVE: '&e&lIle | &7Vous avez reçu {0} suppressions d''île.'\nDISBAND_GIVE_ALL: '&e&lIle | &7Vous avez donné {0} suppressions d''île à tous les joueurs.'\nDISBAND_GIVE_OTHER: '&e&lIle | &7Vous avez donné {0} supressions d''île à {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank'\nDISBAND_SET: '&e&lIle | &7Votre nombre de suppressions d''île a été défini sur {0}.'\nDISBAND_SET_ALL: '&e&lIle | &7Vous avez défini le nombre de suppressions d''île de tous les joueurs sur {0}.'\nDISBAND_SET_OTHER: '&e&lIle | &7Vous avez défini le nombre de suppressions d''île de {0} sur {1}.'\nDISBANDED_ISLAND: '&e&lIle | &7Vous avez supprimé votre île.'\nDISBANDED_ISLAND_OTHER: '&e&lIle | &7Vous avez supprimé l''île de {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lIle | &7Vous avez supprimé l''île {0}.'\nENTER_PVP_ISLAND: '&7&oVous vous êtes téléporté sur une île ou le PVP est actif. Vous êtes donc invincible pour les 10 prochaines secondes...'\nEXPELLED_PLAYER: '&e&lIle | &7{0} a été exclu de l''île.'\nFORMAT_QUAD: Q\nFORMAT_TRILLION: T\nFORMAT_BILLION: B\nFORMAT_MILLION: M\nFORMAT_THOUSANDS: K\nFORMAT_SECONDS_NAME: secondes\nFORMAT_SECOND_NAME: seconde\nFORMAT_MINUTES_NAME: minutes\nFORMAT_MINUTE_NAME: minute\nFORMAT_HOURS_NAME: heures\nFORMAT_HOUR_NAME: heure\nFORMAT_DAYS_NAME: jours\nFORMAT_DAY_NAME: jour\nGENERATOR_CLEARED: '&e&lIle | &7Nettoyage des taux des générateurs pour l''île de {0}.'\nGENERATOR_CLEARED_NAME: '&e&lIle | &7Nettoyage des taux des générateurs pour l''île {0}.'\nGENERATOR_CLEARED_ALL: '&e&lIle | &7Nettoyage des taux des générateurs de toutes les îles.'\nGENERATOR_UPDATED: '&e&lIle | &7Taux du générateur modifié sur {0} pour l''île de {1}.'\nGENERATOR_UPDATED_NAME: '&e&lIle | &7Taux du générateur modifié sur {0} pour l''île de {1}.'\nGLOBAL_COMMAND_EXECUTED: '&e&lIle | &7Éxécution de la commande sur les membres de l''île de {0} !'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIle | &7Éxécution de la commande sur les membres de : {0} !'\nGENERATOR_UPDATED_ALL: '&e&lIle | &7Taux du générateur modifié sur {0} pour toutes les îles.'\nGLOBAL_MESSAGE_SENT: '&e&lIle | &7Message envoyé à tous les membres de l''île de {0} !'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lIle | &7Message envoyé à tous les membres de l''île {0} !'\nGLOBAL_TITLE_SENT: '&e&lIle | &7Envoi du titre aux membres de l''île de {0} !'\nGLOBAL_TITLE_SENT_NAME: '&e&lIle | &7Envoi du titre à tous les membres de l''île {0} !'\nGOT_BANNED: '&e&lIle | &7Vous avez été BANNI de l''île de {0}.'\nGOT_DEMOTED: '&e&lIle | &7Vous avez été rétrogradé au rôle de {0} sur votre île.'\nGOT_EXPELLED: '&e&lIle | &7&oVous avez été exclu de l''île par {0}.'\nGOT_INVITE: '&e&lIle | &7{0} vous a invité sur son île.'\nGOT_INVITE_TOOLTIP: '&7Cliquez sur ce message afin d''accepter l''invitation.'\nGOT_KICKED: '&e&lIle | &7Vous avez été éjecté de votre île par {0}.'\nGOT_PROMOTED: '&e&lIle | &7Vous avez été promu au rôle de {0} sur votre île.'\nGOT_REVOKED: '&e&lIle | &7{0} a révoqué votre invitation sur son île.'\nGOT_UNBANNED: '&e&lIle | &7Vous avez été DÉBANNI de l''île de {0}.'\nHIT_ISLAND_MEMBER: '&c&lErreur | &7Vous ne pouvez pas taper les membres de votre île.'\nHIT_PLAYER_IN_ISLAND: '&c&lErreur | &7Vous ne pouvez pas frapper les autres joueurs sur les îles.'\nIGNORED_ISLAND: '&e&lIle | &7L''île de {0} est désormais masquée du top des îles.'\nIGNORED_ISLAND_NAME: '&e&lIle | &7L''île {0} est désormais masquée du top des îles.'\nINTERACT_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas interagir en dehors de votre île.'\nINVALID_AMOUNT: '&c&lErreur | &7Nombre invalide {0}.'\nINVALID_BIOME: '&c&lErreur | &7Biome invalide {0}.'\nINVALID_BLOCK: '&c&lErreur | &7Emplacement {0} du bloc invalide.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lErreur | &7Effet invalide {0}.'\nINVALID_ENTITY: '&c&lErreur | &7Entité invalide {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_SCHEMATIC: '&c&lErreur | &7Il n''existe aucun schematic portant le nom {0}.'\nINVALID_INTERVAL: '&c&lErreur | &7Interval invalide {0}.'\nINVALID_ISLAND: '&c&lErreur | &7Vous n''avez pas d''île.'\nINVALID_ISLAND_LOCATION: '&c&lErreur | &7Il n''y a pas d''île sur votre position.'\nINVALID_ISLAND_OTHER: '&c&lErreur | &7{0} n''a pas d''île.'\nINVALID_ISLAND_OTHER_NAME: '&c&lErreur | &7Il n''y a pas d''île portant le nom {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lErreur | &7La permission {0} nexiste pas.\n  &c&lErreur | &7Permissions d'île: {1}\nINVALID_LEVEL: '&c&lErreur | &7Niveau invalide: {0}.'\nINVALID_LIMIT: '&c&lErreur | &7Limite invalide: {0}.'\nINVALID_MATERIAL: '&c&lErreur | &7Matériau invalide: {0}.'\nINVALID_MATERIAL_DATA: '&c&lErreur | &7Donnée de matériau {0} invalide.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lErreur | &7Mission {0} invalide.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lErreur | &7Module {0} invalide.'\nINVALID_MULTIPLIER: '&c&lErreur | &7Multiplicateur invalide: {0}.'\nINVALID_PAGE: '&c&lErreur | &7Page {0} invalide.'\nINVALID_PERCENTAGE: '&c&lErreur | &7Le poucentage doit être compris entre 0 et 100.'\nINVALID_PLAYER: '&c&lErreur | &7Le joueur {0} n''existe pas.'\nINVALID_RATE: |\n  &c&lErreur | &7Aucune note ne porte le nom: {0}.\n  &c&lErreur | &7Notes de l'île: {1}\nINVALID_ROWS: '&c&lErreur | &7Nombre de lignes invalide: {0}'\nINVALID_ROLE: |\n  &c&lErreur | &7Aucun rôle ne porte le nom: {0}.\n  &c&lErreur | &7Rôles de l'île: {1}\nINVALID_SETTINGS: |\n  &c&lErreur | &7Aucun paramètre ne porte le nom: {0}.\n  &c&lErreur | &7Paramètres d'île: {1}\nINVALID_SIZE: '&c&lErreur | &7Taille invalide: {0}.'\nINVALID_SLOT: '&c&lErreur | &7Slot invalide {0}.'\nINVALID_TITLE: '&c&lErreur | &7Titre spécifié invalide.'\nINVALID_TOGGLE_MODE: '&c&lErreur | &7Impossible d''Activer/Désactiver: {0}.'\nINVALID_UPGRADE: |\n  &c&lErreur | &7Aucune amélioration ne porte le nom {0}.\n  &c&lErreur | &7Améliorations: {1}\nINVALID_VISIT_LOCATION: '&c&lErreur | &7Cette île ne possède aucune zone visiteurs.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oVous avez activé le mode bypass, téléportation sur l''île...'\nINVALID_WARP: '&c&lErreur | &7Warp invalide: {0}.'\nINVALID_WORLD: '&c&lErreur | &7Monde {0} invalide.'\nINVITE_ANNOUNCEMENT: '&e&lIle | &7{0} a invité {1} sur l''île.'\nINVITE_BANNED_PLAYER: '&c&lErreur | &7Ce joueur est banni de l''île et ne peut pas être invité.'\nINVITE_TO_FULL_ISLAND: '&c&lErreur | &7Vous ne pouvez pas inviter plus de membres sur l''île.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lErreur | &7Une île portant ce nom existe déjà.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBanque | &7La banque de l''île est vide.'\nISLAND_BANK_SHOW: '&e&lBanque | &7Votre île possède {0} crystaux !'\nISLAND_BANK_SHOW_OTHER: '&e&lBanque | &7L''île de {0} possède {1} crystaux !'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanque | &7L''île {0} possède {1} crystaux !'\nISLAND_BEING_CALCULATED: '&c&lErreur | &7Vous ne pouvez pas interagir avec des blocs lorsque l''île est en train d''être recalculée !'\nISLAND_CLOSED: '&e&lIle | &7L''île est désormais fermée au public.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lErreur | &7Votre île est déjà en cours de création.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lIle | &7Requête en cours de traitement...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lVol | &7Le mode vol de l''île a été &cdésactivé &7automatiquement.'\nISLAND_FLY_ENABLED: '&e&lVol | &7Le mode vol de l''île &aactivé &7automatiquement.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIle | &7&oVous vous trouviez sur une île ayant été supprimée, vous avez donc été téléporté(e) au spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIle | &7&oVous vous trouviez sur une île ayant activé le PVP, vous avez donc été téléporté(e) au spawn...'\nISLAND_HELP_FOOTER: '&e&lSkyblock'\nISLAND_HELP_HEADER: '&e&lSkyblock | &7Liste des Commandes [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSkyblock | &7Utilisez /is help {0} pour accéder à la page suivante.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIle | &7Limite Bancaire: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lIle | &7Limite de blocs:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIle | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIle | &7Limite de Coopérateurs: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIle | &7Effets d'Île:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIle | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIle | &7Limite d'Entitées:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIle | &7  {0}: {1}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Cultures:\n  {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Drops: {0}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lIle | &7Taux de Générateur:\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIle | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIle | &7Limite de Roles:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIle | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lIle | &7Taille de la bordure: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Spawners:\n  {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIle | &7Limite de membres: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lIle | &7Améliorations:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIle | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIle | &7Limite de Warps: {0}'\nISLAND_INFO_BANK: '&e&lIle | &7Banque: {0}'\nISLAND_INFO_BONUS: '&e&lIle | &7Bonus de Valeur: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIle | &7Bonus de Niveau: {0}'\nISLAND_INFO_DISCORD: '&e&lIle | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LOCATION: '&e&lIle | &7Accueil: {0}'\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lIle | &7Dernière mise à jour: Il y à {0}'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIle | &7Dernière mise à jour: &aActuellement Active'\nISLAND_INFO_LEVEL: '&e&lIle | &7Niveau: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIle | &7Date de Création: {0}'\nISLAND_INFO_NAME: '&e&lIle | &7Nom: {0}'\nISLAND_INFO_OWNER: '&e&lIle | &7Chef: {0}'\nISLAND_INFO_PAYPAL: '&e&lIle | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lIle | &7 - {0}'\nISLAND_INFO_RATE: '&e&lIle | &7Note: &f&l{0} &7({1}/5) - {2} notes au total'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lIle | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIle | &7Nombre de visiteurs: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lIle | &7Valeur: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIle | &7L''île est désormais ouverte au public.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPrévisualisation | &7Vous vous êtes trop éloigné(e). La prévisualisation à donc été désactivée.'\nISLAND_PREVIEW_CANCEL: '&e&lPrévisualisation | &7Vous avez annulé(e) la prévisualisation.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMER'\nISLAND_PREVIEW_CANCEL_TEXT: 'ANNULER'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lPrévisualisation | &7Vous avez débuté la prévisualisation de l'île {0}.\n  &e&lPrévisualisation | &7Tapez &a&lCONFIRMER &7pour séléctionner cette île, ou &c&lANNULER &7pour annuler la prévisualisation.\n  &e&lPrévisualisation | &7Si vous quittez la zone de l'île, la prévisualisation sera désactivée.\nISLAND_PROTECTED: '&c&lErreur | &7Cette île est protégée.'\nISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lIle | &7Membres de l''île de {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Hors Ligne)'\nISLAND_TEAM_STATUS_ONLINE: '&a(En Ligne)'\nISLAND_TEAM_STATUS_ROLES: '&e&lIle | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Hors Ligne)'\nISLAND_TOP_STATUS_ONLINE: '&a(En Ligne)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Privé]'\nISLAND_WAS_CLOSED: '&e&lIle | &7&oL''île sur laquelle vous étiez a été fermée, vous avez donc été téléporté au spawn...'\nISLAND_WORTH_ERROR: '&c&lErreur | &7Une erreur inattendue est survenue lors du calcul de votre île. Veuillez contacter un administrateur sur le problème persiste.'\nISLAND_WORTH_RESULT: '&e&lIle | &7La valeur de votre île est {0} [Niveau {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lErreur | &7La tâche de calcul des îles a expiré. Veuillez réessayer ultérieurement...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint votre île.'\nJOIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint votre île.'\nJOIN_FULL_ISLAND: '&c&lErreur | &7Cette île a déjà le nombre maximal de membres.'\nJOIN_WHILE_IN_ISLAND: '&c&lErreur | &7Vous êtes déjà membre d''une île.'\nJOINED_ISLAND: '&e&lIle | &7Vous avez rejoint l''île de {0}.'\nJOINED_ISLAND_NAME: '&e&lIle | &7Vous avez rejoint l''île {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lIle | &7Vous êtes désormais un coopérateur de l''île de {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lIle | &7Vous êtes désormais un coopérateur de l''île {0}.'\nKICK_ANNOUNCEMENT: '&e&lIle | &7{0} a été éjecté de l''île par {1}.'\nKICK_ISLAND_LEADER: '&c&lErreur | &7Vous ne pouvez pas éjecter le propriétaire d''une île, utilisez ''/isadmin disband'' à la place.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez éjécter que les membres ayant un rôle d''île inférieur au votre.'\nLACK_CHANGE_PERMISSION: '&c&lErreur | &7Vous devez avoir cette permission afin de pouvoir la modifier pour les autres rôles.'\nLAST_ROLE_DEMOTE: '&c&lErreur | &7Vous ne pouvez plus rétrograder ce joueur.'\nLAST_ROLE_PROMOTE: '&c&lErreur | &7Vous ne pouvez plus promouvoir ce joueur.'\nLEAVE_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté l''île.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lErreur | &7Vous ne pouvez quitter une île vous appartenant.\n  &c&lErreur | &7Vous pouvez transférer votre île à un joueur en tapant /is transfer.\nLEFT_ISLAND: '&e&lIle | &7Vous avez quitté votre île.'\nLEFT_ISLAND_COOP: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île de {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lErreur | &7Vous devez fournir un matériau solide.'\nMAXIMUM_LEVEL: '&c&lErreur | &7Le niveau maximal pour cette amélioration est de {0}.'\nMESSAGE_SENT: '&e&lIle | &7Message envoyé a {0} !'\nMISSION_CANNOT_COMPLETE: '&c&lErreur | &7Vous ne pouvez compléter cette mission pour le moment.'\nMISSION_NO_AUTO_REWARD: '&e&lMission | &7Vous possédez tous les matériaux requis pour compléter la mission {0} - Tapez /is missions afin de compléter la mission !'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErreur | &7Vous devez compléter {0} avant de compléter cette mission.'\nMISSION_STATUS_COMPLETE: '&e&lMission | &7Le statut de la mission {0} a été complété sur {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Toutes les missions ont été completées pour {0}.'\nMISSION_STATUS_RESET: '&e&lMission | &7Le statut de la mission {0} a été réinitialisé sur {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMission | &7Réinitialisation du statut de toutes les missions pour {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7Ce module est déjà chargé.'\nMODULE_INFO: |\n  &e&lModule | &7{0} créé par {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Module {0} activé.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Une erreur est survenue lors du chargement du module {0}. Vérifiez votre console et vos logs pour plus d''informations.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Module désactivé.'\nMODULES_LIST: '&fModules ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIle | &7{0} a changé le nom de son île sur {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lErreur | &7Vous ne pouvez pas utiliser ce nom.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lErreur | &7Vous ne pouvez pas utiliser le pseudonyme d''un joueur comme nom d''île.'\nNAME_TOO_LONG: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir plus de {0} caractères.'\nNAME_TOO_SHORT: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir moins de {0} caractères.'\nNO_ISLANDS_TO_PURGE: '&c&lErreur | &7Il n''y a aucune îles à purger.'\nNO_BAN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de bannir un joueur.'\nNO_CLOSE_BYPASS: '&c&lErreur | &7Cette île n''est pas ouverte au public.'\nNO_CLOSE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de fermer cette.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''ajouter des coopérateurs à l''île.'\nNO_DELETE_WARP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimer des warps.'\nNO_DEMOTE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de rétrograder des joueurs.'\nNO_DEPOSIT_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de déposer de l''argent sur le compte de l''île.'\nNO_DISBAND_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimervotre île.'\nNO_EXPEL_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''exclure des joueurs de l''île.'\nNO_INVITE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''inviter des joueurs sur l''île.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''accéder au stockage de l''île.'\nNO_ISLAND_INVITE: '&c&lErreur | &7Vous n''avez aucune invitation provenant de cette île.'\nNO_KICK_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''éjécter des membres de l''île.'\nNO_MORE_DISBANDS: '&c&lErreur | &7Vous ne pouvez plus supprimer votre île.'\nNO_MORE_WARPS: '&c&lErreur | &7Votre île ne peut contenir plus de warps.'\nNO_NAME_PERMISSION: '&c&lErreur | &7Vous ne pouvez pas changer le nom de votre île.'\nNO_OPEN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''ouvrir l''île au public.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''obtenir des informations sur les permissions.'\nNO_PROMOTE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de promouvoir des joueurs.'\nNO_RANKUP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''augmenter des améliorations.'\nNO_RATINGS_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de vérifier les notes.'\nNO_SET_BIOME_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le biome de l''île.'\nNO_SET_DISCORD_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le Discord de l''île.'\nNO_SET_HOME_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir me point de téléportation de l''île.'\nNO_SET_PAYPAL_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le paypal de l''île.'\nNO_SET_ROLE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir les rôles de membres de l''île.'\nNO_SET_SETTINGS_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de modifier les paramètres de l''île.'\nNO_SET_WARP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir des warps d''île.'\nNO_TRANSFER_PERMISSION: '&c&lErreur | &7Vous devez être le chef de l''île afin de transférer l''île à un autre joueur.'\nNO_UNCOOP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimer des coopérateurs de l''île.'\nNO_UPGRADE_PERMISSION: '&c&lErreur | &7Vous n''avez pas la permission d''augmenter l''amélioration à un autre niveau.'\nNO_WITHDRAW_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de retirer de l''argent du compte de l''île.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent pour déposer {0}$ sur le compte de vôtre île.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent pour utiliser les warps d''île.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oVous êtes trop fatigué pour interagir avec le menu vous ne pensez pas ?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Panel de gestion de l'île &cDÉSACTIVÉ&7.\n  &e&lPanel | &7Tapez /is afin d'être téléporté sur votre île.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Panel de gestion de l'île &aACTIVÉ&7.\n  &e&lPanel | &7Tapez /is afin d'ouvrir le panel de gestion.\nPERMISSION_CHANGED: '&e&lIle | &7Permission {0} de l''île de {1} mise à jour.'\nPERMISSION_CHANGED_NAME: '&e&lIle | &7Permission {0} de l''île {1} mise à jour.'\nPERMISSION_CHANGED_ALL: '&e&lIle | &7Permission {0} mise à jour pour toutes les îles.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIle | &7Réinitialisation de toutes les permissions de {0} !'\nPERMISSIONS_RESET_ROLES: '&e&lIle | &7Réinitialisation de toutes les permissions de l''île !'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lErreur | &7Ce joueur est déjà banni.'\nPLAYER_ALREADY_COOP: '&c&lErreur | &7Ce joueur est déjà coopérateur.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lErreur | &7Ce joueur est déjà membre d''une île.'\nPLAYER_ALREADY_IN_ROLE: '&c&lErreur | &7{0} est déjà {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lErreur | &7Ce joueur ne peut pas être exclu de l''île.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint le serveur.'\nPLAYER_NOT_BANNED: '&c&lErreur | &7Ce joueur n''est pas banni.'\nPLAYER_NOT_COOP: '&c&lErreur | &7Ce joueur n''est pas coopérateur.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lErreur | &7Ce joueur n''est pas sur votre île.'\nPLAYER_NOT_ONLINE: '&c&lErreur | &7Ce joueur n''est pas connecté !'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté le serveur.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez uniquement promouvoir les joueurs ayant un rôle inférieur au votre.'\nPROMOTED_MEMBER: '&e&lIle | &7Vous avez promu {0} {1} sur l''île.'\nPURGE_CLEAR: '&e&lIle | &7Toutes les îles en attente de purge ont été purgées.'\nPURGED_ISLANDS: |-\n  &e&lIle | &7{0} île seront purgées au redémarrage du serveur.\n  &e&lIle | &7Vous pouvez annuler ce processus à nimporte quel moment en tapant /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île de {1}.'\nRANKUP_SUCCESS_ALL: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour toutes les îles.'\nRANKUP_SUCCESS_NAME: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lIle | &7{0} a noté votre île {1} / 5 !.'\nRATE_CHANGE_OTHER: '&e&lIle | &7Vous avez modifié la note de {0} sur {1}.'\nRATE_OWN_ISLAND: '&c&lErreur | &7Vous ne pouvez pas noter votre île.'\nRATE_REMOVE_ALL: '&e&lIle | &7Toutes les notes de {0} ont été supprimées.'\nRATE_REMOVE_ALL_ISLANDS: '&e&llIle | &7Suppression des notes de toutes les îles.'\nRATE_SUCCESS: '&e&lIle | &7Vous avez noté cette île {0} étoile(s) !'\nREACHED_BLOCK_LIMIT: '&e&lAméliorations | &7Vous avez atteint la limite de bloc d''île pour {0}.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lErreur | &7Votre île est déjà en cours de calcul.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lErreur | &7Cette île est déjà en cours de calcul.'\nRECALC_ALL_ISLANDS: '&e&lIle | &7Recalcul de toutes les îles...'\nRECALC_ALL_ISLANDS_DONE: '&e&lIle | &7Recalcul des îles effectué avec succès.'\nRECALC_PROCCESS_REQUEST: '&e&lIle | &7Début du recalcul des îles...'\nRELOAD_COMPLETED: '&e&lIle | &7Rechargement effectué !'\nRELOAD_PROCCESS_REQUEST: '&e&lIle | &7Début du rechargement des configurations...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lIle | &7{0} a révoqué l''inviation à rejoindre l''île de {1}.'\nRESET_WORLD_SUCCEED: '&e&lIle | &7Réinitialisation du monde {0} pour l''île de {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIle | &7Réinitialisation du monde {0} pour toutes les îles.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIle | &7Réinitialisation du monde {0} pour l''île de {1}.'\nSAME_NAME_CHANGE: '&c&lErreur | &7Vous devez entrer un nom différent de celui actuel.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchémas | &7Position #2 séléctionnée ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lErreur | &7Vous n''avez pas séléctionné deux positionss.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchémas | &7Traitement de votre requête...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchémas | &7Vous avez séléctionné deux positions. Tapez /is admin schematic <nom> afin de créer un schematic.\n  &e&lSchémas | &7Assurez-vous de vous situer sur le point de téléportation lors de l'éxécution de la commande.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchémas | &7Position #1 séléctionnée ({0})'\nSCHEMATIC_SAVED: '&e&lSchémas | &7Schematic sauvegardé !'\nSELF_ROLE_CHANGE: '&c&lErreur | &7Vous ne pouvez pas changer votre propre rôle.'\nSET_UPGRADE_LEVEL: '&e&lAméliorations | &7Niveau de {0} augmenté sur l''île de {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lAméliorations | &7Niveau de {0} augmenté sur {1}.'\nSET_WARP: '&e&lIle | &7Nouveau warp crée au coordonnées {0}.'\nSET_WARP_OUTSIDE: '&c&lErreur | &7Vous ne pouvez pas définir de warps hors de votre île.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lIle | &7Paramètre {0} mit à jour pour l''île de {1}.'\nSETTINGS_UPDATED_NAME: '&e&lIle | &7Paramètre {0} mit à jour pour l''île {1}.'\nSETTINGS_UPDATED_ALL: '&e&lIle | &7Paramètre {0} mit à jour pour toutes les îles.'\nSIZE_BIGGER_MAX: '&c&lErreur | &7Vous ne pouvez pas définir une taille d''île supérieure à la taille d''île maximale.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Téléporation de {0} au spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Mise à jour de la position du spawn sur {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Espion] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de l''île de {0}.'\nSYNC_UPGRADES_ALL: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de toutes les îles.'\nSYNC_UPGRADES_NAME: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de l''île {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErreur | &7Vous n''êtes pas sûr votre île.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas vous téléporter en dehors de votre zone de protection.'\nTELEPORT_WARMUP: '&7&oVous serez téléporté dans {0}... Ne bougez pas !'\nTELEPORT_WARMUP_CANCEL: '&7&oVous vous êtes déplacé, la téléportation a donc été annulée.'\nTITLE_SENT: '&e&lIle | &7Envoie du titré {0} effectué !'\nTELEPORTED_FAILED: '&e&lIle | &7Il semblerait que cette île ne soit pas sécurisée. Veuillez contacter un Administrateur.'\nTELEPORTED_SUCCESS: '&e&lIle | &7Vous avez été téléporté sur votre île.'\nTELEPORTED_TO_WARP: '&e&lIle | &7Vous avez été télporté au warp de l''île.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIle | &7{0} s''est téléporté(e) au warp d''île {1}.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Mode bypass &cDÉSACTIVÉ&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Mode bypass &aACTIVÉ&7.'\nTOGGLED_FLY_OFF: '&e&lVol | &7Mode de fly d''île &cDÉSACTIVÉ&7.'\nTOGGLED_FLY_ON: '&e&lVol | &7Mode de fly d''île &aACTIVÉ&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchémas | &7Mode de création de schematics &cDÉSACTIVÉ&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchémas | &7Mode de création de schematics &aACTIVÉ&7.\n  &e&lSchémas | &7Séléctionnez une zone en utilisant la hache en or.\nTOGGLED_SPY_OFF: '&e&lEspion | &7Mode espion du chat &cDÉSACTIVÉ&7.'\nTOGGLED_SPY_ON: '&e&lEspion | &7Mode espion du Chat &aACTIVÉ&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Stacker de blocs &cDÉSACTIVÉ&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Stacker de blocs &aACTIVÉ&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Chat de l''île &cDÉSACTIVÉ&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Chat de l''île &aACTIVÉ&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBordure | &7Bordure de l''île &cDÉSACTIÉE&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBordure | &7Bordure de l''île &aACTIVÉE&7.'\nTRANSFER_ADMIN: '&e&lIle | &7Vous avez transféré le rôle de Chef de l''île de {0} à {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lErreur | &7{0} est déjà le Chef de cette île.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErreur | &7Ces joueurs ne font pas parti de la même île.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lErreur | &7Ce joueur n''est chef d''aucune île.'\nTRANSFER_ALREADY_LEADER: '&c&lErreur | &7Vous êtes déjà le chef de l''île.'\nTRANSFER_BROADCAST: '&e&lIle | &7Le Chef de l''île est désormais {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lIle | &7{0} a été DÉBANNI de l''île par {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lIle | &7{0} a retiré le rôle de coopérateur de {1}.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté le jeu et n''est désormais plus un coopérateur.'\nUNIGNORED_ISLAND: '&e&lIle | &7L''île de {0} est désormais visible dans le top des îles.'\nUNIGNORED_ISLAND_NAME: '&e&lIle | &7L''île {0} n''est plus masquée dans le top des îles.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lIle | &7&oIl semblerait que ce warp ne soit pas sécurisé. Veuillez en essayer un autre.'\nUPDATED_PERMISSION: '&e&lIle | &7Permission mise à jour pour {0}.'\nUPDATED_SETTINGS: '&e&lIle | &7Paramètre de l''île mit à jour {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lErreur | &7Vous devez patienter {0} afin d''effectuer une nouvelle amélioration.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lErreur | &7Vous ne pouvez pas utiliser cette commande sur d''autres îles.'\nWARP_ALREADY_EXIST: '&c&lErreur | &7Un warp portant ce nom éxiste déjà.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Spécifiez un nouveau lore (Entrez \"-cancel\" to pour annuler) :\n  &e&lWarps | &7Vous pouvez ajouter une nouvelle ligne en utilisant \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Spécifiez un nom (Entrez \"-cancel\" to pour annuler) :'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Spécifiez un nouveau matériau (Entrez \"-cancel\" to pour annuler) :'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Mise à jour de l''icone de la catégorie.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lErreur | &7Vous ne pouvez utiliser uniquement des lettres, nombres et ''_'' comme nom de catégorie de warp.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lErreur | &7Le nom d''une catégorie de warp ne peut dépasser 255 caractères.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Spécifiez un nouvel emplacement (Entrez \"-cancel\" to pour annuler) :'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErreur | &7Cet emplacement est déjà utilisé par une autre catégorie.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7L''emplacement de la catégorie est désormais {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Spécifiez un nom (Entrez \"-cancel\" to pour annuler) :'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErreur | &7Ce nom est déjà utilisé par une autre catégorie.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Cette catégorie a été renommée en {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Spécifiez un nouveau lore (Entrez \"-cancel\" to pour annuler) :\n  &e&lWarps | &7Vous pouvez ajouter une nouvelle ligne en utilisant \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Spécifiez un nom (Entrez \"-cancel\" to pour annuler) :'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Spécifiez un nouveau matériau (Entrez \"-cancel\" to pour annuler) :'\nWARP_ICON_UPDATED: '&e&lWarps | &7Mise à jour de l''icone du warp.'\nWARP_ILLEGAL_NAME: '&c&lErreur | &7Vous ne pouvez utiliser uniquement des lettres, nombres et ''_'' comme nom de warp.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Mise à jour de la position de téléportation du warp sur votre emplacement actuel.'\nWARP_NAME_TOO_LONG: '&c&lErreur | &7Le nom d''un warp ne peut dépasser 255 caractères.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Le warp est désormais accessible au public.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Le warp n''est plus accessible au public.'\nWARP_RENAME: '&e&lWarps | &7Spécifiez un nouveau nom (Entrez \"-cancel\" to pour annuler) :'\nWARP_RENAME_ALREADY_EXIST: '&c&lErreur | &7Ce nom est déjà utilisé par un autre warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Le warp a été renommé en {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBanque | &7Le compte de l'île ne contient que {0}$.\n  &e&lBanque | &7&oRécupération de tout l'argent...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBanque | &7{0} a retiré {1}$ du compte de l''île !'\nWITHDRAW_ERROR: '&c&lErreur | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île de {1} !'\nWITHDRAWN_MONEY_NAME: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île {1} !'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lMondes | &7Le monde {0} n''a pas encore été dévérouillé !'\n"
  },
  {
    "path": "src/main/resources/lang/it-IT.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##            Translated by xSavior_of_God          ##\n##                                                  ##\n######################################################\n\n# Se desideri creare un nuovo file di lingua, copia questo.\n# Assicurati di impostare come nome un nome di lingua corretto.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# Puoi trovare un tutorial sulla configurazione dei messaggi qui:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIsola | &7Aggiunto correttamente il giocatore {0} all''isola di {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lIsola | &7Aggiunto correttamente il giocatore {0} all''isola {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBanca | &7Hai depositato ${0} nella banca dell''isola di {1}'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBanca | &7Hai depositato &e${0}&f nella banca dell''isola &e{1}.'\nADMIN_HELP_FOOTER: |\n  &e&lSuperiorSkyblock &7Creato da Ome_R \n  &e&lTradotto&7 in Italiano da xSavior_of_God\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Comandi di Amministrazione [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is admin {0} per vedere la prossima pagina.'\nALREADY_IN_ISLAND: '&c&lErrore | &7Sei già dentro un''isola.'\nALREADY_IN_ISLAND_OTHER: '&c&lErrore | &7Questo giocatore è già membro della tua isola.'\nBAN_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato bannato dall''isola di {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi bannare solo i giocatori aventi un ruolo inferiore al tuo.'\nBANK_DEPOSIT_CUSTOM: '&e&lBanca | &7Digita l''importo che desideri depositare:'\nBANK_DEPOSIT_COMPLETED: Deposito completato\nBANK_LIMIT_EXCEED: '&c&lErrore| &7Hai superato il limite della tua banca.'\nBANK_WITHDRAW_CUSTOM: '&e&lBanca | &7Digita l''importo che desideri prelevare:'\nBANK_WITHDRAW_COMPLETED: Ritiro completato\nBANNED_FROM_ISLAND: '&c&lErrore | &7Sei stato bannato da questa isola.'\nBLOCK_COUNT_CHECK: '&e&lIsola | &7Quest''isola ha x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIsola | &7Quest'isola ha i seguenti blocchi:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIsola | &7Quest''isola non ha blocchi tracciati.'\nBLOCK_COUNTS_CHECK_MATERIAL: x{0} {1}\nBLOCK_LEVEL: '&e&lLivello | &7Il blocco {0} vale {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lLivello | &7Il blocco {0} non ha valore.'\nBLOCK_VALUE: '&e&lWorth | &7Il blocco {0} vale {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lWorth | &7Il blocco {0} non ha valore.'\nBONUS_SYNC_ALL: '&e&lIsola | &7SAggiornato con successo il bonus a tutte le isole.'\nBONUS_SYNC_NAME: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.'\nBONUS_SYNC: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Blu'\nBORDER_PLAYER_COLOR_NAME_RED: 'Rosso'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Verde'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBordo | &7Modificato con successo il colore del bordo personale in {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi costruire al di fuori del tuo raggio di protezione.'\nCANNOT_SET_ROLE: '&c&lErrore | &7Non puoi impostare il ruolo del giocatore su {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErrore | &7Puoi modificare le autorizzazioni solo per i ruoli dell''isola inferiori rispetto al tuo.'\nCHANGED_BANK_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario dell''isola di {0}.'\nCHANGED_BANK_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario di tutte le isole.'\nCHANGED_BANK_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario di {0}.'\nCHANGED_BIOME: '&e&lIsola | &7Bioma modificato con successo in {0}. Potrebbe essere necessario riconnettersi al server per vedere le modifiche.'\nCHANGED_BIOME_ALL: '&e&lIsola | &7Aggiornato con successo il bioma su {0} per tutte le isole.'\nCHANGED_BIOME_NAME: '&e&Isola | &7Aggiornato con successo il bioma su {0} per l''isola {1}.'\nCHANGED_BIOME_OTHER: '&e&lIsola | &7Aggiornato con successo il bioma su {0} per l''isola di {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocchi | &7Aggiornato con successo il numero di blocchi di {0} a {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} dell''isola {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} in tutte le isole.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} nell''isola di {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per l''isola di {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per tutte le isole.'\nCHANGED_CHEST_SIZE_NAME: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per {2}.'\nCHANGED_COOP_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di giocatori coop per l''isola di {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lAggiornamenti | &7SAggiornato con successo il limite di giocatori coop per tutte le isole.'\nCHANGED_COOP_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite di giocatori coop di {0}.'\nCHANGED_CROP_GROWTH: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture dell'' isola di {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture di tutte le isole.'\nCHANGED_CROP_GROWTH_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture dell''isola di {0}.'\nCHANGED_DISCORD: '&e&lIsola | &7Discord dell''isola cambiata con successo in {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per l''isola di {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per tutte le isola.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per l''isola {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per l''isola di {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per tutte le isole.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per l''isola {1}.'\nCHANGED_ISLAND_SIZE: '&e&lAggiornamenti | &7Aggiornata correttamente la dimensione dell''isola di {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lAggiornamenti | &7Aggiornata con successo la dimensione di tutte le isole.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lAggiornamenti | &7Aggiornato con successo la dimensione dell''isola di {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oIl giocatore ha il permesso di costruire fuori dai limiti della sua isola, però il size dell''isola non ha effetti. Puoi disattivare questa funzione dalle configurazione in modo che le dimensioni dell''isola abbiano di nuovo effetto.'\nCHANGED_LANGUAGE: '&e&lLanguage | &7Lingua cambiata in Italiano.'\nCHANGED_MOB_DROPS: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob nell''isola di {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob in tutte le isole.'\nCHANGED_MOB_DROPS_NAME: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob di {0}.'\nCHANGED_NAME: '&e&lIsola | &7Hai cambiato il nome della tua isola in {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIsola | &7Hai cambiato il nome della tua isola da {0} a {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIsola | &7Hai cambiato il nome dell''isola di {0}&7 a {1}&7.'\nCHANGED_PAYPAL: '&e&lIsola | &7Paypal dell''isola cambiato con successo in {0}.'\nCHANGED_ROLE_LIMIT: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} per l''isola di {1}.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} di tutte le isole.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} per l''isola {1}.'\nCHANGED_SPAWNER_RATES: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore degli spawner dell''isola di {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore degli spawner in tutte le isole.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore degli spawner rates dell''isola {0}.'\nCHANGED_TEAM_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite dei membri dell''isola di {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il limite dei membri di tutte le isole.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite di membri dell''isola {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lIsola | &7Aggiornato con successo lo spawn dell''isola.'\nCHANGED_WARPS_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di warps dell''isola di {0}.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lAggiornamenti | &7Aggioranto con successo il limite di warps di tutte le isole.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il mite di warps dell''isola {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: quantità\nCOMMAND_ARGUMENT_BIOME: bioma\nCOMMAND_ARGUMENT_BORDER_COLOR: 'colore-bordo'\nCOMMAND_ARGUMENT_COMMAND: 'comando...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: discord...\nCOMMAND_ARGUMENT_EFFECT: effetto-pozione\nCOMMAND_ARGUMENT_EMAIL: email\nCOMMAND_ARGUMENT_ENTITY: entità\nCOMMAND_ARGUMENT_ISLAND_NAME: nome-isola\nCOMMAND_ARGUMENT_ISLAND_ROLE: ruolo-isola\nCOMMAND_ARGUMENT_LEADER: capo\nCOMMAND_ARGUMENT_LEVEL: livello\nCOMMAND_ARGUMENT_LIMIT: limite\nCOMMAND_ARGUMENT_MATERIAL: materiale\nCOMMAND_ARGUMENT_MENU: nome-menu\nCOMMAND_ARGUMENT_MESSAGE: messagio...\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: nome-missione\nCOMMAND_ARGUMENT_MODULE_NAME: 'nome-modulo'\nCOMMAND_ARGUMENT_MULTIPLIER: moltiplicatore\nCOMMAND_ARGUMENT_NAME: nome\nCOMMAND_ARGUMENT_NEW_LEADER: nuovo-capo\nCOMMAND_ARGUMENT_PAGE: pagina\nCOMMAND_ARGUMENT_PATH: 'percorso'\nCOMMAND_ARGUMENT_PERMISSION: permesso\nCOMMAND_ARGUMENT_PLAYER_NAME: nome-giocatore\nCOMMAND_ARGUMENT_PRIVATE: privato\nCOMMAND_ARGUMENT_RATING: valutazione\nCOMMAND_ARGUMENT_ROWS: righe\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: nome-schematica\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: impostazioni\nCOMMAND_ARGUMENT_SIZE: dimensione\nCOMMAND_ARGUMENT_TIME: tempo\nCOMMAND_ARGUMENT_TITLE_DURATION: durata\nCOMMAND_ARGUMENT_TITLE_FADE_IN: dissolvenza-in-apertura\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: dissolvenza\nCOMMAND_ARGUMENT_UPGRADE_NAME: nome-aggiornamento\nCOMMAND_ARGUMENT_VALUE: valore\nCOMMAND_ARGUMENT_WARP_NAME: nome-warp\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'categoria-warp'\nCOMMAND_ARGUMENT_WORLD: mondo\nCOMMAND_COOLDOWN_FORMAT: '&c&lErrore | &7È possibile utilizzare questo comando tra {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: Accetta un invito da un giocatore.\nCOMMAND_DESCRIPTION_ADMIN: Utilizzare i comandi di amministrazione.\nCOMMAND_DESCRIPTION_ADMIN_ADD: Aggiungi un utente a un'isola.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Aumenta il limite di blocchi per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Aggiungi un bonus a un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Aumenta il limite dei giocatori coop per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Aumenta il moltiplicatore di crescita del raccolto per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Aggiungi un effetto isola per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Aumenta il limite di entità per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Aggiungi la percentuale di un materiale per il generatore di ciottoli.\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Aumenta il moltiplicatore dei mob drops per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Espandi la dimensione dell'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Aumenta il moltiplicatore dei tassi di generazione per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Aumenta il limite di membri per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Aumenta il limite di warps di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: Concedi un bonus a un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: Attiva/disattiva la modalità bypass.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: Apri il baule di un'altra isola.\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Cancella i tassi del generatore per un'isola specifica.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: Chiudi un'isola al pubblico.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Esegui un comando per tutti i membri delle isole.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: Controlla un conteggio dei blocchi su un'isola specifica.\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interagisci con i dati persistenti di giocatori o isole.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: Attiva o disattiva i messaggi di Debug.\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: Elimina un warp per un'isola.\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: Diminuisci il ruolo di un membro dell'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: Depositare denaro nella banca dell'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: Sciogli definitivamente l'isola di un  giocatore.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Aumenta la quantità di reset disponibili di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: Rimuovi un giocatore dal menu delle migliori isole.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: Unisciti a un'isola senza un invito.\nCOMMAND_DESCRIPTION_ADMIN_KICK: Caccia un giocatore dalla usa isola.\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Gestisci i moduli del plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: Cambia lo stato di una missione per un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_MSG: Invia a un giocatore un messaggio senza prefissi.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: Invia a tutti i membri dell'isola un messaggio senza prefissi.\nCOMMAND_DESCRIPTION_ADMIN_NAME: Cambia il nome di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: Apri un'isola al pubblico.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Apri un menu personalizzato per un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: Promuovi un membro nell'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_PURGE: Elimina le isole.\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: Potenzia un aggiornamento per un isola.\nCOMMAND_DESCRIPTION_ADMIN_RECALC: Ricalcola il valore di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: Ricarica tutte le configurazioni e le attività del plugin.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Rimuovi il limite di un blocco da un'isola.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite da un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Crea una schematica per il plugin.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: Imposta il bioma di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Imposta la quantità di un blocco in una posizione specifica.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Imposta il limite di un blocco per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Imposta il numero di righe del baule dell'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Imposta il limite di giocatori coop per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Imposta il moltiplicatore della crescita delle colture per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Imposta la quantità di reset dell'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Imposta il livello dell'effetto dell'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Imposta il limite di entità per l'isola di un altro giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: Trasferisci un'isola a qualcun altro.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Imposta il moltiplicatore di drops dei mob per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Imposta un ruolo richiesto per avere un'autorizzazione, in tutte le isole.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: Imposta la valutazione di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Imposta il limite di ruolo per l''isola di un altro giocatore.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Attiva/disattiva le impostazioni di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Modifica la percentuale di generazione di un materiale dal generatore di ciottoli.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: Cambia la dimensione dell'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Imposta la posizione di spawn del server.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Imposta il moltiplicatore dei tassi dei generatori di mob per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Imposta il limite dei membri per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Imposta il livello di un potenziamento per l'isola di un giocatore.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Imposta il limite delle warp di un'isola.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: Apri l'editor delle impostazioni del plugin.\nCOMMAND_DESCRIPTION_ADMIN_SHOW: Ottieni informazioni su un'isola.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Teletrasportati nella posizione di spawn.\nCOMMAND_DESCRIPTION_ADMIN_SPY: Attiva/disattiva la modalità spia della chat\nCOMMAND_DESCRIPTION_ADMIN_STATS: Mostra le statistiche riguardanti il plugin.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sincronizza il bonus di un''isola con i mondi generati.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Sincronizza i valori di aggiornamento per un'isola.\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: Teletrasporto nelle altre isole.\nCOMMAND_DESCRIPTION_ADMIN_TITLE: Invia un titolo al giocatore\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Invia un titolo a tutti i membri dell''isola'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: Smetti di ignorare un'isola dal menu delle migliori isole.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Sblocca un mondo per un'isola.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: Prelevare denaro dalla banca dell'isola di un giocatore.\nCOMMAND_DESCRIPTION_BALANCE: Controlla la quantità di denaro all'interno della banca di un'isola.\nCOMMAND_DESCRIPTION_BAN: Bandisci un giocatore dalla tua isola.\nCOMMAND_DESCRIPTION_BANK: Apri la banca dell'isola.\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: Cambia il bioma dell'isola.\nCOMMAND_DESCRIPTION_BORDER: Cambia il colore del bordo delle isole.\nCOMMAND_DESCRIPTION_CHEST: Apri il baule dell'isola.\nCOMMAND_DESCRIPTION_CLOSE: Chiudi l'isola al pubblico.\nCOMMAND_DESCRIPTION_COOP: Aggiungi un giocatore come coop alla tua isola.\nCOMMAND_DESCRIPTION_COOPS: Apri il menu Coops.\nCOMMAND_DESCRIPTION_COUNTS: Vedi il numero dei blocchi della tua isola.\nCOMMAND_DESCRIPTION_CREATE: Crea una nuova isola.\nCOMMAND_DESCRIPTION_DEL_WARP: Elimina una warp dell'isola.\nCOMMAND_DESCRIPTION_DEMOTE: Diminuisci il ruolo di un membro nella tua isola.\nCOMMAND_DESCRIPTION_DEPOSIT: Deposita i soldi dal tuo conto personale nella banca dell'isola.\nCOMMAND_DESCRIPTION_DISBAND: Sciogli la tua isola in modo permanente.\nCOMMAND_DESCRIPTION_EXPEL: Caccia a un visitatore della tua isola.\nCOMMAND_DESCRIPTION_FLY: Attiva/Disattiva la modalità volo nella tua isola.\nCOMMAND_DESCRIPTION_HELP: Elenco di tutti i comandi.\nCOMMAND_DESCRIPTION_INVITE: Invita un giocatore sulla tua isola.\nCOMMAND_DESCRIPTION_KICK: Caccia un giocatore dalla tua isola.\nCOMMAND_DESCRIPTION_LANG: Cambia la lingua dei messaggi.\nCOMMAND_DESCRIPTION_LEAVE: Lascia la tua isola.\nCOMMAND_DESCRIPTION_MEMBERS: Apri il menu dei membri.\nCOMMAND_DESCRIPTION_MISSION: Completa una missione.\nCOMMAND_DESCRIPTION_MISSIONS: Apri il menu delle missioni.\nCOMMAND_DESCRIPTION_NAME: Cambia il nome della tua isola.\nCOMMAND_DESCRIPTION_OPEN: Apri l'isola al pubblico.\nCOMMAND_DESCRIPTION_PANEL: Apri il pannello dell'isola.\nCOMMAND_DESCRIPTION_PARDON: Perdona(Sbandisci) un giocatore dalla tua isola.\nCOMMAND_DESCRIPTION_PERMISSIONS: Ottieni tutte le autorizzazioni per un ruolo dell'isola.\nCOMMAND_DESCRIPTION_PROMOTE: Promuovi un membro nella tua isola.\nCOMMAND_DESCRIPTION_RANKUP: Sali di livello un aggiornamento dell'isola.\nCOMMAND_DESCRIPTION_RATE: Valuta un isola.\nCOMMAND_DESCRIPTION_RATINGS: Visualizza tutte le valutazioni dell'isola.\nCOMMAND_DESCRIPTION_SETTINGS: Apri il menu delle impostazioni.\nCOMMAND_DESCRIPTION_RECALC: Ri-calcola il valore della tua isola.\nCOMMAND_DESCRIPTION_SET_DISCORD: Imposta il link discord dell'isola per i pagamenti dell'isola.\nCOMMAND_DESCRIPTION_SET_PAYPAL: Imposta l'e-mail paypal dell'isola per i pagamenti dell'isola.\nCOMMAND_DESCRIPTION_SET_ROLE: Cambia il ruolo di un giocatore nella tua isola.\nCOMMAND_DESCRIPTION_SET_TELEPORT: Cambia la posizione del teletrasporto della tua isola.\nCOMMAND_DESCRIPTION_SET_WARP: Crea una nuova warp dell'isola.\nCOMMAND_DESCRIPTION_SHOW: Ottieni informazioni su un'isola.\nCOMMAND_DESCRIPTION_TEAM: Ottieni informazioni sullo stato dei membri dell'isola.\nCOMMAND_DESCRIPTION_TEAM_CHAT: Attiva/disattiva la modalità chat di gruppo.\nCOMMAND_DESCRIPTION_TELEPORT: Teletrasportati sulla tua isola.\nCOMMAND_DESCRIPTION_TOGGLE: Attiva/disattiva i bordi dell'isola e i posizionamenti di blocchi sovrapposti.\nCOMMAND_DESCRIPTION_TOP: Apri il menu delle migliori isole.\nCOMMAND_DESCRIPTION_TRANSFER: Trasferisci la leadership della tua isola.\nCOMMAND_DESCRIPTION_UNCOOP: Rimuovi un giocatore dall'essere un coop nella tua isola.\nCOMMAND_DESCRIPTION_UPGRADE: Apri il pannello degli aggiornamenti.\nCOMMAND_DESCRIPTION_VALUE: Ottieni il valore di un blocco.\nCOMMAND_DESCRIPTION_VALUES: Apri il menu dei valori.\nCOMMAND_DESCRIPTION_VISIT: Teletrasportati nell'isola di un giocatore.\nCOMMAND_DESCRIPTION_VISITORS: Apri il menu dei visitatori.\nCOMMAND_DESCRIPTION_WARP: Teletrasportati ad una warp dell'isola.\nCOMMAND_DESCRIPTION_WARPS: Apri il menu delle warp.\nCOMMAND_DESCRIPTION_WITHDRAW: Prelevare denaro dalla banca della tua isola sul tuo conto personale.\nCOMMAND_USAGE: '&cUsa: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lIsola | &7{0} ha aggiunto {1} come membro coop dell''isola.'\nCOOP_BANNED_PLAYER: '&c&lErrore | &7Questo giocatore è bannato dall''isola e non può essere un mebro coop.'\nCOOP_LIMIT_EXCEED: '&c&lErrore | &7Hai raggiunto il numero massimo di giocatori coop che l''isola può avere.'\nCREATE_ISLAND: '&e&lIsola | &7Creata una nuova isola a {0} in {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lErrore | &7Si è verificato un errore durante la creazione della tua isola. Si prega di contattare l''amministratore per indagare sul problema.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Debug mode &cOFF&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Debug mode &aON&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lIsola | &7Hai eliminato la warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oC''era un cartello per quel warp, è stato rimosso....'\nDEMOTE_LEADER: '&c&lErrore | &7Non puoi degradare i capi dell''isola.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi degradare solo i giocatori con un ruolo dell''isola inferiore al tuo.'\nDEMOTED_MEMBER: '&e&lIsola | &7Hai degradato {0} a {1}.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBanca | &7{0} ha depositato ${1} nella banca dell''isola!'\nDEPOSIT_ERROR: '&c&lErrore| &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi distruggere al di fuori del tuo raggio di protezione.'\nDISBAND_ANNOUNCEMENT: '&e&lIsola | &7La tua isola è stata sciolta da {0}.'\nDISBAND_GIVE: '&e&lIsola | &7Hai ricevuto {0} reset da poter usare.'\nDISBAND_GIVE_ALL: '&e&lIsola | &7Hai dato {0} reset in più a tutti i giocatori.'\nDISBAND_GIVE_OTHER: '&e&lIsola | &7Hai dato {0} reset a {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oLa tua isola è stata sciolta e ${0} dollari sono stati rimborsati sul tuo conto dalla banca dell''isola'\nDISBAND_SET: '&e&lIsola | &7Il tuo limite di reset è stato impostato a {0}.'\nDISBAND_SET_ALL: '&e&lIsola | &7Hai impostato il limite di reset a {0} per tutte le isole.'\nDISBAND_SET_OTHER: '&e&lIsola | &7Hai impostato i reset dell''isola di {0} a {1}.'\nDISBANDED_ISLAND: '&e&lIsola | &7Hai sciolto la tua isola.'\nDISBANDED_ISLAND_OTHER: '&e&lIsola | &7Hai sciolto l''isola di {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lIsola | &7Hai sciolto l''isola {0}.'\nENTER_PVP_ISLAND: '&7&oSei stato teletrasportato in un''isola con PVP abilitato. Sei immune al PVP per i prossimi 10 secondi...'\nEXPELLED_PLAYER: '&e&lIsola | &7{0} è stato espulso dall''isola.'\nFORMAT_QUAD: Q\nFORMAT_TRILLION: T\nFORMAT_BILLION: B\nFORMAT_MILLION: M\nFORMAT_THOUSANDS: K\nFORMAT_SECONDS_NAME: secondi\nFORMAT_SECOND_NAME: secondo\nFORMAT_MINUTES_NAME: minuti\nFORMAT_MINUTE_NAME: minuto\nFORMAT_HOURS_NAME: ore\nFORMAT_HOUR_NAME: ora\nFORMAT_DAYS_NAME: giorni\nFORMAT_DAY_NAME: giorno\nGENERATOR_CLEARED: '&e&lIsola | &7Cancellati con successo gli importi del generatore per l''isola di {0}.'\nGENERATOR_CLEARED_NAME: '&e&lIsola | &7Cancellati con successo gli importi del generatore per l''isola {0}.'\nGENERATOR_CLEARED_ALL: '&e&lIsola | &7Cancellati con successo gli importi del generatore per tutte le isole.'\nGENERATOR_UPDATED: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} sull''isola di {1}.'\nGENERATOR_UPDATED_NAME: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} sull''isola {1}.'\n\nGLOBAL_COMMAND_EXECUTED: '&e&lIsola | &7Successfully executed the command on {0}''s island members!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsola | &7Successfully executed the command on the island members of {0}!'\nGENERATOR_UPDATED_ALL: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} in tutte le isole.'\nGLOBAL_MESSAGE_SENT: '&e&lIsola | &7Il messaggio è stato inviato correttamente ai membri dell''isola di {0}!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lIsola | &7Il messaggio è stato inviato correttamente ai membri dell''isola di {0}!'\nGLOBAL_TITLE_SENT: '&e&lIsola | &7Il titolo è stato inviato con successo ai membri dell''isola di {0}!'\nGLOBAL_TITLE_SENT_NAME: '&e&lIsola | &7Il titolo è stato inviato con successo ai membri dell''isola {0}!'\nGOT_BANNED: '&e&lIsola | &7Sei stato bannato dall''isola di {0}.'\nGOT_DEMOTED: '&e&lIsola | &7Sei stato retrocesso a {0} nella tua isola.'\nGOT_EXPELLED: '&e&lIsola | &7&o{0} ti ha espulso dall''isola.'\nGOT_INVITE: '&e&lIsola | &7{0} ti ha invitato nella sua isola.'\nGOT_INVITE_TOOLTIP: '&7Clicca il messaggio per accettare l''invito.'\nGOT_KICKED: '&e&lIsola | &7{0} ti ha cacciato dall''isola.'\nGOT_PROMOTED: '&e&lIsola | &7Sei stato promosso a {0} nella tua isola.'\nGOT_REVOKED: '&e&lIsola | &7{0} ha revocato il suo invito.'\nGOT_UNBANNED: '&e&lIsola | &7Sei stato sbannato dall''isola di {0}.'\nHIT_ISLAND_MEMBER: '&c&lErrore | &7Non puoi colpire i membri della tua isola.'\nHIT_PLAYER_IN_ISLAND: '&c&lErrore | &7Non puoi colpire i giocatori all''interno delle isole affinchè non venga attivato il pvp nell''isola (/is settings).'\nIGNORED_ISLAND: '&e&lIsola | &7L''isola di {0] da ora in poi verrà ignorata dalle migliori isole.'\nIGNORED_ISLAND_NAME: '&e&lIsola | &7L''isola {0} da ora in poi verrà ignorata dalle migliori isole.'\nINTERACT_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi interagire al di fuori del tuo raggio di protezione.'\nINVALID_AMOUNT: '&c&lErrore | &7Importo invalido {0}.'\nINVALID_BIOME: '&c&lErrore | &7Bioma invalido {0}.'\nINVALID_BLOCK: '&c&lErrore| &7Posizione del blocco invalida {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Colore del bordo non valido: {0}'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lErrore| &7Effetto invalido {0}.'\nINVALID_ENTITY: '&c&lErrore | &7Entità invalida {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lError | &7Intervallo non valido: {0}'\nINVALID_ISLAND: '&c&lErrore | &7Non hai un''isola.'\nINVALID_ISLAND_LOCATION: '&c&lErrore | &7Non c''è un isola nella tua posizione.'\nINVALID_ISLAND_OTHER: '&c&lErrore | &7{0} non ha un isola.'\nINVALID_ISLAND_OTHER_NAME: '&c&lErrore | &7Non esiste un isola col nome di {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lErrore | &7Impossibile trovare il permesso dell''isola {0}.\n  &c&lErrore | &7Autorizzazioni dell''isola: {1}\nINVALID_LEVEL: '&c&lErrore | &7Livello non valido {0}.'\nINVALID_LIMIT: '&c&lErrore | &7Limite non valido {0}.'\nINVALID_MATERIAL: '&c&lErrore | &7Materiale non valido {0}.'\nINVALID_MATERIAL_DATA: '&c&lErrore | &7Il material-data non è corretto {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lErrore | &7La missione {0} non è corretta.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lError | &7Modulo non valido: {0}'\nINVALID_MULTIPLIER: '&c&lErrore | &7Il moltiplicatore {0} non è corretto.'\nINVALID_PAGE: '&c&lErrore | &7La pagina {0} non è corretta.'\nINVALID_PERCENTAGE: '&c&lErrore | &7La percentuale deve essere compresa tra 0 e 100.'\nINVALID_PLAYER: '&c&lErrore | &7Non sono riuscito a trova il giocatore {0}'\nINVALID_RATE: |\n  &c&lErrore | &7Impossibile trovare una valutazione con il nome {0}.\n  &c&lErrore | &7Valutazioni dell''isola: {1}\nINVALID_ROWS: '&c&lErrore | &7Il numero di righe non è corretto: {0}'\nINVALID_ROLE: |\n  &c&lErrore | &7Impossibile trovare il ruolo dell''isola {0}.\n  &c&lErrore | &7Ruoli dell'isola: {1}\nINVALID_SCHEMATIC: '&c&lErrore | &7Non ho trovato la schematica di nome {0}.'\nINVALID_SETTINGS: |\n  &c&lErrore | &7Impossibile trovare le impostazioni dell''isola {0}.\n  &c&lErrore | &7Impostazioni dell'isola: {1}\nINVALID_SIZE: '&c&lErrore | &7Dimensioni non valide {0}.'\nINVALID_SLOT: '&c&lErrore | &7Slot non valido {0}.'\nINVALID_TITLE: '&c&lErrore | &7Il titolo inserito non è valido'\nINVALID_TOGGLE_MODE: '&c&lErrore | &7Non è possibile attivare/disattivare {0}.'\nINVALID_UPGRADE: |\n  &c&lErrore | &7Impossibile trovare un aggiornamento chiamato {0}.\n  &c&lErrore | &7Aggiornamenti: {1}\nINVALID_VISIT_LOCATION: '&c&lErrore | &7Quest''isola non ha alcuna impostato la posizione dei visitatori.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oHai la modalità bypass, teletrasportandoti sull''isola...'\nINVALID_WARP: '&c&lErrore | &7Warp invalida {0}.'\nINVALID_WORLD: '&c&lErrore| &7Mondo invalido {0}.'\nINVITE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha invitato {1} nella squadra dell''isola.'\nINVITE_BANNED_PLAYER: '&c&lErrore | &7Questo giocatore è bannato dall''isola e non può essere invitato.'\nINVITE_TO_FULL_ISLAND: '&c&lErrore | &7Non puoi invitare altri membri sulla tua isola.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lErrore | &7Un''isola con quel nome esiste già.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBanca | &7La banca dell''isola è vuota.'\nISLAND_BANK_SHOW: '&e&lBanca | &7La tua isola ha ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBanca | &7L''isola di {0} ha ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanca | &7L''isola {0} ha ${1}.'\nISLAND_BEING_CALCULATED: '&c&lErrore | &7Non è possibile interagire con i blocchi durante il ricalcolo dell''isola!'\nISLAND_CLOSED: '&e&lIsola | &7Chiusa con successo l''isola al pubblico.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lErrore | &7Hai un''attività di creazione dell''isola già in corso.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsola | &7Elaborazione della richiesta...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lFly | &7La modalità volo dell''isola è stata  &cdisattivata&7 automaticamente.'\nISLAND_FLY_ENABLED: '&e&lFly | &7La modalità volo dell''isola è stata  &aattivata&7 automaticamente.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsola | &7&oSei stato all''interno di un''isola che è stata sciolta, quindi sei stato teletrasportato allo spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIsola | &7&oSei stato all''interno di un''isola che aveva attivato il pvp, quindi sei stato di nuovo teletrasportato allo spawn...'\nISLAND_HELP_FOOTER: |\n  &e&lSuperiorSkyblock &7Creato da Ome_R\n  &e&lTradotto&7 in Italiano da xSavior_of_God\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista dei comandi [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is help {0} per girare pagina.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsola | &7Bank Limit: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lIsola | &7Limite dei blocchi:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsola | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsola | &7Coop Limit: {0}'\n\n\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIsola | &7Effetti dell'isola:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsola | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIsola | &7Limite Entità:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsola | &7  {0}: {1}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore delle colture: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore dei drops dei mob: {0}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lIsola | &7Percentuali del generatore:\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsola | &7  {0}: {1}%'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIsola | &7Limiti del ruolo:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsola | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lIsola | &7Dimensione dei bordi: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore dei generatori di mob: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsola | &7Limite del team: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lIsola | &7Aggiornamenti:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsola | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsola | &7Limite di warps: {0}'\nISLAND_INFO_BANK: '&e&lIsola | &7Banca: {0}'\nISLAND_INFO_BONUS: '&e&lIsola | &7Valore Bonus: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIsola | &7Livello Bonus: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIsola | &7Tempo di creazione: {0}'\nISLAND_INFO_DISCORD: '&e&lIsola | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lIslola | &7Ultimo aggiornamento: {0} fa'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsola | &7Ultimo aggiornamento: &aAttualmente Attivo'\nISLAND_INFO_LEVEL: '&e&lIsola | &7Livello: {0}'\nISLAND_INFO_LOCATION: '&e&lIsola | &7Casa: {0}'\nISLAND_INFO_NAME: '&e&lIsola | &7Nome: {0}'\nISLAND_INFO_OWNER: '&e&lIsola | &7Capo: {0}'\nISLAND_INFO_PAYPAL: '&e&lIsola | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lIsola | &7 - {0}'\nISLAND_INFO_RATE: '&e&lIsola | &7Valutazione: {0} &7({1}/5) - valutato da {2} giocatore/i.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lIsola | &7{0}:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIsola | &7Numero di visitatori: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lIsola | &7Valore: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIsola | &7Aperta con successo l''isola al pubblico.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lAnteprima | &7Sei andato troppo lontano, non sei più in modalità anteprima.'\nISLAND_PREVIEW_CANCEL: '&e&lAnteprima | &7Hai annullato la modalità di anteprima.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFERMA'\nISLAND_PREVIEW_CANCEL_TEXT: 'ANNULLA'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lAnteprima | &7Hai avviato la modalità di anteprima per la schematica {0}.\n  &e&lAnteprima | &7Scrivi &a&lCONFERMA &7per creare una nuova isola, oppure &c&lANNULLA &7per annullare la modalità di anteprima.\n  &e&lAnteprima | &7Non è possibile lasciare l'area dell'isola, altrimenti la modalità anteprima verrà annullata automaticamente.\nISLAND_PROTECTED: '&c&lErrore | &7Quest''isola è protetta.'\nISLAND_PROTECTED_OPPED: '&7&oPuoi aggirare questa restrizione utilizzando \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lIsola | &7Membri dell''isola di {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Disconnesso)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Connesso)'\nISLAND_TEAM_STATUS_ROLES: '&e&lIsola | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Disconnesso)'\nISLAND_TOP_STATUS_ONLINE: '&a(Connesso)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Privato]'\nISLAND_WAS_CLOSED: '&e&lIsola | &7&oL''isola in cui ti trovavi è stata chiusa e sei stato teletrasportato allo spawn...'\nISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.'\nISLAND_WORTH_RESULT: '&e&lIsola | &7Il valore della tua isola è {0} [Livello {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lError | &7L''attività di calcolo è scaduta. Riprovare più tardi...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lIsola | &7{0} si è unito alla tua isola.'\nJOIN_ANNOUNCEMENT: '&e&lIsola | &7{0} si è unito alla tua isola.'\nJOIN_FULL_ISLAND: '&c&lErrore | &7Quest''isola ha raggiunto il numero massimo di membri consentiti.'\nJOIN_WHILE_IN_ISLAND: '&c&lErrore | &7Sei già dentro un''isola.'\nJOINED_ISLAND: '&e&lIsola | &7Ti sei unito all''isola di {0}.'\nJOINED_ISLAND_NAME: '&e&lIsola | &7Ti sei unito all''isola {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lIsola | &7Ora sei un membro coop dell''isola di {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lIsola | &7Ora sei un membro coop dell''isola {0}.'\nKICK_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato cacciato dall''isola da {1}.'\nKICK_ISLAND_LEADER: '&c&lErrore | &7Non puoi cacciare il capo dell''isola, per farlo usa /is admin disband'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi cacciare solo giocatori con un ruolo insulare inferiore al tuo.'\nLACK_CHANGE_PERMISSION: '&c&lErrore | &7È necessario disporre di questa autorizzazione per cambiarla in altri ruoli.'\nLAST_ROLE_DEMOTE: '&c&lErrore | &7Non puoi più degradare questo giocatore.'\nLAST_ROLE_PROMOTE: '&c&lErrore | &7Non puoi più promuovere questo giocatore.'\nLEAVE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha lasciato l''isola.'\nLEAVE_ISLAND_AS_LEADER: |\n  &c&lErrore | &7Non puoi lasciare la tua isola quando la possiedi.\n  &c&lErrore | &7È possibile trasferire la proprietà utilizzando /is transfer.\nLEFT_ISLAND: '&e&lIsola | &7Hai lasciato la tua isola.'\nLEFT_ISLAND_COOP: '&e&lIsola | &7Non sei più un membro coop dell''isola di {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lIsola | &7Non sei più un membro coop dell''isola {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lErrore | &7È necessario fornire un materiale solido.'\nMAXIMUM_LEVEL: '&c&lErrore | &7Il livello massimo per questo aggiornamento è {0}.'\nMESSAGE_SENT: '&e&lIsola | &7{0} inviato correttamente il messaggio!'\nMISSION_CANNOT_COMPLETE: '&c&lErrore | &7Non puoi ancora completare questa missione.'\nMISSION_NO_AUTO_REWARD: '&e&lMission | &7Hai tutti i materiali necessari per finire {0} - usa /is missions per completarlo!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErrore | &7Devi completare la missione {0} prima di completare questa missione.'\nMISSION_STATUS_COMPLETE: '&e&lMission | &7Modificato lo stato della missione {0} da completare per {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Modificato lo stato di tutte le missioni da completare per {0}.'\nMISSION_STATUS_RESET: '&e&lMission | &7Ripristinato lo stato della missione {0} per {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMission | &7Ripristina lo stato di tutte le missioni per {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7Questo modulo è già caricato.'\nMODULE_INFO: |\n  &e&lModule | &7{0} by {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Caricamento del modulo {0} avvenuto con successo.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Impossibile caricare il modulo {0}. Controlla la console per ulteriori informazioni.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Modulo disabilitato con successo.'\nMODULES_LIST: '&fModuli ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIsola | &7{0} ha cambiato il nome della sua isola in {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lErrore | &7Non puoi usare quel nome.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lErrore | &7Non puoi usare i nomi dei giocatori come nome dell''isola.'\nNAME_TOO_LONG: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza superiore a {0} caratteri.'\nNAME_TOO_SHORT: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza inferiore a {0} caratteri.'\nNO_BAN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter vietare i giocatori.'\nNO_CLOSE_BYPASS: '&c&lErrore | &7Quest''isola non è aperta al pubblico.'\nNO_CLOSE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per chiudere l''isola al pubblico.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per aggiungere giocatori come membri coop.'\nNO_DELETE_WARP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per eliminare le warp.'\nNO_DEMOTE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per degradare i giocatori.'\nNO_DEPOSIT_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per depositare denaro nella banca dell''isola.'\nNO_DISBAND_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per sciogliere la tua isola.'\nNO_EXPEL_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per espellere i giocatori dalla tua isola.'\nNO_INVITE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per invitare i giocatori.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lErrore | &7Devi essere {0} per accedere al baule dell''isola.'\nNO_ISLAND_INVITE: '&c&lErrore | &7Impossibile trovare inviti da quest''isola.'\nNO_ISLANDS_TO_PURGE: '&c&lErrore | &7Non ci sono isole da eliminare.'\nNO_KICK_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cacciare i giocatori.'\nNO_MORE_DISBANDS: '&c&lErrore | &7Non puoi più sciogliere altre isole.'\nNO_MORE_WARPS: '&c&lErrore | &7La tua isola non può avere più warp.'\nNO_NAME_PERMISSION: '&c&lErrore | &7Non puoi cambiare il nome della tua isola.'\nNO_OPEN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per aprire l''isola al pubblico.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lErrore | &7Devi avere almeno {0} per ottenere informazioni sulle autorizzazioni.'\nNO_PROMOTE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per promuovere i giocatori.'\nNO_RANKUP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter potenziare gli aggiornamenti.'\nNO_RATINGS_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per verificare le valutazioni.'\nNO_SET_BIOME_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare il bioma dell''isola.'\nNO_SET_DISCORD_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare il Discord dell''isola.'\nNO_SET_HOME_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare la posizione del teletrasporto dell''isola.'\nNO_SET_PAYPAL_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare l''email PayPal dell''isola.'\nNO_SET_ROLE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare i ruoli per i giocatori.'\nNO_SET_SETTINGS_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per modificare le impostazioni dell''isola.'\nNO_SET_WARP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare le warp dell''isola.'\nNO_TRANSFER_PERMISSION: '&c&lErrore | &7Devi essere il capo dell''isola per trasferire la leadership.'\nNO_UNCOOP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per rimuovere i giocatori dall''essere membri coop.'\nNO_UPGRADE_PERMISSION: '&c&lErrore | &7Ti manca l''autorizzazione per passare a un altro livello.'\nNO_WITHDRAW_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per prelevare denaro dalla banca dell''isola.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErrore | &7Non hai abbastanza soldi per depositare {0} dollari nella banca della tua isola.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErrore | &7Non hai abbastanza soldi.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7Non hai abbastanza soldi per usare le deformazioni dell''isola.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oNon credi di essere troppo stanco per interagire con i menu?'\nPANEL_TOGGLE_OFF: |\n  &e&lPanel | &7Pannello dell'isola impostato &cOFF&7.\n  &e&lPanel | &7Eseguendo /is ti teletrasporterai sulla tua isola.\nPANEL_TOGGLE_ON: |\n  &e&lPanel | &7Pannello dell'isola impostato &aON&7.\n  &e&lPanel | &7Eseguendo /is aprirà il pannello per te.\nPERMISSION_CHANGED: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} dell''isola di {1}.'\nPERMISSION_CHANGED_NAME: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} dell''isola {1}.'\nPERMISSION_CHANGED_ALL: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} di tutte le isola.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7Nessun dato trovato per la tua query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIsola | &7Successfully reset all the permissions for {0} to default values!'\nPERMISSIONS_RESET_ROLES: '&e&lIsola | &7Successfully reset all the permissions of the island to default values!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Si'\nPLAYER_ALREADY_BANNED: '&c&lErrore | &7Questo giocatore è già stato bannato.'\nPLAYER_ALREADY_COOP: '&c&lErrore | &7Questo giocatore è già un membro coop.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lErrore | &7Questo giocatore è già all''interno di un''isola.'\nPLAYER_ALREADY_IN_ROLE: '&c&lErrore | &7{0} è già un {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lErrore | &7Questo utente non può essere espulso dall''isola.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIsola | &7{0} è entrato nel server.'\nPLAYER_NOT_BANNED: '&c&lErrore | &7Questo giocatore non è bannato.'\nPLAYER_NOT_COOP: '&c&lErrore | &7Questo giocatore non è un membro coop.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lErrore | &7Questo giocatore non è all''interno della tua isola.'\nPLAYER_NOT_ONLINE: '&c&lErrore | &7Questo giocatore non è in linea!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lIsola | &7{0} è uscito dal server.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi promuovere solo giocatori con un ruolo inferiore al tuo.'\nPROMOTED_MEMBER: '&e&lIsola | &7Hai promosso {0} a {1} nella sua isola.'\nPURGE_CLEAR: '&e&lIsola | &7Eliminate con successo tutte le isole in coda da eliminare.'\nPURGED_ISLANDS: |\n  &e&lIsola | &7{0} isole verranno eliminate al riavvio del server.\n  &e&lIsola | &7Puoi annullarlo in qualsiasi momento utilizzando /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola di {1}.'\nRANKUP_SUCCESS_ALL: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per tutte le isole.'\nRANKUP_SUCCESS_NAME: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha valutato la tua isola {1} stelle su 5!'\nRATE_CHANGE_OTHER: '&e&lIsola | &7Hai cambiato la valutazione di {0} a {1}.'\nRATE_OWN_ISLAND: '&c&lErrore | &7Non puoi valutare la tua isola.'\nRATE_REMOVE_ALL: '&e&lIsola | &7Rimosse con successo tutte le valutazioni di {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lIslola | &7Rimosse con successo le valutazioni di tutte le isole.'\nRATE_SUCCESS: '&e&lIsola | &7Hai valutato quest''isola con {0} stelle!'\nREACHED_BLOCK_LIMIT: '&e&lAggiornamenti | &7Hai raggiunto il limite di {0} dell''isola.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lErrore | &7La tua isola è già in fase di ricalcolo.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lErrore | &7L''isola è già stata ricalcolata.'\nRECALC_ALL_ISLANDS: '&e&lIsola | &7Ricalcolo di tutte le isole...'\nRECALC_ALL_ISLANDS_DONE: '&e&lIsola | &7Completato con successo il ricalcolo di tutte le isole.'\nRECALC_PROCCESS_REQUEST: '&e&lIsola | &7Elaborazione della richiesta...'\nRELOAD_COMPLETED: '&e&lIsola | &7Il reload è terminato!'\nRELOAD_PROCCESS_REQUEST: '&e&lIsola | &7Starting to reload configurations...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha revocato l''invito di {1}.'\nRESET_WORLD_SUCCEED: '&e&lIsola | &7Ripristinato il mondo {0} con successo per l''isola di {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIsola | &7Ripristinato il mondo {0} con successo per tutte le isole.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIsola | &7Ripristinato il mondo {0} con successo per {1}.'\nSAME_NAME_CHANGE: '&c&lErrore | &7Devi inserire un nome diverso dal tuo attuale nome dell''isola.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posizione selezionata #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lErrore | &7Non hai selezionato due posizioni.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Elaborazione della richiesta...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematics | &7Hai selezionato due posizioni. Esegui /is admin schematic <nome> per creare una nuova schematica.\n  &e&lSchematics | &7Assicurati di trovarti nella posizione di teletrasporto quando esegui il comando.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posizione selezionata #1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematics | &7Schematica salvata con successo!'\nSELF_ROLE_CHANGE: '&c&lErrore | &7Non puoi cambiare il tuo ruolo.'\nSET_UPGRADE_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per l''isola di {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per {1}.'\nSET_WARP: '&e&lIsola | &7Creato con successo un nuovo warp a {0}.'\nSET_WARP_OUTSIDE: '&c&lErrore | &7Non puoi impostare warp fuori dalla tua isola.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} dell''isola di {1}.'\nSETTINGS_UPDATED_NAME: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} di {1}.'\nSETTINGS_UPDATED_ALL: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} a tutte le isole.'\nSIZE_BIGGER_MAX: '&c&lErrore | &7Non è possibile impostare una dimensione maggiore della dimensione massima dell''isola.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Hai teletrasportato {0} con successo allo spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7La posizione di spawn è stata aggiornata correttamente alle coordinate: {0}'\nSPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade dell''isola di {0}.'\nSYNC_UPGRADES_ALL: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade di tutte le isole.'\nSYNC_UPGRADES_NAME: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade di {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErrore | &7Non sei nella tua isola.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi teletrasportarti fuori dal raggio di protezione.'\nTELEPORT_WARMUP: '&7&oVerrai teletrasportato in {0}... Non muoverti!'\nTELEPORT_WARMUP_CANCEL: '&7&oTi sei mosso e quindi il teletrasporto è stato cancellato.'\nTITLE_SENT: '&e&lIsola | &7Inviato con successo il titolo {0}'\nTELEPORTED_FAILED: '&e&lIsola | &7Sembra che quest''isola non abbia blocchi sicuri. Si prega di contattare un membro dello staff.'\nTELEPORTED_SUCCESS: '&e&lIsola | &7Sei stato teletrasportato sulla tua isola.'\nTELEPORTED_TO_WARP: '&e&lIsola | &7Teletrasportato con successo al warp dell''isola.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsola | &7Il giocatore {0} si è teletrasportato alla warp {1} dell''isola.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Modalità bypass &cOFF&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Modalità bypass &aON&7.'\nTOGGLED_FLY_OFF: '&e&lFly | &7Modalità volo &cOFF&7.'\nTOGGLED_FLY_ON: '&e&lFly | &7Modalità volo &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Modalità schematica &cOFF&7.'\nTOGGLED_SCHEMATIC_ON: |\n  &e&lSchematics | &7Schematic mode &aON&7.\n  &e&lSchematics | &7Seleziona un'area usando un'ascia d'oro.\nTOGGLED_SPY_OFF: '&e&lSpy | &7Spy chat &cOFF&7.'\nTOGGLED_SPY_ON: '&e&lSpy | &7Spy chat &aON&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Stacker di blocchi &cOFF&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Stacker di blocchi &aON&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Chat di squadra &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Chat di squadra &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Bordi del mondo &cOFF&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Bordi del mondo &aON&7.'\nTRANSFER_ADMIN: '&e&lIsola | &7Hai trasferito la leadership di {0} a {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lErrore | &7{0} è già il leader della sua isola.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErrore | &7Questi giocatori non sono nelle stesse isole.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lErrore | &7Questo giocatore non è un leader di nessuna isola.'\nTRANSFER_ALREADY_LEADER: '&c&lErrore | &7Sei già il capo di quest''isola.'\nTRANSFER_BROADCAST: '&e&lIsola | &7La leadership dell''isola è stata trasferita a {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato sbannato dall''isola da {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lIsola | &7{0} ha rimosso {1} dall''essere un membro coop.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsola | &7Non ci sono membri dell''isola online e quindi sei stato espulso automaticamente.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsola | &7{0} è uscito dal server, non è più un membro coop.'\nUNIGNORED_ISLAND: '&e&lIsola | &7L''isola di {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).'\nUNIGNORED_ISLAND_NAME: '&e&lIsola | &7L''isola {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lIsola | &7&oSembra che questa warp non sia sicura. Per favore, prova un altra warp.'\nUPDATED_PERMISSION: '&e&lIsola | &7Autorizzazioni aggiornate per {0}.'\nUPDATED_SETTINGS: '&e&lIsola | &7Aggiornate le impostazioni dell''isola {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Puoi eseguire nuovamente l''aggiornamento solo tra {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lErrore | &7Non puoi usare questo comando quando ti trovi sopra ad altre isole.'\nWARP_ALREADY_EXIST: '&c&lErrore | &7C''è già una warp con questo nome.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Inserisci una nuova descrizione (Scrivi \"-cancel\" per annullare)\n  &e&lWarps | &7È possibile separare le righe utilizzando \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Inserisci un nome (Scrivi \"-cancel\" per annullare):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Inserisci un nuovo tipo di materiale (Scrivi \"-cancel\" per annullare):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Icona della categoria aggiornata con successo.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lErrore | &7I nomi delle categorie delle warps non possono essere vuoti.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lErrore | &7I nomi delle categorie delle warps non possono essere più lunghi di 255 caratteri.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Inserisci un nuovo slot (Scrivi \"-cancel\" per annullare):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErrore | &7Questo slot è già occupato da un''altra categoria.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Modificato con successo lo slot della categoria in {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Inserisci un nuovo nome (Scrivi \"-cancel\" per annullare):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErrore | &7Questo nome è già preso da un''altra categoria.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7La categoria è stata rinominata correttamente in {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Scrivi \"-cancel\" per annullare)\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Inserisci un nome (Scrivi \"-cancel\" per annullare):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Inserisci un nuovo tipo di materiale (Scrivi \"-cancel\" per annullare):'\nWARP_ICON_UPDATED: '&e&lWarps | &7Icona del Warp aggiornata con successo.'\nWARP_ILLEGAL_NAME: '&c&lErrore | &7I nomi di Warp non possono essere vuoti.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7La posizione del Warp è stata aggiornata con successo alla tua posizione.'\nWARP_NAME_TOO_LONG: '&c&lErrore | &7I nomi delle Warps non possono essere più lunghi di 255 caratteri.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Hai aperto con successo la Warp al pubblico.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Chiuso con successo la Warp al pubblico.'\nWARP_RENAME: '&e&lWarps | &7Inserisci un nuovo nome (Scrivi \"-cancel\" per annullare):'\nWARP_RENAME_ALREADY_EXIST: '&c&lErrore | &7Questo nome è già preso da un altra Warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Rinominato correttamente il Warp in {0}.'\nWITHDRAW_ALL_MONEY: |\n  &e&lBanca | &7La banca dell'isola ha solo {0} dollari al suo interno.\n  &e&lBanca | &7&oPrelevamento di tutti i soldi...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBanca | &7{0} ha prelevato ${1} dalla banca dell''isola!'\nWITHDRAW_ERROR: '&c&lErrore | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBanca | &7Hai ritirato ${0} dalla banca dell''isola di {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lBanca | &7Hai ritirato ${0} dalla riva dell''isola {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lMondi | &7Il mondo {0} non è ancora stato sbloccato!'\n"
  },
  {
    "path": "src/main/resources/lang/iw-IL.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIsland | &7Successfully added the player {0} to {1}''s island.'\nADMIN_ADD_PLAYER_NAME: '&e&lIsland | &7Successfully added the player {0} to the island {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lקנב | &7.{1} לש יאה לש קנבל ${0} תרבעה'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lקנב | &7.{1} יאה לש קנבל ${0} תרבעה'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Ome_R י\"ע תנכות'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7ןימדא תודוקפ תמישר [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7אבה דומעל רבעמל /is admin {0} ץרה.'\nALREADY_IN_ISLAND: '&c&lהאיגש | &7רחא יא לא ךייתשמ רבכ התא.'\nALREADY_IN_ISLAND_OTHER: '&c&lהאיגש | &7ךלש יאב אצמנ רבכ הזה ןקחשה.'\nBAN_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע יאהמ קחרוה. {0}'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7םכלשמ הכומנ הגרד ילעב םינקחש קר קיחרהל\n  םילוכי םתא.'\nBANK_DEPOSIT_CUSTOM: '&e&lBank | &7Type the amount you want to deposit:'\nBANK_DEPOSIT_COMPLETED: 'Deposit Completed'\nBANK_LIMIT_EXCEED: '&c&lError | &7You have exceeded your bank limit.'\nBANK_WITHDRAW_CUSTOM: '&e&lBank | &7Type the amount you want to withdraw:'\nBANK_WITHDRAW_COMPLETED: 'Withdraw Completed'\nBANNED_FROM_ISLAND: '&c&lהאיגש | &7יאהמ קחרומ התא.'\nBLOCK_COUNT_CHECK: '&e&lIsland | &7This island has x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIsland | &7This island has the following blocks:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIsland | &7This island has no tracked blocks.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lתודוקנ | &7{1} אוה {0} קולבה לש תודוקנה רפסמ.'\nBLOCK_LEVEL_WORTHLESS: '&e&lתודוקנ | &7םולכ הווש אל {0} קולבה.'\nBLOCK_VALUE: '&e&lיווש | &7{1} אוה {0} קולבה לש יוושה.'\nBLOCK_VALUE_WORTHLESS: '&e&lיווש | &7םולכ הווש אל {0} קולבה.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Blue'\nBORDER_PLAYER_COLOR_NAME_RED: 'Red'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Green'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lלובג | &7{0} ל החלצהב הנוש ךלש לובגה עבצ.'\nBUILD_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ תונבל לוכי אל התא.'\nCANNOT_SET_ROLE: '&c&lהאיגש | &7{0} ל ןקחשה לש הגרדה תא תונשל לוכי אל התא.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lהאיגש | &7םינקחשל ךלשמ תוכומנ רתוי תוגרד קר\n  תונשל לושכי התא.'\nCHANGED_BANK_LIMIT: '&e&lUpgrades | &7Successfully updated the bank limit of {0}''s island.'\nCHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the bank limit of all the islands.'\nCHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the bank limit of {0}.'\nCHANGED_BIOME: '&e&lיא | &7תרשל שדחמ רבחתהל שי ,םייונישה תא תוארל תנמ לע .{0}\n  ל החלצהב הנוש יאה לש םויבה.'\nCHANGED_BIOME_ALL: '&e&lIsland | &7Successfully changed biome to {0} for all the islands.'\nCHANGED_BIOME_NAME: '&e&lIsland | &7Successfully changed biome to {0} for the island {1}.'\nCHANGED_BIOME_OTHER: '&e&lIsland | &7Successfully changed biome to {0} for {1}''s island.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at {0} to {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lםיגורדש | &7{1} לש יאל החלצהב הנכדוע {0} קולבה תלבגה.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lםיגורדש | &7םייאה לכל החלצהב הנכדוע {0} קולבה תלבגה.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lםיגורדש | &7{1} יאל החלצהב הנכדוע {0} קולבה תלבגה.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.'\nCHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.'\nCHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.'\nCHANGED_COOP_LIMIT: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}''s island.'\nCHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the coop players limit of all the islands.'\nCHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}.'\nCHANGED_CROP_GROWTH: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש הלידגה סונוב.'\nCHANGED_CROP_GROWTH_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש הלידגה סונוב..'\nCHANGED_CROP_GROWTH_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש הלידגה סונוב.'\nCHANGED_DISCORD: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש דרוקסידה.'\nCHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}''s island.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for all the islands.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}''s island.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for all the islands.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}.'\nCHANGED_ISLAND_SIZE: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לדוג.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Successfully updated the island size of all the islands.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לדוג.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oPlayers are able to build outside their island, so the island size has no affect. You can toggle that feature off in the config so island size will have affect again.'\nCHANGED_LANGUAGE: '&e&lהפש | &7תירבעל החלצהב התנוש ךלש הפשה.'\nCHANGED_MOB_DROPS: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש םיבומ לש םיטירפה סונוב.'\nCHANGED_MOB_DROPS_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש םיבומ לש םיטירפה\n  סונוב.'\nCHANGED_MOB_DROPS_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש םיבומ לש םיטירפה\n  סונוב.'\nCHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.'\nCHANGED_PAYPAL: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש לאפייפה.'\nCHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.'\nCHANGED_SPAWNER_RATES: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש םירנואפסה לש רוגישה\n  סונוב.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש םירנואפסה לש\n  רוגישה סונוב.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש םירנואפסה לש\n  רוגישה סונוב.'\nCHANGED_TEAM_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש יאה לש הצובקה תלבגמ.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש הצובקה תלבגמ.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע רמוע יאה לש הצובקה תלבגמ.'\nCHANGED_TELEPORT_LOCATION: '&e&lיא | &7החלצהב ןכדוע יאה לש רוגישה םוקמ.'\nCHANGED_WARPS_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש יאה לש םימוקימה תלבגמ.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש םימוקימה תלבגמ.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע {0} יאה לש םימוקימה תלבגמ.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: תומכ\nCOMMAND_ARGUMENT_BIOME: 'biome'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: 'command...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: '...דרוקסיד'\nCOMMAND_ARGUMENT_EFFECT: 'potion-effect'\nCOMMAND_ARGUMENT_EMAIL: ליימיא\nCOMMAND_ARGUMENT_ENTITY: entity\nCOMMAND_ARGUMENT_ISLAND_NAME: יאה םש\nCOMMAND_ARGUMENT_ISLAND_ROLE: הגרד\nCOMMAND_ARGUMENT_LEADER: גיהנמ\nCOMMAND_ARGUMENT_LEVEL: המר\nCOMMAND_ARGUMENT_LIMIT: הלבגמ\nCOMMAND_ARGUMENT_MATERIAL: רמוח\nCOMMAND_ARGUMENT_MENU: 'menu-name'\nCOMMAND_ARGUMENT_MESSAGE: '...העדוה'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: המישמה םש\nCOMMAND_ARGUMENT_MODULE_NAME: 'module-name'\nCOMMAND_ARGUMENT_MULTIPLIER: סונוב\nCOMMAND_ARGUMENT_NAME: םש\nCOMMAND_ARGUMENT_NEW_LEADER: שדח גיהנמ\nCOMMAND_ARGUMENT_PAGE: דומע\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: תושר\nCOMMAND_ARGUMENT_PLAYER_NAME: ןקחשה םש\nCOMMAND_ARGUMENT_PRIVATE: יטרפ\nCOMMAND_ARGUMENT_RATING: גוריד\nCOMMAND_ARGUMENT_ROWS: rows\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: הנבמה םש\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: תורדגה\nCOMMAND_ARGUMENT_SIZE: לדוג\nCOMMAND_ARGUMENT_TIME: ןמז\nCOMMAND_ARGUMENT_TITLE_DURATION: 'duration'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out'\nCOMMAND_ARGUMENT_UPGRADE_NAME: גורדשה םש\nCOMMAND_ARGUMENT_VALUE: יווש\nCOMMAND_ARGUMENT_WARP_NAME: םוקימה םש\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category'\nCOMMAND_ARGUMENT_WORLD: 'world'\nCOMMAND_COOLDOWN_FORMAT: '&c&lהאיגש | &7{0} ב הדוקפב בוש שמתשהל לוכי התא.'\nCOMMAND_DESCRIPTION_ACCEPT: םינקחשמ יאל הנמזה רשאל.\nCOMMAND_DESCRIPTION_ADMIN: .ןימדאה תודוקפב שמתשהל.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: יאל סונוב תתל.\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Increase the crop growth multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Add an island effect for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Increase entity limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Add percentage of a material for the cobblestone generator.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Increase the mob drops multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expand another player''s island size.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Increase the spawner rates multiplier for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Increase members limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Increase the warps limit of an island.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: הפיקע בצמ ףילחהל.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Open island''s chest of another island.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Clear generator rates for a specific island.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: רוביצל יא רוגסל.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Check a block count on a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Toggle debug outputs.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: רחא יאב ןקחש הגרדב דירוהל.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: רחא יא לש קנב לא ףסכ ריבעהל.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: רחא ןקחש לש יא קוחמל.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: ןקחשל םייא תוקיחמ תתל.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: רתויב םיבוטה םייאה תמישרמ יא דירוהל.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: הנמזה אלל יאל סנכיהל.\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Kick a player from his island.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: ןקחש רובע המישמ לש סוטטס תונשל.\nCOMMAND_DESCRIPTION_ADMIN_MSG: העדוה ןקחשל חולשל.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: העדוה יא לש םינקחשה לכל חולשל.\nCOMMAND_DESCRIPTION_ADMIN_NAME: יא לש םשה תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: רוביצל יא חותפל.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Open a custom menu for a player.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: רחא יאב ןקחש הגרדב תולעהל.\nCOMMAND_DESCRIPTION_ADMIN_PURGE: .םייא תוקנל\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: יא לש יווש שדחמ בשחל.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: ןיגאלפה לש םיצבקה לכ תא שדחמ ןועטל.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: ןקחש ידי לע ונתנש םיגורידה לכ תא קוחמל.\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: ןיגאלפל שדח הנבמ רוציל.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: רחא ןקחש לש יאל םיקולב לש הלבגה תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Set the chest rows for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Set coop players limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: רחא ןקחש לש יא של הלידגה סונוב תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: ןקחש לש תורתומה תוקיחמה תומכ תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Set entity limit for another player''s island.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: רחא ןקחשל יא לע תוגיהנמה תא ריבעהל.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: רחא ןקחש לש יא לש םיבומ לש םיטירפה סונוב\n  תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: םייאה לכל תמייוסמ תושרל תרתומה הגרדה תא\n  תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: יאל ןתנ ןקחשש גוריד תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: יאל הרדגה ףילחהל.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: רוטרנ'גמ והשלכ רמוח לש זוחא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: ןקחש לש יא לש לדוג תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Set the spawn location of the server.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: רחא ןקחש לש יא לש םירנואפסה סונוב תא\n  תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: רחא ןקחש לש יא לש םינקחש תלבגה תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: רחא ןקחש לש יא לש גורדש לש המרה תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: רחא ןקחש לש יא לש םימוקימה תלבגה תא תונשל.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Open the plugin settings editor.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: יא לע עדימ לבקל.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Teleport to the spawn location.\nCOMMAND_DESCRIPTION_ADMIN_SPY: יומס טא'צ בצמ ףילחהל.\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Show stats about the plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sync upgrade values for an island.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: רחא יא לא רגתשהל.\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: םיבוטה םייאה תמישרל יא ריזחהל.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: יאל םלוע חותפל.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: רחא ןקחש לש יאמ ףסכ איצוהל.\nCOMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.'\nCOMMAND_DESCRIPTION_BAN: ךלש יאהמ ןקחש קיחרהל.\nCOMMAND_DESCRIPTION_BANK: 'Open the island''s bank.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: יאה לש םויבה תא ףילחהל.\nCOMMAND_DESCRIPTION_BORDER: םייאה לש לובגה עבצ תא ףילחהל.\nCOMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.'\nCOMMAND_DESCRIPTION_CLOSE: רוביצל יאה תא רוגסל.\nCOMMAND_DESCRIPTION_COOP: יאה לש הלועפ ףתשמכ ןקחש ףיסוהל.\nCOMMAND_DESCRIPTION_COOPS: 'Open the coops menu.'\nCOMMAND_DESCRIPTION_COUNTS: 'See block counts in your island.'\nCOMMAND_DESCRIPTION_CREATE: שדח יא רוציל.\nCOMMAND_DESCRIPTION_DEL_WARP: יאב םוקימ קוחמל.\nCOMMAND_DESCRIPTION_DEMOTE: יאב ןקחש הגרדב דירוהל.\nCOMMAND_DESCRIPTION_DEPOSIT: יאה לש קנבל ךלש ןובשחהמ ףסכ דיקפהל.\nCOMMAND_DESCRIPTION_DISBAND: תותימצל יאה תא קוחמל.\nCOMMAND_DESCRIPTION_EXPEL: יאהמ רקבמ שרגל.\nCOMMAND_DESCRIPTION_FLY: יאב הפועת בצמ ףילחהל.\nCOMMAND_DESCRIPTION_HELP: תודוקפה לכ תמישר.\nCOMMAND_DESCRIPTION_INVITE: ךלש יאה לא ןקחש ןימזהל.\nCOMMAND_DESCRIPTION_KICK: יאהמ ןקחש ףיעהל.\nCOMMAND_DESCRIPTION_LANG: ךלש הפשה תא ףילחהל.\nCOMMAND_DESCRIPTION_LEAVE: יאה תא בוזעל.\nCOMMAND_DESCRIPTION_MEMBERS: םינקחשה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_MISSION: המישמ םילשהל.\nCOMMAND_DESCRIPTION_MISSIONS: תומישמה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_NAME: יאה םש תא תונשל.\nCOMMAND_DESCRIPTION_OPEN: רוביצל יאה תא חותפל.\nCOMMAND_DESCRIPTION_PANEL: יאה לש ישארה טירפתה תא חותפל.\nCOMMAND_DESCRIPTION_PARDON: יאהמ ןקחש לש הקחרה דירוהל.\nCOMMAND_DESCRIPTION_PERMISSIONS: יאב הגרד לש תואשרהב תופצל.\nCOMMAND_DESCRIPTION_PROMOTE: יאב ןקחש הגרדב תולעהל.\nCOMMAND_DESCRIPTION_RANKUP: גורדש המרב תולעהל.\nCOMMAND_DESCRIPTION_RATE: יא גרדל.\nCOMMAND_DESCRIPTION_RATINGS: יאה לש םיגורידה לכב תופצל.\nCOMMAND_DESCRIPTION_SETTINGS: יאה לש תורדגהה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_RECALC: יאה יווש תא שדחמ בשחל.\nCOMMAND_DESCRIPTION_SET_DISCORD: יאה לש דרוקסידה תא תונשל.\nCOMMAND_DESCRIPTION_SET_PAYPAL: יאה לש לאפייפה תא תונשל.\nCOMMAND_DESCRIPTION_SET_ROLE: יאב ןקחש לש הגרד תונשל.\nCOMMAND_DESCRIPTION_SET_TELEPORT: יאה לש רוגישה םוקמ תא תונשל.\nCOMMAND_DESCRIPTION_SET_WARP: יאב שדח םוקימ רוציל.\nCOMMAND_DESCRIPTION_SHOW: יאה לע עדימ גיצהל.\nCOMMAND_DESCRIPTION_TEAM: יאה לש םינקחשה לש עדימ גיצהל.\nCOMMAND_DESCRIPTION_TEAM_CHAT: יתצובק טא'צ בצמ ףילחהל.\nCOMMAND_DESCRIPTION_TELEPORT: יאה לא רגתשהל.\nCOMMAND_DESCRIPTION_TOGGLE: םייא תולובגו םיקולב גוזימ יבצמ ףילחהל.\nCOMMAND_DESCRIPTION_TOP: םיבוטה םייאה תמישר טירפת תא חותפל.\nCOMMAND_DESCRIPTION_TRANSFER: יאה תוגיהנמ תא ריבעהל.\nCOMMAND_DESCRIPTION_UNCOOP: יאה לש הלועפ ףתשמ תויהלמ ןקחש דירוהל.\nCOMMAND_DESCRIPTION_UPGRADE: םיגורדשה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_VALUE: קולב לש יווש גיצהל.\nCOMMAND_DESCRIPTION_VALUES: 'Open the values menu.'\nCOMMAND_DESCRIPTION_VISIT: יאה לש םירקבמה תדוקנל רגתשהל.\nCOMMAND_DESCRIPTION_VISITORS: םירקבמה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_WARP: יאב םוקימל רגתשהל.\nCOMMAND_DESCRIPTION_WARPS: םימוקימה טירפת תא חותפל.\nCOMMAND_DESCRIPTION_WITHDRAW: ךלש יטרפה ןובשחל יאה קנבמ ףסכ ךושמל.\nCOMMAND_USAGE: '&cשומיש: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lיא | &7יאה לש הלועפ ףתשמכ {1} תא ףיסוה {0}.'\nCOOP_BANNED_PLAYER: '&c&lהאיגש | &7הלועפ ףתשמכ ףסוותהל לוכי אלו יאהמ קחרומ הזה ןקחשה.'\nCOOP_LIMIT_EXCEED: '&c&lError | &7You reached the maximum amount of coop players the island can have.'\nCREATE_ISLAND: '&e&lיא | &7היינשה תופילא {1} ךות {0} ב שדח יא תרצי.'\nCREATE_ISLAND_FAILURE: '&c&lError | &7An error occurred while creating your island. Please contact the administrator to investigate the issue.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Toggled debug mode &cOFF&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Toggled debug mode &aON&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lיא | &7{0} םוקימה תא תקחמ.'\nDELETE_WARP_SIGN_BROKE: '&7&o...רבשנ אוה ,טלש הזה םוקימל היה.'\nDEMOTE_LEADER: '&c&lError | &7You cannot demote island leaders.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ הגרד ילעב םינקחש קר הגרדב\n  דירוהל לוכי התא.'\nDEMOTED_MEMBER: '&e&lיא | &7ולש יאב {1} הגרדל {0} תא הגרדב תדרוה.'\nDEPOSIT_ANNOUNCEMENT: '&e&lקנב | &7יאה לש קנבה לא ${0} דיקפה רמוע!'\nDEPOSIT_ERROR: '&c&lError | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ סורהל לוכי אל התא.'\nDISBAND_ANNOUNCEMENT: '&e&lיא | &7{0} ידי לע קחמנ ךלש יאה.'\nDISBAND_GIVE: '&e&lיא | &7תורתומ תוקיחמ {0} דוע תלביק.'\nDISBAND_GIVE_ALL: '&e&lיא | &7םינקחשה לכל תורתומ תוקיחמ {0} דוע תתנ.'\nDISBAND_GIVE_OTHER: '&e&lיא | &7{1} ל תורתומ תוקיחמ {0} דוע תתנ.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank'\nDISBAND_SET: '&e&lיא | &7{0} ל התנוש ךלש תורתומה תוקיחמה תומכ.'\nDISBAND_SET_ALL: '&e&lיא | &7{0} ל םינקחשה לכ לש תורתומה תוקיחמה תומכ תא תיניש.'\nDISBAND_SET_OTHER: '&e&lיא | &7{1} ל {0} לש תורתומה תוקיחמה תומכ תא תיניש.'\nDISBANDED_ISLAND: '&e&lיא | &7ךלש יאה תא תקחמ.'\nDISBANDED_ISLAND_OTHER: '&e&lיא | &7{0} לש יאה תא תקחמ.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lיא | &7{0} יאה תא תקחמ.'\nENTER_PVP_ISLAND: '&7&oתוינש 10 כ ךשמב תוכמ לבקת אל התא .תוכמ וב תתל ןתינש יא לא תרגוש...'\nEXPELLED_PLAYER: '&e&lיא | &7יאה ןמ שרוג {0}.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: תוינש\nFORMAT_SECOND_NAME: היינש\nFORMAT_MINUTES_NAME: תוקד\nFORMAT_MINUTE_NAME: הקד\nFORMAT_HOURS_NAME: תועש\nFORMAT_HOUR_NAME: העש\nFORMAT_DAYS_NAME: םימי\nFORMAT_DAY_NAME: םוי\nGENERATOR_CLEARED: '&e&lIsland | &7Successfully cleared the generator amounts for {0}''s island.'\nGENERATOR_CLEARED_NAME: '&e&lIsland | &7Successfully cleared the generator amounts for the island of {0}.'\nGENERATOR_CLEARED_ALL: '&e&lIsland | &7Successfully cleared the generator amounts for all the islands.'\nGENERATOR_UPDATED: '&e&lיא | &7החלצהב ןכדוע {1} לש יאה לש רוטארנגב {0} רמוחה לש\n  תומכה.'\nGENERATOR_UPDATED_NAME: '&e&lיא | &7החלצהב ןכדוע {1} יאה לש רוטארנגב {0} רמוחה\n  לש תומכה.'\nGENERATOR_UPDATED_ALL: '&e&lיא | &7החלצהב ןכדוע םייאה לכ לש רוטארנגב {0} רמוחה\n  לש תומכה.'\nGLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lיא | &7{0} לש יאה לש םינקחשל החלצהב החלשנ העדוהה!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lיא | &7{0} יאה לש םינקחשל החלצהב החלשנ העדוהה!'\nGLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!'\nGLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!'\nGOT_BANNED: '&e&lיא | &7רמוע לש יאה ןמ תקחרוה.'\nGOT_DEMOTED: '&e&lיא | &7ךלש יאב {0} תגרדל הגרדב תדרי.'\nGOT_EXPELLED: '&e&lיא | &7{0} ידי לע יאה ןמ תשרוג.'\nGOT_INVITE: '&e&lיא | &7ולש יאה לא ךתוא ןימזה {0}.'\nGOT_INVITE_TOOLTIP: '&7הנמזהה תא רשאל תנמ לע העדוהה לע ץחל.'\nGOT_KICKED: '&e&lיא | &7{0} ידי לע ךלש יאה ןמ תפעוה.'\nGOT_PROMOTED: '&e&lיא | &7ךלש יאב {0} תגרדל הגרדב תלעוה.'\nGOT_REVOKED: '&e&lיא | &7ולש יאל ךלש הנמזהה תא לטיב {0}.'\nGOT_UNBANNED: '&e&lיא | &7הדרי {0} לש יאהמ ךלש הקחרהה.'\nHIT_ISLAND_MEMBER: '&c&lהאיגש | &7ךלש יאהמ םינקחשל תוכמ תתל לוכי אל התא.'\nHIT_PLAYER_IN_ISLAND: '&c&lהאיגש | &7םייא ךותב םינקחשל תוכמ תתל לוכי אל התא.'\nIGNORED_ISLAND: '&e&lיא | &7םיבוטה םייאה תמישר ןמ דרי {0} לש יאה.'\nIGNORED_ISLAND_NAME: '&e&lיא | &7םיבוטה םייאה תמישר ןמ דרי {0} יאה.'\nINTERACT_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ םירבד םע היצקרטניא עצבל לוכי\n  אל התא.'\nINVALID_AMOUNT: '&c&lהאיגש | &7{0} תיקוח אל תומכ.'\nINVALID_BIOME: '&c&lError | &7Invalid biome {0}.'\nINVALID_BLOCK: '&c&lError | &7Invalid block location {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lError | &7Invalid effect {0}.'\nINVALID_ENTITY: '&c&lError | &7Invalid entity {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.'\nINVALID_ISLAND: '&c&lהאיגש | &7יא ךל ןיא.'\nINVALID_ISLAND_LOCATION: '&c&lהאיגש | &7ךלש םוקימב יא ןיא.'\nINVALID_ISLAND_OTHER: '&c&lהאיגש | &7יא ןיא {0} ל.'\nINVALID_ISLAND_OTHER_NAME: '&c&lהאיגש | &7{0} םשה םע יא ןיא.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lהאיגש | &7{0} האשרהה תא אוצמל היה ןתינ אל.\n  &c&lהאיגש | &7{1} :יאה תואשרה\nINVALID_LEVEL: '&c&lהאיגש | &7{0} תיקוח אל המר.'\nINVALID_LIMIT: '&c&lהאיגש | &7{0} תיקוח אל הלבגמ.'\nINVALID_MATERIAL: '&c&lהאיגש | &7{0} תיקוח אל רמוח.'\nINVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lהאיגש | &7{0} תיקוח אל המישמ.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lError | &7Invalid module {0}.'\nINVALID_MULTIPLIER: '&c&lהאיגש | &7{0} יקוח אל סונוב.'\nINVALID_PAGE: '&c&lError | &7Invalid page {0}.'\nINVALID_PERCENTAGE: '&c&lהאיגש | &7100 ל 0 ןיב תויהל בייח זוחא.'\nINVALID_PLAYER: '&c&lהאיגש | &7{0} םשה םע ןקחש אוצמל ןתינ אל.'\nINVALID_RATE: |\n  &c&lהאיגש | &7{0} םשה םע גוריד אוצמל ןתינ אל.\n  &c&lהאיגש | &7{0} :םיגוריד\nINVALID_ROWS: '&c&lError | &7Invalid amount of rows: {0}'\nINVALID_ROLE: |\n  &c&lהאיגש | &7{0} הגרדה תא אוצמל היה ןתינ אל.\n  &c&lהאיגש | &7{1} :תוגרד\nINVALID_SCHEMATIC: '&c&lהאיגש | &7{0} םשה םע הנבמ אוצמל היה ןתינ אל.'\nINVALID_SETTINGS: |\n  &c&lהאיגש | &7{0} םשה םע תורדגה אוצמל ןתינ אל.\n  &c&lהאיגש | &7{1} :תורדגה\nINVALID_SIZE: '&c&lהאיגש | &7{0} יקוח אל לדוג.'\nINVALID_SLOT: '&c&lError | &7Invalid slot {0}.'\nINVALID_TITLE: '&c&lError | &7Invalid title entered.'\nINVALID_TOGGLE_MODE: '&c&lהאיגש | &7{0} בצמ ףילחהל ןתינ אל.'\nINVALID_UPGRADE: |\n  &c&lהאיגש | &7{0} םשה םע גורדש אוצמל היה ןתינ אל.\n  &c&lהאיגש | &7{1} :םיגורדש\nINVALID_VISIT_LOCATION: '&c&lהאיגש | &7םירקבמ םוקמ ןיא הזה יאל.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oתאז לכב יאה לא ךתוא רגשמ ,לעפומ הפיקע בצמ...'\nINVALID_WARP: '&c&lהאיגש | &7{0} יקוח אל םוקימ.'\nINVALID_WORLD: '&c&lError | &7Invalid world {0}.'\nINVITE_ANNOUNCEMENT: '&e&lיא | &7יאה לא {1} תא ןימזה {0}.'\nINVITE_BANNED_PLAYER: '&c&lהאיגש | &7הנמזה לבקל לוכי אל ןכלו יאה ןמ קחרומ הזה ןקחשה.'\nINVITE_TO_FULL_ISLAND: '&c&lהאיגש | &7ךלש יאל םישנא דוע ןימזהל לוכי אל התא.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lהאיגש | &7םייק רבכ {0} םשה םע יא.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lקנב | &7קיר יאה קנב.'\nISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7The island {0} has ${1}.'\nISLAND_BEING_CALCULATED: '&c&lהאיגש | &7שדחמ בשוחמ יאהש ןמזב םיקולב תונשל לוכי אל התא!'\nISLAND_CLOSED: '&e&lיא | &7החלצהב רוביצל רגסנ יאה.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lיא | &7ךתשקב תא דבעמ...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &cקספוה&7.'\nISLAND_FLY_ENABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &aלעפוה&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lיא | &7&oןואפסה לא תרגוש ןכל ,קחמנש יא ךותב\n  תייה...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lיא | &7&oןואפסל תרגוש ןכל ,םינקחש ןיב\n  תוכמ ליעפהש יאב תייה...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7ידי לע רצונ Ome_R'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7תודוקפ תמישר [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7אבה דומעל רבעמל /is help {0} ץרה.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsland | &7Bank Limit: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lיא | &7םיקולב תלבגה:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lיא | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsland | &7Coop Limit: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIsland | &7Island Effects:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIsland | &7Entities Limits:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lיא | &7הלידג סונוב: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lיא | &7םיבוממ םיטירפ סונוב: {0}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lיא | &7רוטארנג ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lיא | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIsland | &7Role Limits:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lיא | &7לובגה לדוג: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lיא | &7םירנואפס סונוב: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lיא | &7הצובק תלבגה: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lיא | &7םיגורדש:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lיא | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsland | &7Warps Limit: {0}'\nISLAND_INFO_BANK: '&e&lיא | &7קנב: {0}'\nISLAND_INFO_BONUS: '&e&lIsland | &7Worth Bonus: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIsland | &7Level Bonus: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIsland | &7Creation Time: {0}'\nISLAND_INFO_DISCORD: '&e&lיא | &7דרוקסיד: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lיא | &7ןכדועש הנורחא םעפ: {0} ינפל'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lיא | &7ןכדועש הנורחא םעפ: &aליעפ עגרכ'\nISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}'\nISLAND_INFO_LOCATION: '&e&lיא | &7תיב: {0}'\nISLAND_INFO_NAME: '&e&lיא | &7םש: {0}'\nISLAND_INFO_OWNER: '&e&lיא | &7גיהנמ: {0}'\nISLAND_INFO_PAYPAL: '&e&lיא | &7לאפייפ: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lיא | &7 - {0}'\nISLAND_INFO_RATE: '&e&lיא | &7גוריד: {0} &7({1}/5) - םינוש םיגוריד {2}.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lיא | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lיא | &7יווש: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lיא | &7החלצהב רוביצל חתפנ יאה.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.'\nISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM'\nISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lPreview | &7You started the preview mode for the schematic {0}.\n  &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode.\n  &e&lPreview | &7You cannot leave the area of the island, otherwise the preview mode will be cancelled automatically.\nISLAND_PROTECTED: '&c&lהאיגש | &7ןגומ הזה יאה.'\nISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lיא | &7 לש יאה לש םינקחשה {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(קתונמ)'\nISLAND_TEAM_STATUS_ONLINE: '&a(רבוחמ)'\nISLAND_TEAM_STATUS_ROLES: '&e&lיא | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(קתונמ)'\nISLAND_TOP_STATUS_ONLINE: '&a(רבוחמ)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[יטרפ]'\nISLAND_WAS_CLOSED: '&e&lיא | &7&oןואפסל תרגוש ןכלו ,רוביצל רגסנ וב תייהש יאה...'\nISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.'\nISLAND_WORTH_RESULT: '&e&lיא | &7אוה ךלש יאה יווש {0} [המר {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lיא | &7ךלש יאה לא סנכנ {0}.'\nJOIN_ANNOUNCEMENT: '&e&lיא | &7ךלש יאה לא סנכנ {0}.'\nJOIN_FULL_ISLAND: '&c&lהאיגש | &7תרתומה םינקחשה תומכ תלבגמל עיגה יאה.'\nJOIN_WHILE_IN_ISLAND: '&c&lהאיגש | &7יאב אצמנ רבכ התא.'\nJOINED_ISLAND: '&e&lיא | &7{0} לש יאה לא תסנכנ.'\nJOINED_ISLAND_NAME: '&e&lיא | &7{0} יאה לא תסנכנ.'\nJOINED_ISLAND_AS_COOP: '&e&lיא | &7{0} לש יאל הלועפ ףתשמכ תסנכנ.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lיא | &7{0} יאל הלועפ ףתשמכ תסנכנ.'\nKICK_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע יאהמ ףעוה {0}.'\nKICK_ISLAND_LEADER: '&c&lError | &7You cannot kick the leader of the island, use /is admin disband instead.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ רתוי הגרד ילעב קר םינקחש ףיעהל\n  לוכי התא.'\nLACK_CHANGE_PERMISSION: '&c&lהאיגש | &7תורחא תוגרדל התוא תונשל תנמ לע האשרהה תא ךל\n  היהיש בייח התא.'\nLAST_ROLE_DEMOTE: '&c&lהאיגש | &7הזה ןקחשה תא הגרדב דירוהל דוע לוכי אל התא.'\nLAST_ROLE_PROMOTE: '&c&lהאיגש | &7הזה ןקחשה תא הגרדב תולעהל דוע לוכי אל התא.'\nLEAVE_ANNOUNCEMENT: '&e&lיא | &7יאה תא בזע {0}.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lהאיגש | &7ותוא גיהנמ התא רשאכ יאה תא בוזעל לוכי אל התא.\n  &c&lהאיגש | &7/is transfer ידי לע יאה לע תוגיהנמה תא ריבעהל לוכי התא.\nLEFT_ISLAND: '&e&lיא | &7ךלש יאה תא תבזע.'\nLEFT_ISLAND_COOP: '&e&lיא | &7{0} לש יאה לש הלועפ ףתשמ אל התא.'\nLEFT_ISLAND_COOP_NAME: '&e&lיא | &7רמוע יאה לש הלועפ ףתשמ אל התא.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lהאיגש | &7חישק רמוח סינכהל ביוחמ התא.'\nMAXIMUM_LEVEL: '&c&lהאיגש | &7{0} איה גורדשה לש תילמיסקמה המרה.'\nMESSAGE_SENT: '&e&lיא | &7החלצהב {0} לא החלשנ העדוהה!'\nMISSION_CANNOT_COMPLETE: '&c&lהאיגש | &7ןיידע המישמה תא םילשהל לוכי אל התא.'\nMISSION_NO_AUTO_REWARD: '&e&lתומישמ | &7התוא םילשהל תנמ לע /is mission complete ץרה\n  - {0} המישמה תא םילשהל תנמ לע םיכרצמה לכ תא ךל שי!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lהאיגש | &7וזה המישמה תא םילשמ התאש ינפל\n  {0} המישמה תא םילשהל בייח התא.'\nMISSION_STATUS_COMPLETE: '&e&lתומישמ | &7{1} ןקחשל העצובל התנוש {0} המישמה לש סוטטסה.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Changed the status of all the missions to completed for {0}.'\nMISSION_STATUS_RESET: '&e&lתומישמ | &7{1} ןקחשל הלחתוא {0} המישמה לש סוטטסה.'\nMISSION_STATUS_RESET_ALL: '&e&lMission | &7Reset the status of all the missions for {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.'\nMODULE_INFO: |\n  &e&lModule | &7{0} by {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.'\nMODULES_LIST: '&fModules ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lהאיגש | &7הזה םשב שמתשהל לוכי אל התא.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.'\nNAME_TOO_LONG: '&c&lהאיגש | &7םיוות {0} מ לעמ תויהל םילוכי אל םייא לש תומש.'\nNAME_TOO_SHORT: '&c&lהאיגש | &7םיוות {0} מ תוחפ תויהל םילוכי אל םייא לש תומש.'\nNO_BAN_PERMISSION: '&c&lהאיגש | &7םינקחש קיחרהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_CLOSE_BYPASS: '&c&lהאיגש | &7רוביצל חותפ אל הזה יאה.'\nNO_CLOSE_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא רוגסל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lהאיגש | &7הלועפ יפתשמכ םינקחש ףיסוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_DELETE_WARP_PERMISSION: '&c&lהאיגש | &7םימוקימ קוחמל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_DEMOTE_PERMISSION: '&c&lהאיגש | &7המרב םינקחש דירוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_DEPOSIT_PERMISSION: '&c&lהאיגש | &7יאה לש קנבב ףסכ דיקפהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_DISBAND_PERMISSION: '&c&lהאיגש | &7יאה תא קוחמל תנמ לע ןימדא תגרדב תוחפל תויהל בייח התא.'\nNO_EXPEL_PERMISSION: '&c&lהאיגש | &7יאהמ םירקבמ שרגל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_INVITE_PERMISSION: '&c&lהאיגש | &7םינקחש ןימזהל תנמ לע ןימדא תגרדב תוחפל תויהל בייח התא.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lError | &7You must be at least {0} in order to access the island''s chest.'\nNO_ISLAND_INVITE: '&c&lהאיגש | &7הזה יאהמ תונמזה אוצמל ןתינ היה אל.'\nNO_ISLANDS_TO_PURGE: '&c&lהאיגש | &7יוקינל םייא םוש ואצמנ אל.'\nNO_KICK_PERMISSION: '&c&lהאיגש | &7םינקחש ףיעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_MORE_DISBANDS: '&c&lהאיגש | &7םייא דוע קוחמל לוכי אל התא.'\nNO_MORE_WARPS: '&c&lהאיגש | &7ךלש יאל םימוקימ דוע רוציל ןתינ אל.'\nNO_NAME_PERMISSION: '&c&lהאיגש | &7ךלש יאה לש םשה תא תונשל לוכי אל התא.'\nNO_OPEN_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא חותפל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lהאיגש | &7תואשרה רובע עדימ לבקל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_PROMOTE_PERMISSION: '&c&lהאיגש | &7םינקחש הגרדב תולעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_RANKUP_PERMISSION: '&c&lהאיגש | &7םיגורדש המרב תולעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_RATINGS_PERMISSION: '&c&lהאיגש | &7םיגוריד קודבל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_BIOME_PERMISSION: '&c&lהאיגש | &7יאה לש םויבה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_DISCORD_PERMISSION: '&c&lהאיגש | &7יאה לש דרוקסידה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_HOME_PERMISSION: '&c&lהאיגש | &7יאל רוגישה םוקימ תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_PAYPAL_PERMISSION: '&c&lהאיגש | &7יאה לש לאפייפה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_ROLE_PERMISSION: '&c&lהאיגש | &7םינקחשל תוגרד תתל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_SETTINGS_PERMISSION: '&c&lהאיגש | &7יאה לש תורדגהה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_SET_WARP_PERMISSION: '&c&lהאיגש | &7יאב םימוקימ רוציל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_TRANSFER_PERMISSION: '&c&lהאיגש | &7רחא ןקחשל תוגיהנמה תא ריבעהל תנמ לע יאה גיהנמ תויהל בייח התא.'\nNO_UNCOOP_PERMISSION: '&c&lהאיגש | &7יאה לש הלועפ יפתשמ תויהלמ םישנא דירוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNO_UPGRADE_PERMISSION: '&c&lהאיגש | &7המר דועל גרדשל האשרהה ךל הרסח.'\nNO_WITHDRAW_PERMISSION: '&c&lהאיגש | &7יאה לש קנבהמ ףסכ ךושמל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lהאיגש | &7יאה לש קנבל רלוד {0} ריבעהל תנמ לע ףסכ קיפסמ ךל ןיא.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lהאיגש | &7ףסכ קיפסמ ךל ןיא.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oYou''re too tired to interact with menus, don''t you think?'\nPANEL_TOGGLE_OFF: |-\n  &e&lטירפת | &cתיביכ &יטמוטואה יאה טירפת בצמ תא7.\n  &e&lטירפת | &7יאה לא םכתא חלשת /is תצרה.\nPANEL_TOGGLE_ON: |-\n  &e&lטירפת | &aתקלדה &יטמוטואה יאה טירפת בצמ תא7.\n  &e&lטירפת | &7יאה טירפת תא חתפת /is תצרה.\nPERMISSION_CHANGED: '&e&lיא | &7החלצהב {1} לש יאב {0} האשרהה תא תיניש.'\nPERMISSION_CHANGED_NAME: '&e&lיא | &7החלצהב {1} יאב {0} האשרהה תא תיניש.'\nPERMISSION_CHANGED_ALL: '&e&lיא | &7החלצהב םייאה לכב {0} האשרהה תא תיניש.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!'\nPERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lהאיגש | &7יאהמ קחרומ רבכ הזה ןקחשה.'\nPLAYER_ALREADY_COOP: '&c&lהאיגש | &7יאה לש הלועפ ףתשמ רבכ הזה ןקחשה.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lError | &7This player is already inside an island.'\nPLAYER_ALREADY_IN_ROLE: '&c&lהאיגש | &7{1} הגרדב אצמנ רבכ {0}.'\nPLAYER_EXPEL_BYPASS: '&c&lהאיגש | &7יאהמ שרוגמ תויהל לוכי אל הזה ןקחשה.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lיא | &7תרשה לא רבחתה {0}.'\nPLAYER_NOT_BANNED: '&c&lהאיגש | &7יאהמ קחרומ וניא הזה ןקחשה.'\nPLAYER_NOT_COOP: '&c&lהאיגש | &7יאה לש הלועפ ףתשמ וניא הזה ןקחשה.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאה ךותב אצמנ אל הזה ןקחשה.'\nPLAYER_NOT_ONLINE: '&c&lהאיגש | &7רבוחמ אל הזה ןקחשה.'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lיא | &7תרשה תא בזע {0}.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ הגרד ילעב םינקחש הגרד תולעהל קר לוכי התא.'\nPROMOTED_MEMBER: '&e&lיא | &7ולש יאב {1} תגרדל {0} תא הגרדב תלעה.'\nPURGE_CLEAR: '&e&lיא | &7המישרהמ וקחמנ ,תוקנתהל םיכירצ ויהש םייאה לכ.'\nPURGED_ISLANDS: |-\n  &e&lיא | &7טרטסיר רובעי תרשה רשאכ וקנתי םייא {0}.\n  &e&lיא | &7/is admin purge cancel הדוקפה תצרה ידי לע ןמז לכב תאז לטבל ןתינ.\nRANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.'\nRANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.'\nRANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lיא | &75 ךותמ {1} ךלש יאה תא גריד {0}!'\nRATE_CHANGE_OTHER: '&e&lיא | &7{1} ל {0} לש גורידה תא תיניש.'\nRATE_OWN_ISLAND: '&c&lהאיגש | &7ךלש יאה תא גרדל לוכי אל התא.'\nRATE_REMOVE_ALL: '&e&lיא | &7החלצהב {0} לש םיגורידה לכ תא תקחמ.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.'\nRATE_SUCCESS: '&e&lיא | &7םיבכוכ {0} םע הזה יאה תא תגריד!'\nREACHED_BLOCK_LIMIT: '&e&lםיגורדש | &7{0} קולבה לש יאב םיקולבה תלבגמל תעגה.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lError | &7Your island is already being recalculated.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7This island is already being recalculated.'\nRECALC_ALL_ISLANDS: '&e&lיא | &7םייאה לכ לש יוושה תא שדחמ בשחמ...'\nRECALC_ALL_ISLANDS_DONE: '&e&lיא | &7החלצהב שדחמ ובשוח םייאה לכ.'\nRECALC_PROCCESS_REQUEST: '&e&lיא | &7ךתשקב תא דבעמ...'\nRELOAD_COMPLETED: '&e&lSuperiorSkyblock | &7החלצהב העצוב שדחמ הניעט!'\nRELOAD_PROCCESS_REQUEST: '&e&lSuperiorSkyblock | &7םיצבקה לכ תא שדחמ ןעוט...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lיא | &7יאה לא {1} לש הנמזהה תא לטיב {0}.'\nRESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.'\nSAME_NAME_CHANGE: '&c&lהאיגש | &7ךלש יאה לש יוושכעה םשהמ רחא םש סינכהל ךירצ התא.'\nSCHEMATIC_LEFT_SELECT: '&e&lםינבמ רצוי | &7היינש הדוקנ תנמיס ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lהאיגש | &7תודוקנ ינש תרחב אל.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lםינבמ רצוי | &7ךתשקב תא דבעמ...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lםינבמ רצוי | &7שדח הנבמ רוציל תנמ לע Run /is admin schematic <name> ץרה .תודוקנ יתש תרחב.\n  &e&lםינבמ רצוי | &7הדוקפה תא ץירמ התא רשאכ רגתשהל םירומא וילא רוזאב דמוע התאש בל םיש.\nSCHEMATIC_RIGHT_SELECT: '&e&lםינבמ רצוי | &7הנושאר הדוקנ תנמיס ({0})'\nSCHEMATIC_SAVED: '&e&lםינבמ רצוי | &7החלצהב רמשנ הנבמה!'\nSELF_ROLE_CHANGE: '&c&lהאיגש | &7ךמצע לש הגרדה תא תונשל לוכי אל התא.'\nSET_UPGRADE_LEVEL: '&e&lםיגורדש | &7החלצהב התנוש {1} לש יאב {0} גורדשה לש המרה.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lםיגורדש | &7החלצהב התנוש {1} יאב {0} גורדשה לש המרה.'\nSET_WARP: '&e&lיא | &7{0} ב החלצהב שדח םוקימ תרצי.'\nSET_WARP_OUTSIDE: '&c&lהאיגש | &7ךלש יאל ץוחמ םימוקימ רוציל לוכי אל התא.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lיא | &7{1} לש יאב החלצהב הנכדוע {0} הרדגהה.'\nSETTINGS_UPDATED_NAME: '&e&lיא | &7{1} יאב החלצהב הנכדוע {0} הרדגהה.'\nSETTINGS_UPDATED_ALL: '&e&lיא | &7םייאה לכב החלצהב הנכדוע {0} הרדגהה.'\nSIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[יומס] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}''s island.'\nSYNC_UPGRADES_ALL: '&e&lUpgrades | &7Successfully synced all upgrade values of all the islands.'\nSYNC_UPGRADES_NAME: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאב אצמנ אל התא.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lError | &7You cannot teleport outside of your protection range.'\nTELEPORT_WARMUP: '&7&oזוזת לא {0}... ב רגושת התא!'\nTELEPORT_WARMUP_CANCEL: '&7&oלטוב רוגישה ןכלו תזז.'\nTITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!'\nTELEPORTED_FAILED: '&e&lיא | &7תרשה תווצל הנפת אנא .יאב חוטב םוקמ ןיא יכ הארנ.'\nTELEPORTED_SUCCESS: '&e&lיא | &7ךלש יאל תרגוש.'\nTELEPORTED_TO_WARP: '&e&lיא | &7החלצהב יאה םוקימל תרגוש.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.'\nTOGGLED_BYPASS_OFF: '&e&lהפיקע | &7הפיקעה בצמ תא &cתיביכ&7.'\nTOGGLED_BYPASS_ON: '&e&lהפיקע | &7הפיקעה בצמ תא &aתקלדה&7.'\nTOGGLED_FLY_OFF: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &cתיביכ&7.'\nTOGGLED_FLY_ON: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &aתקלדה&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &cתיביכ&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &aתקלדה&7.\n  &e&lםינבמ רצוי | בהז ןזרג תרזעב רוזא ןמס.\nTOGGLED_SPY_OFF: '&e&lיומס | &7יומסה טא''צה בצמ תא &cתיביכ&7.'\nTOGGLED_SPY_ON: '&e&lיומס | &7יומסה טא''צה בצמ תא &aתקלדה&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lםיקולב גוזימ | &7םיקולב גוזימה בצמ תא &cתיביכ&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lםיקולב גוזימ | &7םיקולב גוזימה בצמ תא &aתקלדה&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lטא''צ | &7Toggling team chat &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lטא''צ | &7Toggling team chat &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lלובג | &7יתצובקה טא''צה בצמ תא &cתיביכ&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lלובג | &7יתצובקה טא''צה בצמ תא &aתקלדה&7.'\nTRANSFER_ADMIN: '&e&lיא | &7{1} לא {0} לש יאה תגהנה תא תרבעה.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lהאיגש | &7ולש יאה לש גיהנמה רבכ {0}.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lהאיגש | &7יאה ותואב אל הלאה םינקחשה.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lהאיגש | &7יא ףא גיהנמ אל הזה ןקחשה.'\nTRANSFER_ALREADY_LEADER: '&c&lהאיגש | &7הזה יאה לש גיהנמה רבכ התא.'\nTRANSFER_BROADCAST: '&e&lיא | &7{0} לא הרבע יאה תוגיהנמ.'\nUNBAN_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע הלטוב {0} לש הקחרהה.'\nUNCOOP_ANNOUNCEMENT: '&e&lיא | &7יאה לש הלועפ ףתשמכ {1} תא דירוה {0}.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lיא | &7דוע יאה לש הלועפ ףתשמ וניא ןכלו תרשה תא בזע {0}.'\nUNIGNORED_ISLAND: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} לש יאה.'\nUNIGNORED_ISLAND_NAME: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} יאה.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lיא | &7&oרחא םוקימ הסנ אנא .חוטב וניא םוקימה יכ הארנ.'\nUPDATED_PERMISSION: '&e&lיא | &7{0} ל תואשרהה ונכדוע.'\nUPDATED_SETTINGS: '&e&lיא | &7{0} תורדגהה ונכדוע.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lהאיגש | &7םירחא םייאב וזה הדוקפב שמתשהל לוכי אל התא.'\nWARP_ALREADY_EXIST: '&c&lהאיגש | &7הזה םשה םע םוקימ םייק רבכ.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Enter a new lore (Type \"-cancel\" to cancel):\n  &e&lWarps | &7You can separate lines by using \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type \"-cancel\" to cancel):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type \"-cancel\" to cancel):'\nWARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.'\nWARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.'\nWARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.'\nWARP_RENAME: '&e&lWarps | &7Enter a new name (Type \"-cancel\" to cancel):'\nWARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lקנב | &7וכותב םירלוד {0} קר שי יאה לש קנבב.\n  &e&lקנב | &7&oףסכה לכ תא ךשומ...\nWITHDRAW_ANNOUNCEMENT: '&e&lקנב | &7יאה לש קנבהמ ${1} ךשמ {0}!'\nWITHDRAW_ERROR: '&c&lError | &7{0}.'\nWITHDRAWN_MONEY: '&e&lקנב | &7{1} לש יאה לש קנבהמ ${0} תכשמ!'\nWITHDRAWN_MONEY_NAME: '&e&lקנב | &7{1} יאה לש קנבהמ ${0} תכשמ!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lתומלוע | &7הזה יאב חותפ אל ןיידע {0} םלועה.'\n"
  },
  {
    "path": "src/main/resources/lang/pl-PL.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lWyspa | &7Pomyslnie dodano gracza {0} do wyspy {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lWyspa | &7Pomyslnie dodano gracza {0} do wyspy {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBank | &7Wplaciles {0}$ do banku wyspy {1}.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7Wplaciles ${0} na do wyspy {1}.'\nADMIN_HELP_FOOTER: '&e&lSkyblock &7Opracowany przez Ome_R'\nADMIN_HELP_HEADER: '&e&lSkyblock &7Lista poleceń administratora [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Uzyj /is admin {0} na nastepnej stronie.'\nALREADY_IN_ISLAND: '&c&lBlad | &7Jestes juz na wyspie.'\nALREADY_IN_ISLAND_OTHER: '&c&lBlad | &7Ten gracz jest juz czlonkiem Twojej wyspy.'\nBAN_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal ZBANOWANY na wyspie przez {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz zbanowac tylko graczy z nizsza rola wyspy niz twoja.'\nBANK_DEPOSIT_CUSTOM: '&e&lBank | &7Wpisz kwote, która chcesz wplacic:'\nBANK_DEPOSIT_COMPLETED: 'Wplata zakończona'\nBANK_LIMIT_EXCEED: '&c&lBlad | &7Przekroczyles limit bankowy.'\nBANK_WITHDRAW_CUSTOM: '&e&lBank | &7Wpisz kwote, która chcesz wyplacic:'\nBANK_WITHDRAW_COMPLETED: 'Wyplata zakończona'\nBANNED_FROM_ISLAND: '&c&lBlad | &7Masz zakaz wstepu na te wyspe.'\nBLOCK_COUNT_CHECK: '&e&lWyspa | &7Ta wyspa ma x{0} {1}.'\nBLOCK_COUNTS_CHECK: '|\n&e&lWyspa | &7Ta wyspa ma nastepujace bloki:\n&7{0}'\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lWyspa | &7Ta wyspa nie ma sledzonych bloków.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lLevel | &7Poziom bloku {0} to {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Blok {0} jest bezwartosciowy.'\nBLOCK_VALUE: '&e&lWartosc | &7Blok {0} o wartosci {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lWartosc | &7Blok {0} jest bezwartosciowy.'\nBONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands'\nBONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.'\nBONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Niebieski'\nBORDER_PLAYER_COLOR_NAME_RED: 'Czerwony'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Zielony'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBariera | &7Pomyslnie zmieniono kolor bariery na {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz budowac poza bariera.'\nCANNOT_SET_ROLE: '&c&lBlad | &7Nie mozesz ustawic roli gracza na {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lBlad | &7Mozesz zmienic uprawnienia tylko na nizsza role wyspy niz twoja.'\nCHANGED_BANK_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit banku wyspy {0}.'\nCHANGED_BANK_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bankowy wszystkich wysp.'\nCHANGED_BANK_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bankowy w wysokosci {0}.'\nCHANGED_BIOME: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0}. Aby zobaczyc zmiany, moze byc konieczne ponowne polaczenie z serwerem.'\nCHANGED_BIOME_ALL: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wszystkich wysp.'\nCHANGED_BIOME_NAME: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wyspy {1}.'\nCHANGED_BIOME_OTHER: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wyspy {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Pomyslnie zmieniono wielkosc bloku z {0} na {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bloków {0} wyspy {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} blokowania wszystkich wysp.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit blokowania {0} {1}.'\nCHANGED_BONUS_LEVEL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wyspy {0}.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wszystkich wysp.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu {0}.'\nCHANGED_BONUS_WORTH: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wyspy {0}.'\nCHANGED_BONUS_WORTH_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wszystkich wysp.'\nCHANGED_BONUS_WORTH_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci {0}.'\nCHANGED_CHEST_SIZE: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze strony nr {0} na {1} dla wyspy {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze na stronie nr {0} do {1} dla wszystkich wysp.'\nCHANGED_CHEST_SIZE_NAME: '&e&lSkrzynia | &7Pomyslnie zaktualizowano wiersze strony nr {0} do {1} dla {2}.'\nCHANGED_COOP_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy na wyspie {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy na wszystkich wyspach.'\nCHANGED_COOP_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy wynoszacy {0}.'\nCHANGED_CROP_GROWTH: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu plonów wyspy {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu upraw na wszystkich wyspach.'\nCHANGED_CROP_GROWTH_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu plonów wynoszacy {0}.'\nCHANGED_DISCORD: '&e&lWyspa | &7Pomyslnie zmieniono niezgodnosc wyspy na {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla wyspy {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla wszystkich wysp.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom efektu wyspy {0} dla wyspy {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAktualizacje | &7Sukces'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom efektu wyspowego {0} dla {1}.'\nCHANGED_ISLAND_SIZE: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wyspy {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wszystkich wysp.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wyspy {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oGracze moga budowac poza swoja wyspa, wiec rozmiar wyspy nie ma zadnego wplywu. Mozesz wylaczyc te funkcje w konfiguracji, aby rozmiar wyspy znów mial wplyw.'\nCHANGED_LANGUAGE: '&e&lJezyk | &7Pomyslnie zmieniono jezyk na angielski.'\nCHANGED_MOB_DROPS: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów z wyspy {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania z mobów na wszystkich wyspach.'\nCHANGED_MOB_DROPS_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów wynoszacy {0}.'\nCHANGED_NAME: '&e&lWyspa | &7Zmieniles nazwe swojej wyspy na {0}&7.'\nCHANGED_NAME_OTHER: '&e&lWyspa | &7Zmieniles nazwe wyspy {0} na {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lWyspa | &7Zmieniles nazwe {0}&7 na {1}&7.'\nCHANGED_PAYPAL: '&e&lWyspa | &7Pomyslnie zmieniono paypal wyspy na {0}.'\nCHANGED_ROLE_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wyspy {1}.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wszystkich wysp.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla {1}.'\nCHANGED_SPAWNER_RATES: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik liczby odradzajacych sie wyspy {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik liczby pojawiajacych sie na wszystkich wyspach.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wspólczynników pojawiania sie {0}.'\nCHANGED_TEAM_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit zespolu wyspy {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit druzyn na wszystkich wyspach.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit zespolu {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lWyspa | &7Pomyslnie zaktualizowano lokalizacje teleportu.'\nCHANGED_WARPS_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow wyspy {0}.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warp na wszystkich wyspach.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: 'kwota'\nCOMMAND_ARGUMENT_BIOME: 'biom'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: 'polecenie...'\nCOMMAND_ARGUMENT_DIMENSION: 'wymiar'\nCOMMAND_ARGUMENT_DISCORD: 'niezgoda...'\nCOMMAND_ARGUMENT_EFFECT: 'efekt mikstury'\nCOMMAND_ARGUMENT_EMAIL: 'e-mail'\nCOMMAND_ARGUMENT_ENTITY: 'podmiot'\nCOMMAND_ARGUMENT_ISLAND_NAME: 'nazwa-wyspy'\nCOMMAND_ARGUMENT_ISLAND_ROLE: 'rola-wyspy'\nCOMMAND_ARGUMENT_LEADER: 'lider'\nCOMMAND_ARGUMENT_LEVEL: 'poziom'\nCOMMAND_ARGUMENT_LIMIT: 'limit'\nCOMMAND_ARGUMENT_MATERIAL: 'material'\nCOMMAND_ARGUMENT_MENU: 'nazwa-menu'\nCOMMAND_ARGUMENT_MESSAGE: 'wiadomosc...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'kategoria misji'\nCOMMAND_ARGUMENT_MISSION_NAME: 'nazwa misji'\nCOMMAND_ARGUMENT_MODULE_NAME: 'nazwa-modulu'\nCOMMAND_ARGUMENT_MULTIPLIER: 'mnoznik'\nCOMMAND_ARGUMENT_NAME: 'nazwa'\nCOMMAND_ARGUMENT_NEW_LEADER: 'nowy lider'\nCOMMAND_ARGUMENT_PAGE: 'strona'\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: 'uprawnienie'\nCOMMAND_ARGUMENT_PLAYER_NAME: 'nazwa gracza'\nCOMMAND_ARGUMENT_PRIVATE: 'prywatny'\nCOMMAND_ARGUMENT_RATING: 'ocena'\nCOMMAND_ARGUMENT_ROWS: 'wiersze'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: 'nazwa schematu'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: 'ustawienia'\nCOMMAND_ARGUMENT_SIZE: 'rozmiar'\nCOMMAND_ARGUMENT_TIME: 'czas'\nCOMMAND_ARGUMENT_TITLE_DURATION: 'czas trwania'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'zanikanie'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'zanikanie'\nCOMMAND_ARGUMENT_UPGRADE_NAME: 'nazwa uaktualnienia'\nCOMMAND_ARGUMENT_VALUE: 'wartosc'\nCOMMAND_ARGUMENT_WARP_NAME: 'nazwa wypaczenia'\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'kategoria wypaczenia'\nCOMMAND_ARGUMENT_WORLD: 'swiat'\nCOMMAND_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uzywac tylko polecenia w {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: 'Zaakceptuj zaproszenie od gracza.'\nCOMMAND_DESCRIPTION_ADMIN: 'Uzyj poleceń administratora.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Dodaj uzytkownika do wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Zwieksz limit banku dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Zwieksz limit bloków dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Dodaj bonus do gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Zwieksz limit graczy w trybie wspólpracy na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Zwieksz mnoznik wzrostu plonów na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Dodaj efekt wyspy dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Zwieksz limit jednostek dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Dodaj procent materialu do generatora kostki brukowej.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Zwieksz mnoznik dropów z mobów dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Zwieksz rozmiar wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Zwieksz mnoznik wspólczynników pojawiania sie na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Zwieksz limit czlonków na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Zwieksz limit wypaczeń wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: 'Przyznaj graczowi bonus.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: 'Przelacz tryb obejscia.'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Otwórz skrzynie innej wyspy na wyspie.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Wyczysc stawki generatora dla okreslonej wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: 'Zamknij wyspe dla publicznosci.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Wykonaj polecenie dla wszystkich czlonków wysp.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Sprawdz liczbe bloków na okreslonej wyspie.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Przelacz wyjscia debugowania.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Usuń warp dla wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Zdegraduj czlonka na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Wplac pieniadze do banku wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: 'Rozwiaz wyspe innego gracza na stale.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Daj rozwiazania graczowi.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignoruj ​​wyspe z najlepszych wysp.'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: 'Dolacz do wyspy bez zaproszenia.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Wyrzuc gracza z jego wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Zarzadzaj modulami wtyczki.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: 'Zmień status misji gracza.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: 'Wyslij graczowi wiadomosc bez zadnych prefiksów.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Wyslij do wszystkich czlonków wyspy wiadomosc bez zadnych prefiksów.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: 'Zmień nazwe wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: 'Otwórz wyspe dla publicznosci.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Otwórz niestandardowe menu gracza.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Awansuj czlonka na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: 'Oczysc wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Ranguj ulepszenie wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: 'Ponownie oblicza wartosc wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: 'Zaladuj ponownie wszystkie konfiguracje i zadania wtyczki.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Usuń limit bloków z wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Usun limit bytów z wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Usuń wszystkie oceny wystawione przez gracza.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Zresetuj wszystkie uprawnienia wyspy dla konkretnej wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Utwórz schematy dla wtyczki.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Ustaw limit banku dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Ustaw biom wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Ustaw kwote bloku w okreslonej lokalizacji.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Ustaw limit bloków dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Ustaw rzedy skrzyni dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Ustaw limit graczy w trybie wspólpracy na wyspie innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Ustaw mnoznik wzrostu plonów dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Ustaw ilosc rozwiazanych wysp dla gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Ustaw level wyspy innego gracza'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Ustaw limit jednostek dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Ustaw lokalizacje podgladu dla wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Przenies wyspe komus innemu.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Ustaw mnoznik dropów mobów dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Ustaw wymagana role uprawnień dla wszystkich wysp.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Ustaw ocene innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Ustaw limit ról dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Przelacz ustawienia dla okreslonej wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Zmień procent materialu generatora kostki brukowej.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Zmień rozmiar wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Ustaw lokalizacje odradzania sie serwera.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Ustaw mnoznik wspólczynnika pojawiania sie dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Ustaw limit czlonków dla wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Ustaw poziom ulepszenia wyspy innego gracza.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Ustaw limit warpow wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Otwórz edytor ustawień wtyczki.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: 'Uzyskaj informacje o wyspie.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teleportuj sie do miejsca odrodzenia.'\nCOMMAND_DESCRIPTION_ADMIN_SPY: 'Przelacz tryb szpiegowania czatu'\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Pokaz statystyki dotyczace wtyczki.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Synchronizuj wartosci aktualizacji dla wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teleportuj sie na inne wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Wyslij graczowi tytul.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Wyslij tytul do wszystkich czlonków wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Zignoruj ​​wyspe z najlepszych wysp.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Odblokuj swiat dla wyspy.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Wyplac pieniadze z banku wyspy innego gracza.'\nCOMMAND_DESCRIPTION_BALANCE: 'Sprawdz ilosc pieniedzy w banku wyspy.'\nCOMMAND_DESCRIPTION_BAN: 'Zablokuj gracza na swojej wyspie.'\nCOMMAND_DESCRIPTION_BANK: 'Otwórz bank wyspy.'\nCOMMAND_DESCRIPTION_BANS: 'Otwórz menu banów.'\nCOMMAND_DESCRIPTION_BIOME: 'Zmień biom wyspy.'\nCOMMAND_DESCRIPTION_BORDER: 'Zmień kolor bariery wysp.'\nCOMMAND_DESCRIPTION_CHEST: 'Otwórz skrzynie wyspy.'\nCOMMAND_DESCRIPTION_CLOSE: 'Zamknij wyspe dla graczy.'\nCOMMAND_DESCRIPTION_COOP: 'Dodaj gracza w trybie wspólpracy na swojej wyspie.'\nCOMMAND_DESCRIPTION_COOPS: 'Otwórz menu wspólpracy.'\nCOMMAND_DESCRIPTION_COUNTS: 'Zobacz liczbe bloków na swojej wyspie.'\nCOMMAND_DESCRIPTION_CREATE: 'Utwórz nowa wyspe.'\nCOMMAND_DESCRIPTION_DEL_WARP: 'Usuń warp wyspy.'\nCOMMAND_DESCRIPTION_DEMOTE: 'Zdegraduj czlonka na swojej wyspie.'\nCOMMAND_DESCRIPTION_DEPOSIT: 'Wplac pieniadze ze swojego konta osobistego do banku wyspy.'\nCOMMAND_DESCRIPTION_DISBAND: 'Rozwiaz swoja wyspe na stale.'\nCOMMAND_DESCRIPTION_EXPEL: 'Wyrzuc goscia ze swojej wyspy.'\nCOMMAND_DESCRIPTION_FLY: 'Przelacz lot na wyspe.'\nCOMMAND_DESCRIPTION_HELP: 'Lista wszystkich poleceń.'\nCOMMAND_DESCRIPTION_INVITE: 'Zapros gracza na swoja wyspe.'\nCOMMAND_DESCRIPTION_KICK: 'Wyrzuc gracza ze swojej wyspy.'\nCOMMAND_DESCRIPTION_LANG: 'Zmień swój osobisty jezyk.'\nCOMMAND_DESCRIPTION_LEAVE: 'Opusc swoja wyspe.'\nCOMMAND_DESCRIPTION_MEMBERS: 'Otwórz menu czlonków.'\nCOMMAND_DESCRIPTION_MISSION: 'Ukończ misje.'\nCOMMAND_DESCRIPTION_MISSIONS: 'Otwórz menu misji.'\nCOMMAND_DESCRIPTION_NAME: 'Zmień nazwe swojej wyspy.'\nCOMMAND_DESCRIPTION_OPEN: 'Otwórz wyspe dla graczy.'\nCOMMAND_DESCRIPTION_PANEL: 'Otwórz panel wyspy.'\nCOMMAND_DESCRIPTION_PARDON: 'Odbanuj gracza na swojej wyspie.'\nCOMMAND_DESCRIPTION_PERMISSIONS: 'Uzyskaj wszystkie uprawnienia dla roli wyspy.'\nCOMMAND_DESCRIPTION_PROMOTE: 'Awansuj czlonka na swojej wyspie.'\nCOMMAND_DESCRIPTION_RANKUP: 'Popraw uaktualnienie na wyzszym poziomie.'\nCOMMAND_DESCRIPTION_RATE: 'Oceń wyspe.'\nCOMMAND_DESCRIPTION_RATINGS: 'Pokaz wszystkie oceny wysp.'\nCOMMAND_DESCRIPTION_SETTINGS: 'Otwórz menu ustawień.'\nCOMMAND_DESCRIPTION_RECALC: 'Ponownie oblicza wartosc wyspy.'\nCOMMAND_DESCRIPTION_SET_DISCORD: 'Ustaw niezgode na wyspie dla wyplat na wyspie.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: 'Ustaw adres e-mail PayPal wyspy dla wyplat na wyspie.'\nCOMMAND_DESCRIPTION_SET_ROLE: 'Zmień role gracza na swojej wyspie.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: 'Zmień lokalizacje teleportacji swojej wyspy.'\nCOMMAND_DESCRIPTION_SET_WARP: 'Utwórz nowa wyspe warp.'\nCOMMAND_DESCRIPTION_SHOW: 'Uzyskaj informacje o wyspie.'\nCOMMAND_DESCRIPTION_TEAM: 'Uzyskaj informacje o czlonkach wyspy'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'Wlacz/wylacz czat wyspy.'\nCOMMAND_DESCRIPTION_TELEPORT: 'Teleportuj na wyspe.'\nCOMMAND_DESCRIPTION_TOGGLE: 'Wlacz/wylacz granice wyspy i stakowanie sie bloków.'\nCOMMAND_DESCRIPTION_TOP: 'Otwórz menu najlepszych wysp.'\nCOMMAND_DESCRIPTION_TRANSFER: 'Zmień lidera wyspy.'\nCOMMAND_DESCRIPTION_UNCOOP: 'Usuń co-op graczowi na twojej wyspie.'\nCOMMAND_DESCRIPTION_UPGRADE: 'Otwórz menu ulepszeń.'\nCOMMAND_DESCRIPTION_VALUE: 'Pokaz wartosc bloku.'\nCOMMAND_DESCRIPTION_VALUES: 'Otwórz menu wartosci bloków.'\nCOMMAND_DESCRIPTION_VISIT: 'Teleportuj w miejsce spawnu odwiedzajacych na wyspie.'\nCOMMAND_DESCRIPTION_VISITORS: 'Otwórz menu odwiedzajacych.'\nCOMMAND_DESCRIPTION_WARP: 'Teleportuj na warp wyspy.'\nCOMMAND_DESCRIPTION_WARPS: 'Otwórz menu warpów.'\nCOMMAND_DESCRIPTION_WITHDRAW: 'Wyplac pieniadze z banku wyspy na twoje konto.'\nCOMMAND_USAGE: '&cUzycie: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lWyspa | &7{0} dodal {1} jako czlonka co-op.'\nCOOP_BANNED_PLAYER: '&c&lBlad | &7Ten gracz jest zablokowany na wyspie i nie moze zostac czlonkiem co-op.'\nCOOP_LIMIT_EXCEED: '&c&lBlad | &7Osiagnales maksymalna liczbe czlonków co-op na wyspie.'\nCREATE_ISLAND: '&e&lWyspa | &7Stworzono wyspe na {0} w {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lBlad | &7Wystapil blad ze stworzeniem wyspy. Skontaktuj sie z administracja.'\nCREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Tryb debug mode &cWylaczony&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Tryb debug mode &aWlaczony&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.'\nDELETE_WARP: '&e&lWyspa | &7Usunales warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oWarp nie istnieje...'\nDEMOTE_LEADER: '&c&lBlad | &7Nie mozesz zmienic lidera wyspy.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz zmniejszyc range tylko osobom nizej od ciebie.'\nDEMOTED_MEMBER: '&e&lWyspa | &7Zmniejszyles range {0} do {1} na wyspie.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} wplacil ${1} do banku wyspy!'\nDEPOSIT_ERROR: '&c&lBlad | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz niszczyc poza zasiegiem ochrony.'\nDISBAND_ANNOUNCEMENT: '&e&lWyspa | &7Twoja wyspa zostala rozwiazana przez {0}.'\nDISBAND_GIVE: '&e&lWyspa | &7Otrzymales {0} rozwiazania.'\nDISBAND_GIVE_ALL: '&e&lWyspa | &7Dales {0} rozwiazanych wszystkim graczom.'\nDISBAND_GIVE_OTHER: '&e&lWyspa | &7Dales {0} rozwiazania dla {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oTwoja wyspa zostala rozwiazana, a na Twoje konto zwrócono {0}$$ z banku wyspy'\nDISBAND_SET: '&e&lWyspa | &7Liczba rozlaczeń zostala ustawiona na {0}.'\nDISBAND_SET_ALL: '&e&lWyspa | &7Ustawiles licznik likwidacji wszystkich graczy na {0}.'\nDISBAND_SET_OTHER: '&e&lWyspa | &7Ustawiles liczbe rozlaczeń uzytkownika {0} na {1}.'\nDISBANDED_ISLAND: '&e&lWyspa | &7 Zlikwidowales swoja wyspe.'\nDISBANDED_ISLAND_OTHER: '&e&lWyspa | &7Usunales wyspe uzytkownika {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lWyspa | &7Usunales wyspe {0}.'\nENTER_PVP_ISLAND: '&7&oZostales przeteleportowany na wyspe z wlaczonym PVP. Jestes odporny na PvP przez nastepne 10 sekund...'\nEXPELLED_PLAYER: '&e&lWyspa | &7{0} zostal wydalony z wyspy.'\nFORMAT_QUAD: 'P'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: 'sekundy'\nFORMAT_SECOND_NAME: 'druga'\nFORMAT_MINUTES_NAME: 'minuty'\nFORMAT_MINUTE_NAME: 'minuta'\nFORMAT_HOURS_NAME: 'godziny'\nFORMAT_HOUR_NAME: 'godzina'\nFORMAT_DAYS_NAME: 'dni'\nFORMAT_DAY_NAME: 'dzień'\nGENERATOR_CLEARED: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatora dla wyspy {0}.'\nGENERATOR_CLEARED_NAME: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatora dla wyspy {0}.'\nGENERATOR_CLEARED_ALL: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatorów dla wszystkich wysp.'\nGENERATOR_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} na wyspe {1}.'\nGENERATOR_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} na wyspe {1}.'\nGENERATOR_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} dla wszystkich wysp.'\nGLOBAL_COMMAND_EXECUTED: '&e&lWyspa | &7Pomyslnie wykonano polecenie na czlonkach wyspy {0}!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lWyspa | &7Pomyslnie wykonano polecenie na elementach wyspy {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lWyspa | &7Pomyslnie wyslano wiadomosc do czlonków wyspy {0}!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lWyspa | &7Pomyslnie wyslano do czlonków wyspy {0} wiadomosc!'\nGLOBAL_TITLE_SENT: '&e&lWyspa | &7Pomyslnie wyslano tytul do czlonków wyspy {0}!'\nGLOBAL_TITLE_SENT_NAME: '&e&lWyspa | &7Pomyslnie wyslano do czlonków wyspy {0} tytul!'\nGOT_BANNED: '&e&lWyspa | &7Zostales ZABRONIONY z wyspy uzytkownika {0}.'\nGOT_DEMOTED: '&e&lWyspa | &7Zostales zdegradowany do {0} na swojej wyspie.'\nGOT_EXPELLED: '&e&lWyspa | &7&oZostales wydalony z wyspy przez {0}.'\nGOT_INVITE: '&e&lWyspa | &7{0} zaprosil cie na swoja wyspe.'\nGOT_INVITE_TOOLTIP: '&7Kliknij wiadomosc, aby zaakceptowac zaproszenie.'\nGOT_KICKED: '&e&lWyspa | &7Zostales wyrzucony z wyspy przez {0}.'\nGOT_PROMOTED: '&e&lWyspa | &7Zostales awansowany na {0} na swojej wyspie.'\nGOT_REVOKED: '&e&lWyspa | &7{0} odwolal Twoje zaproszenie na swoja wyspe.'\nGOT_UNBANNED: '&e&lWyspa | &7Zostales ODBANOWANY z wyspy uzytkownika {0}.'\nHIT_ISLAND_MEMBER: '&c&lBlad | &7Nie mozesz uderzyc czlonków swojej wyspy.'\nHIT_PLAYER_IN_ISLAND: '&c&lBlad | &7Nie mozesz uderzac graczy na wyspach.'\nIGNORED_ISLAND: '&e&lWyspa | Wyspa &7{0} jest teraz ignorowana z najlepszych wysp.'\nIGNORED_ISLAND_NAME: '&e&lWyspa | &7Wyspa {0} jest teraz ignorowana z najlepszych wysp.'\nINTERACT_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz wchodzic w interakcje poza zasiegiem ochrony.'\nINVALID_AMOUNT: '&c&lBlad | &7Nieprawidlowa kwota {0}.'\nINVALID_BIOME: '&c&lBlad | &7Nieprawidlowy biom {0}.'\nINVALID_BLOCK: '&c&lBlad | &7Nieprawidlowa lokalizacja bloku {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lBlad | &7Nieprawidlowa komenda {0}.'\nINVALID_EFFECT: '&c&lBlad | &7Nieprawidlowy efekt {0}.'\nINVALID_ENTITY: '&c&lBlad | &7Nieprawidlowa jednostka {0}.'\nINVALID_ENVIRONMENT: '&c&lBlad | &7Nieprawidlowy wymiar {0}.'\nINVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.'\nINVALID_ISLAND: '&c&lBlad | &7Nie masz wyspy.'\nINVALID_ISLAND_LOCATION: '&c&lBlad | &7W Twojej lokalizacji nie ma wyspy.'\nINVALID_ISLAND_OTHER: '&c&lBlad | &7{0} nie ma wyspy.'\nINVALID_ISLAND_OTHER_NAME: '&c&lBlad | &7Nie ma wyspy o nazwie {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lBlad | &7Nie mozna znalezc uprawnienia wyspy {0}.\n  &c&lBlad | &7Uprawnienia na wyspie: {1}\nINVALID_LEVEL: '&c&lBlad | &7Nieprawidlowy poziom {0}.'\nINVALID_LIMIT: '&c&lBlad | &7Nieprawidlowy limit {0}.'\nINVALID_MATERIAL: '&c&lBlad | &7Nieprawidlowy material {0}.'\nINVALID_MATERIAL_DATA: '&c&lBlad | &7Nieprawidlowe dane materialu {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lBlad | &7Nieprawidlowa misja {0}.'\nINVALID_MISSION_CATEGORY: '&c&lBlad | &7Nieprawidlowa kategoria misji {0}.'\nINVALID_MODULE: '&c&lBlad | &7Nieprawidlowy modul {0}.'\nINVALID_MULTIPLIER: '&c&lBlad | &7Nieprawidlowy mnoznik {0}.'\nINVALID_PAGE: '&c&lBlad | &7Nieprawidlowa strona {0}.'\nINVALID_PERCENTAGE: '&c&lBlad | &7Procent musi zawierac sie w przedziale od 0 do 100.'\nINVALID_PLAYER: '&c&lBlad | &7Nie mozna znalezc gracza o nazwie {0}'\nINVALID_RATE: |\n  &c&lBlad | &7Nie udalo sie znalezc oceny o nazwie {0}.\n  &c&lBlad | &7Oceny wysp: {1}\nINVALID_ROWS: '&c&lBlad | &7Nieprawidlowa liczba wierszy: {0}'\nINVALID_ROLE: |\n  &c&lBlad | &7Nie mozna znalezc roli wyspy {0}.\n  &c&lBlad | &7Role na wyspie: {1}\nINVALID_SCHEMATIC: '&c&lBlad | &7Nie mozna znalezc schematu o nazwie {0}.'\nINVALID_SETTINGS: |\n  &c&lBlad | &7Nie mozna znalezc ustawień wyspy {0}.\n  &c&lBlad | &7Ustawienia wyspy: {1}\nINVALID_SIZE: '&c&lBlad | &7Nieprawidlowy rozmiar {0}.'\nINVALID_SLOT: '&c&lBlad | &7Nieprawidlowy przedzial {0}.'\nINVALID_TITLE: '&c&lBlad | &7Wprowadzono nieprawidlowy tytul.'\nINVALID_TOGGLE_MODE: '&c&lBlad | &7Nie mozna przelaczyc {0}.'\nINVALID_UPGRADE: |\n  &c&lBlad | &7Nie mozna znalezc uaktualnienia o nazwie {0}.\n  &c&lBlad | &7Aktualizacje: {1}\nINVALID_VISIT_LOCATION: '&c&lBlad | &7Ta wyspa nie ma lokalizacji odwiedzajacych.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oMasz tryb obejscia, teleportujesz cie na wyspe...'\nINVALID_WARP: '&c&lBlad | &7Nieprawidlowe wypaczenie {0}.'\nINVALID_WORLD: '&c&lBlad | &7Nieprawidlowy swiat {0}.'\nINVITE_ANNOUNCEMENT: '&e&lWyspa | &7{0} zaprosil {1} na wyspe.'\nINVITE_BANNED_PLAYER: '&c&lBlad | &7Ten gracz ma zakaz wstepu na wyspe i nie moze zostac zaproszony.'\nINVITE_TO_FULL_ISLAND: '&c&lBlad | &7Nie mozesz zaprosic wiecej czlonków na swoja wyspe.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lBlad | &7Wyspa o tej nazwie juz istnieje.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBank | &7Bank na wyspie jest pusty.'\nISLAND_BANK_SHOW: '&e&lBank | &7Twoja wyspa ma {0}$.'\nISLAND_BANK_SHOW_OTHER: '&e&lBank | Wyspa &7{0} ma {1}$.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7Wyspa {0} ma {1}$.'\nISLAND_BEING_CALCULATED: '&c&lBlad | &7Nie mozesz wchodzic w interakcje z blokami podczas przeliczania wyspy!'\nISLAND_CLOSED: '&e&lWyspa | &7Pomyslnie zamknelismy wyspe dla publicznosci.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lBlad | &7Masz juz trwajace zadanie tworzenia wyspy.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lWyspa | &7Przetwarzanie zadania...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lFly | &7Mucha na wyspe zostala automatycznie &cwylaczona&7.'\nISLAND_FLY_ENABLED: '&e&lFly | &7Lot na wyspe zostal automatycznie &wlaczony&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lWyspa | &7&oByles na wyspie, która zostala rozwiazana, wiec zostales przeteleportowany z powrotem na miejsce odrodzenia...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lWyspa | &7&oByles na wyspie, na której wlaczono PvP, wiec zostales przeteleportowany z powrotem na miejsce odrodzenia...'\nISLAND_HELP_FOOTER: '&e&lSkyblock &7Opracowany przez Ome_R'\nISLAND_HELP_HEADER: '&e&lSkyblock &7Lista poleceń [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Uzyj /is help {0} na nastepnej stronie.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lWyspa | &7Limit banku: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lWyspa | &7 Limity bloków:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lWyspa | &7Limit wspólpracy: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lWyspa | &7Mnoznik upraw: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lWyspa | &7Mnoznik zrzutów: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lWyspa | &7Efekty wyspy:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lWyspa | &7 {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lWyspa | &7 Limity jednostek:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lWyspa | &7Ceny generatora ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lWyspa | &7 {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lWyspa | &7 Limity ról:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lWyspa | &7Rozmiar obramowania: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lWyspa | &7Mnoznik spawnerów: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lWyspa | &7Limit zespolu: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lWyspa | &7Aktualizacje:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lWyspa | &7 {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lWyspa | &7Limit wypaczeń: {0}'\nISLAND_INFO_BANK: '&e&lWyspa | &7Bank: {0}'\nISLAND_INFO_BONUS: '&e&lWyspa | &7Warta premia: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lWyspa | &7 Premia za poziom: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lWyspa | &7Czas utworzenia: {0}'\nISLAND_INFO_DISCORD: '&e&lWyspa | &7Niezgodnosc: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lWyspa | &7Ostatnia aktualizacja: {0} temu'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lWyspa | &7Ostatnia aktualizacja: &aObecnie aktywny'\nISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}'\nISLAND_INFO_LOCATION: '&e&lWyspa | &7Strona glówna: {0}'\nISLAND_INFO_NAME: '&e&lWyspa | &7Nazwa: {0}'\nISLAND_INFO_OWNER: '&e&lWyspa | &7Lider: {0}'\nISLAND_INFO_PAYPAL: '&e&lWyspa | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lWyspa | &7 - {0}'\nISLAND_INFO_RATE: '&e&lWyspa | &7Ocena: {0} &7({1}/5) - {2} lacznych ocen.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lWyspa | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lWyspa | &7Odwiedzajacy: {0} ({1} unikalnych odwiedzajacych)'\nISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}'\nISLAND_NAME_NONE: Brak\nISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.'\nISLAND_OWNER_NONE: Brak\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tej komendy w trybie podgladu.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPodglad | &7Odszedles za daleko, nie jestes juz w trybie podgladu.'\nISLAND_PREVIEW_CANCEL: '&e&lPodglad | &7Anulowales tryb podgladu.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'POTWIERDZ'\nISLAND_PREVIEW_CANCEL_TEXT: 'ANULUJ'\nISLAND_PREVIEW_SET: '&e&lPodglad | &7Pomyslnie zaktualizowano lokalizacje podgladu dla schematu {0} na {1}.'\nISLAND_PREVIEW_START: |\n  &e&lPodglad | &7Wlaczyles tryb podgladu dla schematu {0}.\n  &e&lPodglad | &7Wpisz &a&lPOTWIERDZ &7by stworzyc nowa wyspe, lub &c&lANULUJ &7by wylaczyc tryb podladu.\n  &e&lPodglad | &7Nie mozesz opuscic terenu wyspy, w przeciwnym razie tryb podgladowy zostanie anulowany.\nISLAND_PROTECTED: '&c&lBlad | &7Ta wyspa jest chroniona.'\nISLAND_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lWyspa | &7Czlonkowie {0}''s Wyspy &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Online)'\nISLAND_TEAM_STATUS_ROLES: '&e&lWyspa | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TOP_STATUS_ONLINE: '&a(Online)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Prywatne]'\nISLAND_WAS_CLOSED: '&e&lWyspa | &7&oWyspa, na której byles, zostala zamknieta i zostales przeteleportowany z powrotem na miejsce odrodzenia...'\nISLAND_WORTH_ERROR: '&c&lBlad | &7Podczas obliczania wyspy wystapil nieoczekiwany blad. Skontaktuj sie z administratorami, jesli problem bedzie sie powtarzal.'\nISLAND_WORTH_RESULT: '&e&lWyspa | &7Wartosc Twojej wyspy to {0} [Poziom {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lBlad | &7Uplynal limit czasu zadania obliczeniowego. Spróbuj ponownie pózniej...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do Twojej wyspy.'\nJOIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do Twojej wyspy.'\nJOIN_FULL_ISLAND: '&c&lBlad | &7Ta wyspa osiagnela maksymalna liczbe dozwolonych czlonków.'\nJOIN_WHILE_IN_ISLAND: '&c&lBlad | &7Jestes juz na wyspie.'\nJOINED_ISLAND: '&e&lWyspa | &7Dolaczyles do wyspy uzytkownika {0}.'\nJOINED_ISLAND_NAME: '&e&lWyspa | &7Dolaczyles do wyspy {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lWyspa | &7Jestes teraz czlonkiem trybu wspólpracy na wyspie {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lWyspa | &7Jestes teraz czlonkiem trybu wspólpracy na wyspie {0}.'\nKICK_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal wyrzucony z wyspy przez {1}.'\nKICK_ISLAND_LEADER: '&c&lBlad | &7Nie mozesz wyrzucic przywódcy wyspy, zamiast tego uzyj /is admin disband.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz wyrzucac tylko graczy z nizsza rola wyspy niz twoja.'\nLACK_CHANGE_PERMISSION: '&c&lBlad | &7Musisz miec to uprawnienie, aby zmienic je na inne role.'\nLAST_ROLE_DEMOTE: '&c&lBlad | &7Nie mozesz juz zdegradowac tego gracza.'\nLAST_ROLE_PROMOTE: '&c&lBlad | &7Nie mozesz juz promowac tego gracza.'\nLEAVE_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil wyspe.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lBlad | &7Nie mozesz opuscic swojej wyspy, kiedy jest jej wlascicielem.\n  &c&lBlad | &7Mozesz przeniesc prawo wlasnosci za pomoca /is transfer.\nLEFT_ISLAND: '&e&lWyspa | &7Opusciles swoja wyspe.'\nLEFT_ISLAND_COOP: '&e&lWyspa | &7Nie jestes juz czlonkiem trybu wspólpracy na wyspie {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lWyspa | &7Nie jestes juz czlonkiem spóldzielni na wyspie {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lBlad | &7Musisz dostarczyc solidny material.'\nMAXIMUM_LEVEL: '&c&lBlad | &7Maksymalny poziom tego uaktualnienia to {0}.'\nMESSAGE_SENT: '&e&lWyspa | &7Pomyslnie wyslano {0} wiadomosc!'\nMISSION_CANNOT_COMPLETE: '&c&lBlad | &7Nie mozesz jeszcze ukończyc tej misji.'\nMISSION_NO_AUTO_REWARD: '&e&lMisja | &7Masz wszystkie wymagane materialy do ​​ukończenia {0} - uzyj /is misji, aby ukończyc!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lBlad | &7Musisz ukończyc {0} przed ukończeniem tej misji.'\nMISSION_STATUS_COMPLETE: '&e&lMisja | &7Zmieniono status misji {0} na ukończona dla {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMisja | &7Zmieniono status wszystkich misji na ukończone dla {0}.'\nMISSION_STATUS_RESET: '&e&lMisja | &7Zresetuj status misji {0} dla {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMisja | &7Zresetuj status wszystkich misji dla {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModul | &7Ten modul jest juz zaladowany.'\nMODULE_INFO: |\n  &e&lModul | &7{0} przez {1}\n  &e&lModul | &7&m--------------------\n  &e&lModul | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModul | &7Pomyslnie zaladowano modul {0}.'\nMODULE_LOADED_FAILURE: '&e&lModul | &7Nie udalo sie zaladowac modulu {0}. Sprawdz konsole, aby uzyskac wiecej informacji.'\nMODULE_UNLOADED_SUCCESS: '&e&lModul | &7Pomyslnie wyladowano modul.'\nMODULES_LIST: '&fModuly ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f,'\nNAME_ANNOUNCEMENT: '&e&lWyspa | &7{0} zmienil nazwe swojej wyspy na {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lWyspa | &7{0} zmienil nazwe wyspy {1} na {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lWyspa | &7{0} zmienil nazwe {1}&7 na {2}&7.'\nNAME_BLACKLISTED: '&c&lBlad | &7Nie mozesz uzywac tej nazwy.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lBlad | &7Nie mozesz uzywac nazw graczy jako nazw wysp.'\nNAME_TOO_LONG: '&c&lBlad | &7Nazwy wysp nie moga miec wiecej niz {0} znaków.'\nNAME_TOO_SHORT: '&c&lBlad | &7Nazwy wysp nie moga miec mniej niz {0} znaki.'\nNO_BAN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby blokowac graczy.'\nNO_CLOSE_BYPASS: '&c&lBlad | &7Ta wyspa nie jest otwarta dla publicznosci.'\nNO_CLOSE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zamknac wyspe dla publicznosci.'\nNO_COMMAND_PERMISSION: '&c&lBlad | &7Nie masz uprawnien do uzycia tego polecenia. ({0})'\nNO_COOP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby dodawac graczy jako czlonków trybu wspólpracy.'\nNO_DELETE_WARP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby usunac wypaczenia.'\nNO_DEMOTE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zdegradowac graczy.'\nNO_DEPOSIT_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wplacac pieniadze do banku wyspy.'\nNO_DISBAND_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby rozwiazac swoja wyspe.'\nNO_EXPEL_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wydalic graczy ze swojej wyspy.'\nNO_INVITE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zapraszac graczy.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby uzyskac dostep do skrzyni wyspy.'\nNO_ISLAND_INVITE: '&c&lBlad | &7Nie udalo sie znalezc zadnych zaproszeń z tej wyspy.'\nNO_ISLANDS_TO_PURGE: '&c&lBlad | &7Nie bylo wysp do oczyszczenia.'\nNO_KICK_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wyrzucac graczy.'\nNO_MORE_DISBANDS: '&c&lBlad | &7Nie mozesz juz rozwiazac kolejnych wysp.'\nNO_MORE_WARPS: '&c&lBlad | &7Twoja wyspa nie moze miec wiecej wypaczeń.'\nNO_NAME_PERMISSION: '&c&lBlad | &7Nie mozesz zmienic nazwy swojej wyspy.'\nNO_OPEN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby otworzyc wyspe dla publicznosci.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby uzyskac informacje o uprawnieniach.'\nNO_PROMOTE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby promowac graczy.'\nNO_RANKUP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby awansowac na wyzsza range.'\nNO_RATINGS_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby sprawdzac oceny.'\nNO_SET_BIOME_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic biom wyspy.'\nNO_SET_DISCORD_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic niezgodnosc wysp.'\nNO_SET_HOME_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic lokalizacje teleportu na wyspie.'\nNO_SET_PAYPAL_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic adres e-mail na wyspie PayPal.'\nNO_SET_ROLE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic role dla graczy.'\nNO_SET_SETTINGS_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic ustawienia wyspy.'\nNO_SET_WARP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic zawijanie wysp.'\nNO_TRANSFER_PERMISSION: '&c&lBlad | &7Musisz byc przywódca wyspy, aby przekazac przywództwo.'\nNO_UNCOOP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby usunac graczy z czlonkostwa w trybie wspólpracy.'\nNO_UPGRADE_PERMISSION: '&c&lBlad | &7Nie masz uprawnień do przejscia na inny poziom.'\nNO_WITHDRAW_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wyplacac pieniadze z banku wyspy.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy, aby wplacic {0} dolarów do banku wyspy.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy, aby korzystac z wypaczeń wyspowych.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oJestes zbyt zmeczony, aby korzystac z menu, nie sadzisz?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Wlaczony panel wyspowy &cWYl&7.\n  &e&lPanel | &7Uruchomienie /is przeniesie Cie na wyspe.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Wlaczony panel wyspy &aWl&7.\n  &e&lPanel | &7Uruchomienie /is otworzy panel.\nPERMISSION_CHANGED: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} wyspy {1}.'\nPERMISSION_CHANGED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} wyspy {1}.'\nPERMISSION_CHANGED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} dla wszystkich wysp.'\nPERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.'\nPERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.'\nPERMISSIONS_RESET: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy gracza {0} do wartosci domyslnych!'\nPERMISSIONS_RESET_ALL: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wszystkich wysp do wartosci domyslnych!'\nPERMISSIONS_RESET_NAME: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy {0} do wartosci domyslnych!'\nPERMISSIONS_RESET_PLAYER: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia dla {0} do wartosci domyslnych!'\nPERMISSIONS_RESET_ROLES: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy do wartosci domyslnych!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lBlad | &7Ten gracz jest juz zbanowany.'\nPLAYER_ALREADY_COOP: '&c&lBlad | &7Ten gracz jest juz w trybie wspólpracy.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lBlad | &7Ten gracz jest juz na wyspie.'\nPLAYER_ALREADY_IN_ROLE: '&c&lBlad | &7{0} to juz {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lBlad | &7Tego uzytkownika nie mozna usunac z wyspy.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do serwera.'\nPLAYER_NOT_BANNED: '&c&lBlad | &7Ten gracz nie jest zbanowany.'\nPLAYER_NOT_COOP: '&c&lBlad | &7Ten gracz nie jest w trybie wspólpracy.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lBlad | &7Ten gracz nie znajduje sie na twojej wyspie.'\nPLAYER_NOT_ONLINE: '&c&lBlad | &7Ten gracz nie jest online!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil serwer.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz promowac tylko graczy z nizsza rola wyspy niz twoja.'\nPROMOTED_MEMBER: '&e&lWyspa | &7Awansowales {0} na {1} na jego wyspie.'\nPURGE_CLEAR: '&e&lWyspa | &7Pomyslnie wyczyscilem wszystkie wyspy w kolejce do oczyszczenia.'\nPURGED_ISLANDS: |-\n  &e&lWyspa | &7{0} wyspy zostana wyczyszczone po ponownym uruchomieniu serwera.\n  &e&lWyspa | &7Mozesz to anulowac w dowolnym momencie za pomoca /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla wyspy {1}.'\nRANKUP_SUCCESS_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom aktualizacji {0} dla wszystkich wysp.'\nRANKUP_SUCCESS_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla {1}.'\nRATE_ALREADY_GIVEN: '&c&lBlad | &7Oceniles juz te wyspe.'\nRATE_ANNOUNCEMENT: '&e&lWyspa | &7{0} ocenilo Twoja wyspe {1} na 5!.'\nRATE_CHANGE_OTHER: '&e&lWyspa | &7Zmieniles ocene z {0} na {1}.'\nRATE_OWN_ISLAND: '&c&lBlad | &7Nie mozesz ocenic wlasnej wyspy.'\nRATE_REMOVE_ALL: '&e&lWyspa | &7Pomyslnie usunieto wszystkie oceny {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lWyspa | &7Pomyslnie usunieto wszystkie oceny wszystkich wysp.'\nRATE_SUCCESS: '&e&lWyspa | &7Ocenales te wyspe na {0} gwiazdek!'\nREACHED_BLOCK_LIMIT: '&e&lAktualizacje | &7Osiagnieto limit wyspy dla {0} blokowania.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lBlad | &7Twoja wyspa jest juz przeliczana.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lBlad | &7Ta wyspa jest juz przeliczana.'\nRECALC_ALL_ISLANDS: '&e&lWyspa | &7Ponowne obliczanie wszystkich wysp...'\nRECALC_ALL_ISLANDS_DONE: '&e&lWyspa | &7Pomyslnie zakończono ponowne obliczanie wszystkich wysp.'\nRECALC_PROCCESS_REQUEST: '&e&lWyspa | &7Przetwarzanie zadania...'\nRELOAD_COMPLETED: '&e&lWyspa | &7Ponowne ladowanie zakończone!'\nRELOAD_PROCCESS_REQUEST: '&e&lWyspa | &7Rozpoczynanie ponownego ladowania konfiguracji...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lWyspa | &7{0} odwolal zaproszenie uzytkownika {1} na wyspe.'\nRESET_WORLD_SUCCEED: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla wyspy {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla wszystkich wysp.'\nRESET_WORLD_SUCCEED_NAME: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla {1}.'\nSAME_NAME_CHANGE: '&c&lBlad | &7Musisz wprowadzic inna nazwe niz obecna nazwa wyspy.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematy | &7Wybrana pozycja #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lBlad | &7Serwer nie dodal schematu {0}. Skontaktuj sie z administratorem, aby rozwiazac problem. Format dla schematu {0} to \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lBlad | &7Nie wybrales dwóch pozycji.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematy | &7Przetwarzanie zadania...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematy | &7Wybrales dwie pozycje. Uruchom /is admin schematic <name>, aby utworzyc nowy schemat.\n  &e&lSchematy | &7Upewnij sie, ze stoisz w miejscu teleportacji podczas wykonywania polecenia.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematy | &7Wybrana pozycja nr 1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematy | &7Schemat zapisany pomyslnie!'\nSELF_ROLE_CHANGE: '&c&lBlad | &7Nie mozesz zmienic swojej roli.'\nSET_UPGRADE_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wyspy {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wszystkich wysp.'\nSET_UPGRADE_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla {1}.'\nSET_WARP: '&e&lWyspa | &7Pomyslnie utworzono nowe wypaczenie w {0}.'\nSET_WARP_OUTSIDE: '&c&lBlad | &7Nie mozesz ustawic warp poza swoja wyspa.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie ustawienia wyspy do domyslnych wartosci!'\nSETTINGS_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.'\nSETTINGS_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.'\nSETTINGS_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} dla wszystkich wysp.'\nSIZE_BIGGER_MAX: '&c&lBlad | &7Nie mozna ustawic rozmiaru wiekszego niz maksymalny rozmiar wyspy.'\nSPAWN_PROTECTED: '&c&lBlad | &7Spawn jest chroniony.'\nSPAWN_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Pomyslnie teleportowano {0} do odrodzenia.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Pomyslnie zaktualizowano lokalizacje odradzania do {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Szpieg] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji wyspy {0}.'\nSYNC_UPGRADES_ALL: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji na wszystkich wyspach.'\nSYNC_UPGRADES_NAME: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lBlad | &7 Nie jestes na swojej wyspie.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz teleportowac sie poza swój zasieg ochrony.'\nTELEPORT_WARMUP: '&7&oZostaniesz przeteleportowany w {0}... Nie ruszaj sie!'\nTELEPORT_WARMUP_CANCEL: '&7&oPrzeniosles sie, wiec teleportacja zostala anulowana.'\nTITLE_SENT: '&e&lWyspa | &7Pomyslnie wyslano {0} tytul!'\nTELEPORTED_FAILED: '&e&lWyspa | &7Wyglada na to, ze ta wyspa nie ma bezpiecznych bloków. Prosze skontaktowac sie z czlonkiem wyspy.'\nTELEPORTED_SUCCESS: '&e&lWyspa | &7Zostales przeteleportowany na swoja wyspe.'\nTELEPORTED_TO_WARP: '&e&lWyspa | &7Pomyslnie teleportowano sie na te wyspe warp.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lWyspa | &7Gracz {0} teleportowal sie na wyspe warp {1}.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Wlaczony tryb obejscia &cWYl&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Wlaczony tryb obejscia &aWl&7.'\nTOGGLED_FLY_OFF: '&e&lFly | &7Wlacz lot wyspowy &cWYl&7.'\nTOGGLED_FLY_ON: '&e&lFly | &7Wlacz lot wyspowy &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematy | &7Przelaczanie trybu schematu &cOFF&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchematy | &7Przelaczanie trybu schematu &aWl&7.\n  &e&lSchematy | &7Wybierz obszar za pomoca zlotego topora.\nTOGGLED_SPY_OFF: '&e&lSpy | &7Wlaczono czat szpiegowski &cWYl&7.'\nTOGGLED_SPY_ON: '&e&lSpy | &7Wlaczony czat szpiegowski &aWl&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Przelaczanie ukladarki bloków &cWYl&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Przelaczanie ukladarki bloków &aON&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Przelaczanie czatu zespolu &cWYl&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Przelaczanie czatu zespolu &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBariera | &7Przelaczanie granicy swiata &cWYl&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBariera | &7Przelaczanie granicy swiata &aW&7.'\nTRANSFER_ADMIN: '&e&lWyspa | &7Przeniosles kierownictwo uzytkownika {0} do {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lBlad | &7{0} jest juz przywódca swojej wyspy.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lBlad | &7Ci gracze nie sa na tych samych wyspach.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lBlad | &7Ten gracz nie jest przywódca zadnej wyspy.'\nTRANSFER_ALREADY_LEADER: '&c&lBlad | &7Jestes juz przywódca tej wyspy.'\nTRANSFER_BROADCAST: '&e&lWyspa | &7Przywództwo wyspy zostalo przeniesione do {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal ODBLOKOWANY na wyspie przez {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lWyspa | &7{0} usunelo {1} z czlonkostwa w trybie wspólpracy.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil gre i nie jest juz czlonkiem trybu wspólpracy.'\nUNIGNORED_ISLAND: '&e&lWyspa | Wyspa &7{0} nie jest teraz ignorowana wsród najlepszych wysp.'\nUNIGNORED_ISLAND_NAME: '&e&lWyspa | &7Wyspa {0} nie jest teraz ignorowana wsród najlepszych wysp.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lWyspa | &7&oWyglada na to, ze to wypaczenie jest niebezpieczne. Prosze spróbowac innego wypaczenia.'\nUPDATED_PERMISSION: '&e&lWyspa | &7Zaktualizowano uprawnienia dla {0}.'\nUPDATED_SETTINGS: '&e&lWyspa | &7Zaktualizowano ustawienia wyspy {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uaktualnic ponownie dopiero za {0}.'\nVAULT_NOT_INSTALLED: '&c&lBlad | &7Na serwerze nie ma zainstalowanego pluginu Vault, wiec transakcje sa wylaczone.'\nVISITOR_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tego polecenia na innych wyspach.'\nWARP_ALREADY_EXIST: '&c&lBlad | &7Istnieje juz warp o tej nazwie.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarpy | &7Wprowadz nowa wiedze (wpisz -cancel\", aby anulowac):\n  &e&lWarpy | &7Mozesz oddzielic wiersze, uzywajac '\\n.'\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarpy | &7Wpisz nazwe (wpisz \"-cancel\", aby anulowac):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarpy | &7Wprowadz nowy typ materialu (wpisz \"-cancel\", aby anulowac):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarpy | &7Pomyslnie zaktualizowano ikone kategorii.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lBlad | &7W nazwach kategorii wypaczenia mozna uzywac tylko liter alfabetu, cyfr i ''_''.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.'\nWARP_CATEGORY_SLOT: '&e&lWarpy | &7Wprowadz nowe miejsce (wpisz \"-cancel\", aby anulowac):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lBlad | &7To miejsce jest juz zajete przez inna kategorie.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono miejsce kategorii na {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarpy | &7Wprowadz nowa nazwe (wpisz \"-cancel\", aby anulowac):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lBlad | &7Ta nazwa jest juz zajeta przez inna kategorie.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono nazwe kategorii na {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarpy | &7Wprowadz nowa wiedze (wpisz \"-cancel\", aby anulowac):\n  &e&lWarpy | &7Mozesz oddzielic wiersze, uzywajac '\\n.'\nWARP_ICON_NEW_NAME: '&e&lWarpy | &7Wpisz nazwe (wpisz \"-cancel\", aby anulowac):'\nWARP_ICON_NEW_TYPE: '&e&lWarpy | &7Wprowadz nowy typ materialu (wpisz \"-cancel\", aby anulowac):'\nWARP_ICON_UPDATED: '&e&lWarpy | &7Pomyslnie zaktualizowano ikone wypaczenia.'\nWARP_ILLEGAL_NAME: '&c&lBlad | &7W nazwach wypaczeń mozna uzywac tylko liter alfabetu, cyfr i ''_''.'\nWARP_LOCATION_UPDATE: '&e&lWarpy | &7Pomyslnie zaktualizowano lokalizacje wypaczenia do Twojej lokalizacji.'\nWARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.'\nWARP_PUBLIC_UPDATE: '&e&lWarpy | &7Udalo sie otworzyc osnowe dla publicznosci.'\nWARP_PRIVATE_UPDATE: '&e&lWarpy | &7Z powodzeniem zamknieto osnowe dla publicznosci.'\nWARP_RENAME: '&e&lWarpy | &7Wprowadz nowa nazwe (wpisz \"-cancel\", aby anulowac):'\nWARP_RENAME_ALREADY_EXIST: '&c&lBlad | &7Ta nazwa jest juz przejeta przez inna osnowe.'\nWARP_RENAME_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono nazwe wypaczenia na {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBank | &7Island Bank ma w sobie tylko {0} dolarów.\n  &e&lBank | &7&oWyplata wszystkich pieniedzy...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} wyplaciles {1}$ z banku wyspy!'\nWITHDRAW_ERROR: '&c&lBlad | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBank | &7Wyplaciles {0}$ z banku wysp {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lBank | &7Wyplaciles {0}$ z banku wyspy {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7Swiat {0} nie jest wlaczony na serwerze.'\nWORLD_NOT_UNLOCKED: '&e&lSwiaty | &7swiat {0} nie jest jeszcze odblokowany!'\n"
  },
  {
    "path": "src/main/resources/lang/pt-BR.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha de {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lBanco | &7Você depositou R${0} no banco da ilha de {1}.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBanco | &7Você depositou R${0} no banco da ilha {1}.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desenvolvido por Ome_R'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de Comandos Admin [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is admin {0} para a próxima página.'\nALREADY_IN_ISLAND: '&c&lErro | &7Você já está em uma ilha.'\nALREADY_IN_ISLAND_OTHER: '&c&lErro | &7Este jogador já é membro da sua ilha.'\nBAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi BANIDO da ilha por {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode banir jogadores com um cargo inferior ao seu na ilha.'\nBANK_DEPOSIT_CUSTOM: '&e&lBanco | &7Digite o valor que deseja depositar:'\nBANK_DEPOSIT_COMPLETED: 'Depósito Concluído'\nBANK_LIMIT_EXCEED: '&c&lErro | &7Você excedeu o limite do banco.'\nBANK_WITHDRAW_CUSTOM: '&e&lBanco | &7Digite o valor que deseja sacar:'\nBANK_WITHDRAW_COMPLETED: 'Saque Concluído'\nBANNED_FROM_ISLAND: '&c&lErro | &7Você está banido desta ilha.'\nBLOCK_COUNT_CHECK: '&e&lIlha | &7Esta ilha possui x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lIlha | &7Esta ilha possui os seguintes blocos:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lIlha | &7Esta ilha não possui blocos registrados.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lNível | &7O nível do bloco {0} é {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lNível | &7O bloco {0} não possui valor.'\nBLOCK_VALUE: '&e&lValor | &7O bloco {0} vale {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lValor | &7O bloco {0} não possui valor.'\nBONUS_SYNC_ALL: '&e&lIlha | &7Bônus sincronizado com sucesso para todas as ilhas.'\nBONUS_SYNC_NAME: '&e&lIlha | &7Bônus sincronizado com sucesso para {0}.'\nBONUS_SYNC: '&e&lIlha | &7Bônus sincronizado com sucesso para a ilha de {0}.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Azul'\nBORDER_PLAYER_COLOR_NAME_RED: 'Vermelho'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Verde'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBorda | &7Cor da borda pessoal alterada com sucesso para {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode construir fora do seu limite de proteção.'\nCANNOT_SET_ROLE: '&c&lErro | &7Você não pode definir o cargo do jogador como {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErro | &7Você só pode alterar permissões para cargos inferiores ao seu na ilha.'\nCHANGED_BANK_LIMIT: '&e&lMelhorias | &7Limite do banco da ilha de {0} atualizado com sucesso.'\nCHANGED_BANK_LIMIT_ALL: '&e&lMelhorias | &7Limite do banco de todas as ilhas atualizado com sucesso.'\nCHANGED_BANK_LIMIT_NAME: '&e&lMelhorias | &7Limite do banco de {0} atualizado com sucesso.'\nCHANGED_BIOME: '&e&lIlha | &7Bioma alterado com sucesso para {0}. Você pode precisar se reconectar ao servidor para ver as mudanças.'\nCHANGED_BIOME_ALL: '&e&lIlha | &7Bioma alterado com sucesso para {0} em todas as ilhas.'\nCHANGED_BIOME_NAME: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha {1}.'\nCHANGED_BIOME_OTHER: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha de {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocos | &7Quantidade de blocos em {0} alterada para {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lMelhorias | &7Limite de blocos {0} atualizado na ilha de {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lMelhorias | &7Limite de blocos {0} atualizado em todas as ilhas.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lMelhorias | &7Limite de blocos {0} atualizado em {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} na ilha de {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} em todas as ilhas.'\nCHANGED_CHEST_SIZE_NAME: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} de {2}.'\nCHANGED_COOP_LIMIT: '&e&lMelhorias | &7O limite de jogadores na cooperação da ilha de {0} foi atualizado com sucesso.'\nCHANGED_COOP_LIMIT_ALL: '&e&lMelhorias | &7O limite de jogadores na cooperação de todas as ilhas foi atualizado com sucesso.'\nCHANGED_COOP_LIMIT_NAME: '&e&lMelhorias | &7O limite de jogadores na cooperação de {0} foi atualizado com sucesso.'\nCHANGED_CROP_GROWTH: '&e&lMelhorias | &7O multiplicador de crescimento das plantações da ilha de {0} foi atualizado com sucesso.'\nCHANGED_CROP_GROWTH_ALL: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de todas as ilhas foi atualizado com sucesso.'\nCHANGED_CROP_GROWTH_NAME: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de {0} foi atualizado com sucesso.'\nCHANGED_DISCORD: '&e&lIlha | &7O Discord da ilha foi atualizado para {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lMelhorias | &7O limite de entidades {0} para a ilha de {1} foi atualizado com sucesso.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lMelhorias | &7O limite de entidades {0} para todas as ilhas foi atualizado com sucesso.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lMelhorias | &7O limite de entidades {0} para {1} foi atualizado com sucesso.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para a ilha de {1} foi atualizado com sucesso.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para todas as ilhas foi atualizado com sucesso.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lMelhorias | &7O nível do efeito da ilha {0} para {1} foi atualizado com sucesso.'\nCHANGED_ISLAND_SIZE: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lMelhorias | &7O tamanho de todas as ilhas foi atualizado com sucesso.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oOs jogadores podem construir fora de sua ilha, então o tamanho da ilha não tem efeito. Você pode desativar essa função na configuração para que o tamanho da ilha volte a ter efeito.'\nCHANGED_LANGUAGE: '&e&lIdioma | &7Seu idioma foi alterado com sucesso para Inglês.'\nCHANGED_MOB_DROPS: '&e&lMelhorias | &7O multiplicador de drops de mobs da ilha de {0} foi atualizado com sucesso.'\nCHANGED_MOB_DROPS_ALL: '&e&lMelhorias | &7O multiplicador de drops de mobs de todas as ilhas foi atualizado com sucesso.'\nCHANGED_MOB_DROPS_NAME: '&e&lMelhorias | &7O multiplicador de drops de mobs de {0} foi atualizado com sucesso.'\nCHANGED_NAME: '&e&lIlha | &7Você alterou o nome da sua ilha para {0}&7.'\nCHANGED_NAME_OTHER: '&e&lIlha | &7Você alterou o nome da ilha de {0} para {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lIlha | &7Você alterou o nome de {0}&7 para {1}&7.'\nCHANGED_PAYPAL: '&e&lIlha | &7O PayPal da ilha foi atualizado para {0}.'\nCHANGED_ROLE_LIMIT: '&e&lMelhorias | &7O limite do cargo {0} para a ilha de {1} foi atualizado com sucesso.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lMelhorias | &7O limite do cargo {0} para todas as ilhas foi atualizado com sucesso.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lMelhorias | &7O limite do cargo {0} para {1} foi atualizado com sucesso.'\nCHANGED_SPAWNER_RATES: '&e&lMelhorias | &7O multiplicador das taxas de geradores da ilha de {0} foi atualizado com sucesso.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lMelhorias | &7O multiplicador das taxas de geradores de todas as ilhas foi atualizado com sucesso.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lMelhorias | &7O multiplicador das taxas de geradores de {0} foi atualizado com sucesso.'\nCHANGED_TEAM_LIMIT: '&e&lMelhorias | &7O limite de membros da equipe da ilha de {0} foi atualizado com sucesso.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lMelhorias | &7O limite de membros da equipe de todas as ilhas foi atualizado com sucesso.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lMelhorias | &7O limite de membros da equipe de {0} foi atualizado com sucesso.'\nCHANGED_TELEPORT_LOCATION: '&e&lIlha | &7A localização de teletransporte foi atualizada com sucesso.'\nCHANGED_WARPS_LIMIT: '&e&lMelhorias | &7O limite de warps da ilha de {0} foi atualizado com sucesso.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lMelhorias | &7O limite de warps de todas as ilhas foi atualizado com sucesso.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lMelhorias | &7O limite de warps de {0} foi atualizado com sucesso.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: 'quantidade'\nCOMMAND_ARGUMENT_BIOME: 'bioma'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'cor-da-borda'\nCOMMAND_ARGUMENT_COMMAND: 'comando...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: 'discord...'\nCOMMAND_ARGUMENT_EFFECT: 'efeito-de-poção'\nCOMMAND_ARGUMENT_EMAIL: 'email'\nCOMMAND_ARGUMENT_ENTITY: 'entidade'\nCOMMAND_ARGUMENT_ISLAND_NAME: 'nome-da-ilha'\nCOMMAND_ARGUMENT_ISLAND_ROLE: 'cargo-da-ilha'\nCOMMAND_ARGUMENT_LEADER: 'líder'\nCOMMAND_ARGUMENT_LEVEL: 'nível'\nCOMMAND_ARGUMENT_LIMIT: 'limite'\nCOMMAND_ARGUMENT_MATERIAL: 'material'\nCOMMAND_ARGUMENT_MENU: 'nome-do-menu'\nCOMMAND_ARGUMENT_MESSAGE: 'mensagem...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: 'nome-da-missão'\nCOMMAND_ARGUMENT_MODULE_NAME: 'nome-do-módulo'\nCOMMAND_ARGUMENT_MULTIPLIER: 'multiplicador'\nCOMMAND_ARGUMENT_NAME: 'nome'\nCOMMAND_ARGUMENT_NEW_LEADER: 'novo-líder'\nCOMMAND_ARGUMENT_PAGE: 'página'\nCOMMAND_ARGUMENT_PATH: 'caminho'\nCOMMAND_ARGUMENT_PERMISSION: 'permissão'\nCOMMAND_ARGUMENT_PLAYER_NAME: 'nome-do-jogador'\nCOMMAND_ARGUMENT_PRIVATE: 'privado'\nCOMMAND_ARGUMENT_RATING: 'avaliação'\nCOMMAND_ARGUMENT_ROWS: 'linhas'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: 'nome-da-esquema'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: 'configurações'\nCOMMAND_ARGUMENT_SIZE: 'tamanho'\nCOMMAND_ARGUMENT_TIME: 'tempo'\nCOMMAND_ARGUMENT_TITLE_DURATION: 'duração'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'desaparecer'\nCOMMAND_ARGUMENT_UPGRADE_NAME: 'nome-do-upgrade'\nCOMMAND_ARGUMENT_VALUE: 'valor'\nCOMMAND_ARGUMENT_WARP_NAME: 'nome-do-warp'\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'categoria-do-warp'\nCOMMAND_ARGUMENT_WORLD: 'mundo'\nCOMMAND_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode usar o comando novamente em {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: 'Aceite um convite de um jogador.'\nCOMMAND_DESCRIPTION_ADMIN: 'Use os comandos de administrador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Adicione um usuário a uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumente o limite de blocos para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Adicione um bônus a um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumente o limite de jogadores na cooperação da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Aumente o multiplicador de crescimento das plantações da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Adicione um efeito à ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Aumente o limite de entidades na ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Adicione porcentagem de um material ao gerador de pedra.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Aumente o multiplicador de drops de mobs da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expanda o tamanho da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Aumente o multiplicador das taxas dos geradores da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Aumente o limite de membros da equipe da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Aumente o limite de warps de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: 'Conceda um bônus a um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: 'Alternar o modo bypass.'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Abrir o baú da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Limpar as taxas do gerador para uma ilha específica.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: 'Fechar uma ilha para o público.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Executar um comando para todos os membros de ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Verificar a contagem de blocos em uma ilha específica.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interagir com dados persistentes de jogadores ou ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Alternar saídas de depuração.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Excluir um warp de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Rebaixar um membro na ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Depositar dinheiro no banco da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: 'Desfazer permanentemente a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Conceder dissoluções de ilhas a um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignorar uma ilha das melhores ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: 'Entrar em uma ilha sem convite.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Expulsar um jogador de sua ilha.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Gerenciar módulos do plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: 'Alterar o status de uma missão para um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: 'Enviar uma mensagem a um jogador sem prefixos.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Enviar a todos os membros de uma ilha uma mensagem sem prefixos.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: 'Alterar o nome de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: 'Abrir uma ilha para o público.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Abrir um menu personalizado para um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promover um membro na ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: 'Remover ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir o nível de um upgrade para uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: 'Recalcular o valor de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas do plugin.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Definir o bioma de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Definir a quantidade de blocos em um local específico.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Definir o limite de blocos para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Definir as linhas do baú para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Definir o limite de cooperação para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Definir o multiplicador de crescimento de plantações para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Definir a quantidade de dissoluções de ilhas de um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Definir o nível do efeito da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Definir o limite de entidades para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transferir uma ilha para outra pessoa.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Definir o multiplicador de drops de mobs para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Definir uma permissão de função obrigatória para todas as ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Definir a avaliação de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Definir o limite de cargos para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Alternar configurações para uma ilha específica.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Alterar a porcentagem de um material no gerador de pedra.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Alterar o tamanho da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Definir o local de spawn do servidor.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Definir o multiplicador das taxas de spawner para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Definir o limite de membros da equipe para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Definir o nível de um upgrade para a ilha de outro jogador.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Definir o limite de warps de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Abrir o editor de configurações do plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: 'Obter informações sobre uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teletransportar para o local de spawn.'\nCOMMAND_DESCRIPTION_ADMIN_SPY: 'Alternar o modo de espionagem de chat.'\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Exibir estatísticas sobre o plugin.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sincronizar o bônus de uma ilha com os mundos gerados.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sincronizar os valores de upgrades de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teletransportar para outras ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Enviar um título para um jogador.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Enviar um título para todos os membros de uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Remover uma ilha da lista de ignorados das melhores ilhas.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Desbloquear um mundo para uma ilha.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinheiro do banco da ilha de outro jogador.'\nCOMMAND_DESCRIPTION_BALANCE: 'Verificar a quantidade de dinheiro no banco da ilha.'\nCOMMAND_DESCRIPTION_BAN: 'Banir um jogador de sua ilha.'\nCOMMAND_DESCRIPTION_BANK: 'Abrir o banco da ilha.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: 'Alterar o bioma da ilha.'\nCOMMAND_DESCRIPTION_BORDER: 'Alterar a cor da borda das ilhas.'\nCOMMAND_DESCRIPTION_CHEST: 'Abrir o baú da ilha.'\nCOMMAND_DESCRIPTION_CLOSE: 'Fechar a ilha para o público.'\nCOMMAND_DESCRIPTION_COOP: 'Adicionar um jogador como coop na sua ilha.'\nCOMMAND_DESCRIPTION_COOPS: 'Abrir o menu de coops.'\nCOMMAND_DESCRIPTION_COUNTS: 'Ver contagem de blocos na sua ilha.'\nCOMMAND_DESCRIPTION_CREATE: 'Criar uma nova ilha.'\nCOMMAND_DESCRIPTION_DEL_WARP: 'Excluir um warp da ilha.'\nCOMMAND_DESCRIPTION_DEMOTE: 'Rebaixar um membro na sua ilha.'\nCOMMAND_DESCRIPTION_DEPOSIT: 'Depositar dinheiro da sua conta pessoal no banco da ilha.'\nCOMMAND_DESCRIPTION_DISBAND: 'Dissolver sua ilha permanentemente.'\nCOMMAND_DESCRIPTION_EXPEL: 'Expulsar um visitante da sua ilha.'\nCOMMAND_DESCRIPTION_FLY: 'Alternar o modo de voo na ilha.'\nCOMMAND_DESCRIPTION_HELP: 'Lista de todos os comandos.'\nCOMMAND_DESCRIPTION_INVITE: 'Convidar um jogador para sua ilha.'\nCOMMAND_DESCRIPTION_KICK: 'Expulsar um jogador da sua ilha.'\nCOMMAND_DESCRIPTION_LANG: 'Alterar seu idioma pessoal.'\nCOMMAND_DESCRIPTION_LEAVE: 'Sair da sua ilha.'\nCOMMAND_DESCRIPTION_MEMBERS: 'Abrir o menu de membros.'\nCOMMAND_DESCRIPTION_MISSION: 'Completar uma missão.'\nCOMMAND_DESCRIPTION_MISSIONS: 'Abrir o menu de missões.'\nCOMMAND_DESCRIPTION_NAME: 'Alterar o nome da sua ilha.'\nCOMMAND_DESCRIPTION_OPEN: 'Abrir a ilha para o público.'\nCOMMAND_DESCRIPTION_PANEL: 'Abrir o painel da ilha.'\nCOMMAND_DESCRIPTION_PARDON: 'Desbanir um jogador da sua ilha.'\nCOMMAND_DESCRIPTION_PERMISSIONS: 'Exibir todas as permissões para um cargo da ilha.'\nCOMMAND_DESCRIPTION_PROMOTE: 'Promover um membro na sua ilha.'\nCOMMAND_DESCRIPTION_RANKUP: 'Subir de nível em um upgrade.'\nCOMMAND_DESCRIPTION_RATE: 'Avaliar uma ilha.'\nCOMMAND_DESCRIPTION_RATINGS: 'Exibir todas as avaliações das ilhas.'\nCOMMAND_DESCRIPTION_SETTINGS: 'Abrir o menu de configurações.'\nCOMMAND_DESCRIPTION_RECALC: 'Recalcular o valor da ilha.'\nCOMMAND_DESCRIPTION_SET_DISCORD: 'Definir o discord da ilha para prêmios de ilha.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: 'Definir o e-mail do PayPal da ilha para prêmios de ilha.'\nCOMMAND_DESCRIPTION_SET_ROLE: 'Alterar o cargo de um jogador na sua ilha.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: 'Alterar a localização de teleporte da sua ilha.'\nCOMMAND_DESCRIPTION_SET_WARP: 'Criar um novo warp da ilha.'\nCOMMAND_DESCRIPTION_SHOW: 'Obter informações sobre uma ilha.'\nCOMMAND_DESCRIPTION_TEAM: 'Obter informações sobre o status dos membros da ilha.'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'Alternar o modo de chat da equipe.'\nCOMMAND_DESCRIPTION_TELEPORT: 'Teletransportar para sua ilha.'\nCOMMAND_DESCRIPTION_TOGGLE: 'Alternar as bordas da ilha e o posicionamento de blocos empilhados.'\nCOMMAND_DESCRIPTION_TOP: 'Abrir o painel das melhores ilhas.'\nCOMMAND_DESCRIPTION_TRANSFER: 'Transferir a liderança da sua ilha.'\nCOMMAND_DESCRIPTION_UNCOOP: 'Remover um jogador como coop da sua ilha.'\nCOMMAND_DESCRIPTION_UPGRADE: 'Abrir o painel de upgrades.'\nCOMMAND_DESCRIPTION_VALUE: 'Obter o valor de um bloco.'\nCOMMAND_DESCRIPTION_VALUES: 'Abrir o menu de valores.'\nCOMMAND_DESCRIPTION_VISIT: 'Teletransportar para o local de visitantes de uma ilha.'\nCOMMAND_DESCRIPTION_VISITORS: 'Abrir o menu de visitantes.'\nCOMMAND_DESCRIPTION_WARP: 'Ir para um warp da ilha.'\nCOMMAND_DESCRIPTION_WARPS: 'Abrir o menu de warps.'\nCOMMAND_DESCRIPTION_WITHDRAW: 'Retirar dinheiro do banco da sua ilha para sua conta pessoal.'\nCOMMAND_USAGE: '&cUso: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lIlha | &7{0} adicionou {1} como membro coop.'\nCOOP_BANNED_PLAYER: '&c&lErro | &7Este jogador está banido da ilha e não pode ser adicionado como coop.'\nCOOP_LIMIT_EXCEED: '&c&lErro | &7Você atingiu o número máximo de jogadores coop que a ilha pode ter.'\nCREATE_ISLAND: '&e&lIlha | &7Criou uma nova ilha em {0} em {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lErro | &7Ocorreu um erro ao criar sua ilha. Por favor, entre em contato com o administrador para investigar o problema.'\nCREATE_WORLD_FAILURE: '&c&lErro | &7Ocorreu um erro ao gerar o mundo. Por favor, entre em contato com o administrador para investigar o problema.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7Modo de debug alternado para &cDESATIVADO&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7Modo de debug alternado para &aATIVADO&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Filtro de debug {0} alternado para &aATIVADO&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Todos os filtros de debug alternados para &cDESATIVADO&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Filtro de debug {0} alternado para &cDESATIVADO&7.'\nDELETE_WARP: '&e&lIlha | &7Você excluiu o warp {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oHavia uma placa para esse warp, ela foi quebrada...'\nDEMOTE_LEADER: '&c&lErro | &7Você não pode rebaixar líderes da ilha.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode rebaixar jogadores com um cargo inferior ao seu.'\nDEMOTED_MEMBER: '&e&lIlha | &7Você rebaixou {0} para {1} na ilha dele.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBanco | &7{0} depositou ${1} no banco da ilha!'\nDEPOSIT_ERROR: '&c&lErro | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode destruir fora da sua área de proteção.'\nDISBAND_ANNOUNCEMENT: '&e&lIlha | &7Sua ilha foi apagada por {0}.'\nDISBAND_GIVE: '&e&lIlha | &7Você recebeu {0} dissoluções.'\nDISBAND_GIVE_ALL: '&e&lIlha | &7Você deu {0} dissoluções para todos os jogadores.'\nDISBAND_GIVE_OTHER: '&e&lIlha | &7Você deu {0} dissoluções para {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oSua ilha foi apagada, e ${0} foram reembolsados para sua conta a partir do banco da ilha.'\nDISBAND_SET: '&e&lIlha | &7O número de dissoluções foi definido como {0}.'\nDISBAND_SET_ALL: '&e&lIlha | &7Você definiu o número de dissoluções para todos os jogadores como {0}.'\nDISBAND_SET_OTHER: '&e&lIlha | &7Você definiu o número de dissoluções de {0} para {1}.'\nDISBANDED_ISLAND: '&e&lIlha | &7Você apagou sua ilha.'\nDISBANDED_ISLAND_OTHER: '&e&lIlha | &7Você apagou a ilha de {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lIlha | &7Você apagou a ilha {0}.'\nENTER_PVP_ISLAND: '&7&oVocê foi teleportado para uma ilha com PVP ativado. Você está imune ao PVP pelos próximos 10 segundos...'\nEXPELLED_PLAYER: '&e&lIlha | &7{0} foi expulso da ilha.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: 'segundos'\nFORMAT_SECOND_NAME: 'segundo'\nFORMAT_MINUTES_NAME: 'minutos'\nFORMAT_MINUTE_NAME: 'minuto'\nFORMAT_HOURS_NAME: 'horas'\nFORMAT_HOUR_NAME: 'hora'\nFORMAT_DAYS_NAME: 'dias'\nFORMAT_DAY_NAME: 'dia'\nGENERATOR_CLEARED: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.'\nGENERATOR_CLEARED_NAME: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.'\nGENERATOR_CLEARED_ALL: '&e&lIlha | &7Os valores do gerador de todas as ilhas foram limpos com sucesso.'\nGENERATOR_UPDATED: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.'\nGENERATOR_UPDATED_NAME: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.'\nGENERATOR_UPDATED_ALL: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para todas as ilhas.'\nGLOBAL_COMMAND_EXECUTED: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!'\nGLOBAL_TITLE_SENT: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!'\nGLOBAL_TITLE_SENT_NAME: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!'\nGOT_BANNED: '&e&lIlha | &7Você foi BANIDO da ilha de {0}.'\nGOT_DEMOTED: '&e&lIlha | &7Você foi rebaixado para {0} na sua ilha.'\nGOT_EXPELLED: '&e&lIlha | &7&oVocê foi expulso da ilha por {0}.'\nGOT_INVITE: '&e&lIlha | &7{0} convidou você para a ilha dele.'\nGOT_INVITE_TOOLTIP: '&7Clique na mensagem para aceitar o convite.'\nGOT_KICKED: '&e&lIlha | &7Você foi expulso da sua ilha por {0}.'\nGOT_PROMOTED: '&e&lIlha | &7Você foi promovido para {0} na sua ilha.'\nGOT_REVOKED: '&e&lIlha | &7{0} revogou seu convite para a ilha dele.'\nGOT_UNBANNED: '&e&lIlha | &7Você foi DESBANIDO da ilha de {0}.'\nHIT_ISLAND_MEMBER: '&c&lErro | &7Você não pode atacar membros da sua ilha.'\nHIT_PLAYER_IN_ISLAND: '&c&lErro | &7Você não pode atacar jogadores dentro de ilhas.'\nIGNORED_ISLAND: '&e&lIlha | &7A ilha de {0} agora está ignorada no ranking das melhores ilhas.'\nIGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora está ignorada no ranking das melhores ilhas.'\nINTERACT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode interagir fora da sua área de proteção.'\nINVALID_AMOUNT: '&c&lErro | &7Valor inválido {0}.'\nINVALID_BIOME: '&c&lErro | &7Bioma inválido {0}.'\nINVALID_BLOCK: '&c&lErro | &7Localização de bloco inválida {0}.'\nINVALID_BORDER_COLOR: '&c&lErro | &7Cor da borda inválida {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lErro | &7Efeito inválido {0}.'\nINVALID_ENTITY: '&c&lErro | &7Entidade inválida {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lErro | &7Intervalo inválido {0}.'\nINVALID_ISLAND: '&c&lErro | &7Você não tem uma ilha.'\nINVALID_ISLAND_LOCATION: '&c&lErro | &7Não há ilha na sua localização.'\nINVALID_ISLAND_OTHER: '&c&lErro | &7{0} não tem uma ilha.'\nINVALID_ISLAND_OTHER_NAME: '&c&lErro | &7Não existe uma ilha com o nome {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lErro | &7Não foi possível encontrar a permissão da ilha {0}.\n  &c&lErro | &7Permissões da ilha: {1}\nINVALID_LEVEL: '&c&lErro | &7Nível inválido {0}.'\nINVALID_LIMIT: '&c&lErro | &7Limite inválido {0}.'\nINVALID_MATERIAL: '&c&lErro | &7Material inválido {0}.'\nINVALID_MATERIAL_DATA: '&c&lErro | &7Material-dados inválido {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lErro | &7Missão inválida {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lErro | &7Módulo inválido {0}.'\nINVALID_MULTIPLIER: '&c&lErro | &7Multiplicador inválido {0}.'\nINVALID_PAGE: '&c&lErro | &7Página inválida {0}.'\nINVALID_PERCENTAGE: '&c&lErro | &7A porcentagem deve estar entre 0 e 100.'\nINVALID_PLAYER: '&c&lErro | &7Não foi possível encontrar um jogador chamado {0}.'\nINVALID_RATE: |\n  &c&lErro | &7Não foi possível encontrar uma classificação com o nome {0}.\n  &c&lErro | &7Classificações da ilha: {1}\nINVALID_ROWS: '&c&lErro | &7Quantidade inválida de linhas: {0}'\nINVALID_ROLE: |\n  &c&lErro | &7Não foi possível encontrar a função da ilha {0}.\n  &c&lErro | &7Funções da ilha: {1}\nINVALID_SCHEMATIC: '&c&lErro | &7Não foi possível encontrar um esquema com o nome {0}.'\nINVALID_SETTINGS: |\n  &c&lErro | &7Não foi possível encontrar as configurações da ilha {0}.\n  &c&lErro | &7Configurações da ilha: {1}\nINVALID_SIZE: '&c&lErro | &7Tamanho inválido {0}.'\nINVALID_SLOT: '&c&lErro | &7Slot inválido {0}.'\nINVALID_TITLE: '&c&lErro | &7Título inválido inserido.'\nINVALID_TOGGLE_MODE: '&c&lErro | &7Não é possível alternar {0}.'\nINVALID_UPGRADE: |\n  &c&lErro | &7Não foi possível encontrar uma atualização chamada {0}.\n  &c&lErro | &7Atualizações: {1}\nINVALID_VISIT_LOCATION: '&c&lErro | &7Esta ilha não tem localização de visitantes.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oVocê tem o modo bypass, teletransportando você para a ilha...'\nINVALID_WARP: '&c&lErro | &7Warp inválido {0}.'\nINVALID_WORLD: '&c&lErro | &7Mundo inválido {0}.'\nINVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} convidou {1} para a ilha.'\nINVITE_BANNED_PLAYER: '&c&lErro | &7Este jogador foi banido da ilha e não pode ser convidado.'\nINVITE_TO_FULL_ISLAND: '&c&lErro | &7Você não pode convidar mais membros para sua ilha.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lErro | &7Uma ilha com esse nome já existe.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lBanco | &7O banco da ilha está vazio.'\nISLAND_BANK_SHOW: '&e&lBanco | &7Sua ilha tem ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7A ilha de {0} tem ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanco | &7A ilha {0} tem ${1}.'\nISLAND_BEING_CALCULATED: '&c&lErro | &7Você não pode interagir com blocos quando a ilha está sendo recalculada!'\nISLAND_CLOSED: '&e&lIsland | &7A ilha foi fechada com sucesso para o público.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lErro | &7Você já tem uma tarefa de criação de ilha em andamento.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &cdesabilitado&7.'\nISLAND_FLY_ENABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &ahabilitado&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIlha | &7&oVocê estava dentro de uma ilha que foi apagada, então você foi teletransportado de volta para spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIlha | &7&oVocê estava dentro de uma ilha que havia ativado o PvP, então você foi teletransportado de volta para o spawn...'\nISLAND_HELP_FOOTER: '&e&lSkyblock &7Desenvolvido por Ome_R'\nISLAND_HELP_HEADER: '&e&lSkyblock &7Lista de Comandos [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is help {0} para a próxima página.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIlha | &7Limite do Banco: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lIlha | &7Blocos Limites:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIlha | &7Limite de coop: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de colheitas: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de gotas: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lIlha | &7Efeitos da Ilha:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIlha | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lIlha | Limites de &7Entidades:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIlha | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lIlha | &7Taxas de Geração ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIlha | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lIlha | &7Limites de Função:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIlha | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lIlha | &7Tamanho da Borda: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIlha | &7Multiplicador de Geradores: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIlha | &7Limite da Equipe: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lIlha | &7Melhorias:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIlha | &7 {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIlha | &7Limite de Warps: {0}'\nISLAND_INFO_BANK: '&e&lIlha | &7Banco: {0}'\nISLAND_INFO_BONUS: '&e&lIlha | &7Bônus de valor: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lIlha | &7Bônus de nível: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lIlha | &7Hora da criação: {0}'\nISLAND_INFO_DISCORD: '&e&lIlha | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lIlha | &7Última atualização: {0} atrás'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIlha | &7Última atualização: &aAtualmente ativo'\nISLAND_INFO_LEVEL: '&e&lIlha | &7Nível: {0}'\nISLAND_INFO_LOCATION: '&e&lIlha | &7Casa: {0}'\nISLAND_INFO_NAME: '&e&lIlha | &7Nome: {0}'\nISLAND_INFO_OWNER: '&e&lIlha | &7Líder: {0}'\nISLAND_INFO_PAYPAL: '&e&lIlha | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lIlha | &7 - {0}'\nISLAND_INFO_RATE: '&e&lIlha | &7Rate: {0} &7({1}/5) - {2} avaliações totais.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lIlha | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não está mais no modo de visualização.'\nISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR'\nISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lVisualizar | &7Você iniciou o modo de visualização para o esquema {0}.\n  &e&lVisualizar | &7Digite &a&lCONFIRMAR &7para criar uma nova ilha, ou &c&lCANCELAR &7para cancelar o modo de pré-visualização.\n  &e&lPreview | &7Você não pode sair da área da ilha, caso contrário, o modo de pré-visualização será cancelado automaticamente.\nISLAND_PROTECTED: '&c&lErro | &7Esta ilha está protegida.'\nISLAND_PROTECTED_OPPED: '&7&oVocê pode ignorar esta restrição usando \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lIlha | &7Membros da Ilha de {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Online)'\nISLAND_TEAM_STATUS_ROLES: '&e&lIlha | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Offline)'\nISLAND_TOP_STATUS_ONLINE: '&a(Online)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Privado]'\nISLAND_WAS_CLOSED: '&e&lIlha | &7&oA ilha em que você estava foi fechada e você foi teletransportado de volta para o spawn...'\nISLAND_WORTH_ERROR: '&c&lErro | &7Ocorreu um erro inesperado ao calcular sua ilha. Entre em contato com os administradores se o problema persistir.'\nISLAND_WORTH_RESULT: '&e&lIlha | &7O valor da sua ilha é {0} [Nível {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lErro | &7A tarefa de cálculo expirou. Tente novamente mais tarde...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.'\nJOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.'\nJOIN_FULL_ISLAND: '&c&lErro | &7Esta ilha atingiu a quantidade máxima de membros permitidos.'\nJOIN_WHILE_IN_ISLAND: '&c&lErro | &7Você já está dentro de uma ilha.'\nJOINED_ISLAND: '&e&lIlha | &7Você entrou na ilha de {0}.'\nJOINED_ISLAND_NAME: '&e&lIlha | &7Você entrou na ilha {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lIlha | &7Você agora é um membro cooperativo da ilha de {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lIlha | &7Agora você é um membro cooperativo da ilha {0}.'\nKICK_ANNOUNCEMENT: '&e&lIlha | &7{0} foi expulso da ilha por {1}.'\nKICK_ISLAND_LEADER: '&c&lErro | &7Você não pode expulsar o líder da ilha, use /is admin disband em vez disso.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode expulsar jogadores com uma função de ilha inferior à sua.'\nLACK_CHANGE_PERMISSION: '&c&lErro | &7Você deve ter esta permissão para alterá-la para outras funções.'\nLAST_ROLE_DEMOTE: '&c&lErro | &7Você não pode mais rebaixar este jogador.'\nLAST_ROLE_PROMOTE: '&c&lErro | &7Você não pode mais promover este jogador.'\nLEAVE_ANNOUNCEMENT: '&e&lIlha | &7{0} deixou a ilha.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lErro | &7Você não pode deixar sua ilha quando você a possui.\n  &c&lErro | &7Você pode transferir a propriedade usando /is transfer.\nLEFT_ISLAND: '&e&lIlha | &7Você saiu da sua ilha.'\nLEFT_ISLAND_COOP: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha de {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lErro | &7Você deve fornecer um material sólido.'\nMAXIMUM_LEVEL: '&c&lErro | &7O nível máximo para esta atualização é {0}.'\nMESSAGE_SENT: '&e&lIlha | &7A mensagem foi enviada com sucesso para {0}!'\nMISSION_CANNOT_COMPLETE: '&c&lErro | &7Você não pode concluir esta missão ainda.'\nMISSION_NO_AUTO_REWARD: '&e&lMissão | &7Você tem todos os materiais necessários para concluir {0} - use /is missions para concluir!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErro | &7Você deve concluir {0} antes de concluir esta missão.'\nMISSION_STATUS_COMPLETE: '&e&lMissão | &7Alterou o status da missão {0} para concluída para {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lMissão | &7Alterou o status de todas as missões para concluídas para {0}.'\nMISSION_STATUS_RESET: '&e&lMissão | &7Redefiniu o status da missão {0} para {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lMissão | &7Redefiniu o status de todas as missões para {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lMódulo | &7Este módulo já está carregado.'\nMODULE_INFO: |\n  &e&lMódulo | &7{0} por {1}\n  &e&lMódulo | &7&m--------------------\n  &e&lMódulo | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lMódulo | &7Carregou o módulo {0} com sucesso.'\nMODULE_LOADED_FAILURE: '&e&lMódulo | &7Não foi possível carregar o módulo {0}. Verifique o console para obter mais informações.'\nMODULE_UNLOADED_SUCCESS: '&e&lMódulo | &7Descarregado o módulo com sucesso.'\nMODULES_LIST: '&fMódulos ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lIlha | &7{0} alterou o nome da ilha para {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lErro | &7Você não pode usar esse nome.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lErro | &7Você não pode usar nomes de jogadores como nomes de ilhas.'\nNAME_TOO_LONG: '&c&lErro | &7Os nomes de ilhas não podem ter mais de {0} caracteres.'\nNAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de {0} caracteres.'\nNO_BAN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para banir jogadores.'\nNO_CLOSE_BYPASS: '&c&lErro | &7Esta ilha não está aberta ao público.'\nNO_CLOSE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para fechar a ilha ao público.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para adicionar jogadores como membros cooperativos.'\nNO_DELETE_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para excluir warps.'\nNO_DEMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para rebaixar jogadores.'\nNO_DEPOSIT_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para depositar dinheiro no banco da ilha.'\nNO_DISBAND_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para dissolver sua ilha.'\nNO_EXPEL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores de sua ilha.'\nNO_INVITE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para convidar jogadores.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para acessar o baú da ilha.'\nNO_ISLAND_INVITE: '&c&lErro | &7Não foi possível encontrar nenhum convite desta ilha.'\nNO_ISLANDS_TO_PURGE: '&c&lErro | &7Não havia ilhas para expurgar.'\nNO_KICK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores.'\nNO_MORE_DISBANDS: '&c&lErro | &7Você não pode dissolver mais nenhuma ilha.'\nNO_MORE_WARPS: '&c&lErro | &7Sua ilha não pode ter mais nenhuma teletransportação.'\nNO_NAME_PERMISSION: '&c&lErro | &7Você não pode alterar o nome da sua ilha.'\nNO_OPEN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para abrir a ilha ao público.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para obter informações sobre permissões.'\nNO_PROMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para promover jogadores.'\nNO_RANKUP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para aumentar a classificação.'\nNO_RATINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para verificar as classificações.'\nNO_SET_BIOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o bioma da ilha.'\nNO_SET_DISCORD_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o discord da ilha.'\nNO_SET_HOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir o local de teletransporte da ilha.'\nNO_SET_PAYPAL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o e-mail do PayPal da ilha.'\nNO_SET_ROLE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir funções para os jogadores.'\nNO_SET_SETTINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar as configurações da ilha.'\nNO_SET_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para poder definir teletransportes de ilha.'\nNO_TRANSFER_PERMISSION: '&c&lErro | &7Você deve ser o líder da ilha para poder transferir a liderança.'\nNO_UNCOOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para remover jogadores de serem membros cooperativos.'\nNO_UPGRADE_PERMISSION: '&c&lErro | &7Você não tem permissão para fazer upgrade para outro nível.'\nNO_WITHDRAW_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para sacar dinheiro do banco da ilha.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErro | &7Você não tem dinheiro suficiente para depositar {0} dólares no banco da sua ilha.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErro | &7Você não tem dinheiro suficiente.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lErro | &7Você não tem dinheiro suficiente para usar os teleportes de ilha.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oVocê está cansado demais para interagir com os menus, não acha?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPainel | &7Painel da ilha desativado &cOFF&7.\n  &e&lPainel | &7Executar /is te teleportará para a ilha.\nPANEL_TOGGLE_ON: |-\n  &e&lPainel | &7Painel da ilha ativado &aON&7.\n  &e&lPainel | &7Executar /is abrirá o painel para você.\nPERMISSION_CHANGED: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha de {1}.'\nPERMISSION_CHANGED_NAME: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha {1}.'\nPERMISSION_CHANGED_ALL: '&e&lIlha | &7Atualizada com sucesso a permissão {0} para todas as ilhas.'\nPERSISTENT_DATA_EMPTY: '&c&lErro | &7Nenhum dado foi encontrado para sua consulta.'\nPERSISTENT_DATA_MODIFY: '&e&lDados | &7Definidos com sucesso os dados para {0} com {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lDados | &7Dados de {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lData | &7Dados removidos com sucesso para {0} do caminho {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lIlha | &7Redefiniu com sucesso todas as permissões para {0} para os valores padrão!'\nPERMISSIONS_RESET_ROLES: '&e&lIlha | &7Redefiniu com sucesso todas as permissões da ilha para os valores padrão!'\nPLACEHOLDER_NO: 'Não'\nPLACEHOLDER_YES: 'Sim'\nPLAYER_ALREADY_BANNED: '&c&lErro | &7Este jogador já foi banido.'\nPLAYER_ALREADY_COOP: '&c&lErro | &7Este jogador já é cooperativo.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lErro | &7Este jogador já está dentro de uma ilha.'\nPLAYER_ALREADY_IN_ROLE: '&c&lErro | &7{0} já é um {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lErro | &7Este usuário não pode ser expulso da ilha.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou no servidor.'\nPLAYER_NOT_BANNED: '&c&lErro | &7Este jogador não está banido.'\nPLAYER_NOT_COOP: '&c&lErro | &7Este jogador não é cooperativo.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lErro | &7Este jogador não está dentro da sua ilha.'\nPLAYER_NOT_ONLINE: '&c&lErro | &7Este jogador não está online!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do servidor.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode promover jogadores com uma função de ilha inferior à sua.'\nPROMOTED_MEMBER: '&e&lIlha | &7Você promoveu {0} para um {1} na ilha dele.'\nPURGE_CLEAR: '&e&lIlha | &7Todas as ilhas na fila para serem expurgadas foram limpas com sucesso.'\nPURGED_ISLANDS: |-\n  &e&lIlha | &7{0} ilhas serão purgadas quando o servidor reiniciar.\n  &e&lIlha | &7Você pode cancelar a qualquer momento usando /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para a ilha de {1}.'\nRANKUP_SUCCESS_ALL: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para todas as ilhas.'\nRANKUP_SUCCESS_NAME: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lIlha | &7{0} classificou sua ilha {1} de 5!.'\nRATE_CHANGE_OTHER: '&e&lIlha | &7Você alterou a classificação de {0} para {1}.'\nRATE_OWN_ISLAND: '&c&lErro | &7Você não pode classificar sua própria ilha.'\nRATE_REMOVE_ALL: '&e&lIlha | &7Todas as classificações de {0} foram removidas com sucesso.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lIlha | &7Todas as classificações de todas as ilhas foram removidas com sucesso.'\nRATE_SUCCESS: '&e&lIlha | &7Você classificou esta ilha com {0} estrelas!'\nREACHED_BLOCK_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para o bloco {0}.'\nREACHED_ENTITY_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para a entidade {0}.'\nRECALC_ALREADY_RUNNING: '&c&lErro | &7Sua ilha já está sendo recalculada.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lErro | &7Esta ilha já está sendo recalculada.'\nRECALC_ALL_ISLANDS: '&e&lIlha | &7Recalculando todas as ilhas...'\nRECALC_ALL_ISLANDS_DONE: '&e&lIlha | &7Concluída com sucesso a recalculação de todas as ilhas.'\nRECALC_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...'\nRELOAD_COMPLETED: '&e&lIlha | &7Recarregamento concluído!'\nRELOAD_PROCCESS_REQUEST: '&e&lIlha | &7Começando a recarregar as configurações...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} revogou o convite de {1} para a ilha.'\nRESET_WORLD_SUCCEED: '&e&lIlha | &7Redefiniu com sucesso o mundo {0} para a ilha de {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para todas as ilhas.'\nRESET_WORLD_SUCCEED_NAME: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para {1}.'\nSAME_NAME_CHANGE: '&c&lErro | &7Você deve digitar um nome diferente do nome atual da sua ilha.'\nSCHEMATIC_LEFT_SELECT: '&e&lEsquemas | &7Posição selecionada nº 2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lErro | &7Você não selecionou duas posições.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lEsquemas | &7Processando sua solicitação...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lschematic | &7Você selecionou duas posições. Execute /is admin schematic <nome> para criar um novo esquema.\n  &e&lschematic | &7Certifique-se de estar no local de teleportação ao executar o comando.\nSCHEMATIC_RIGHT_SELECT: '&e&lschematic | &7Posição selecionada nº 1 ({0})'\nSCHEMATIC_SAVED: '&e&lschematic | &7Esquema salvo com sucesso!'\nSELF_ROLE_CHANGE: '&c&lErro | &7Você não pode alterar sua função.'\nSET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para a ilha de {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.'\nSET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.'\nSET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha de {1}.'\nSETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.'\nSETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.'\nSIZE_BIGGER_MAX: '&c&lErro | &7Você não pode definir um tamanho maior que o tamanho máximo da ilha.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado com sucesso {0} para spawn.'\nSPAWN_SET_SUCCESS: '&e&lSpawn | &7Atualizado com sucesso o local de spawn para {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lAtualizações | &7Todos os valores de atualização da ilha de {0} foram sincronizados com sucesso.'\nSYNC_UPGRADES_ALL: '&e&lAtualizações | &7Todos os valores de atualização de todas as ilhas foram sincronizados com sucesso.'\nSYNC_UPGRADES_NAME: '&e&lAtualizações | &7Todos os valores de atualização de {0} foram sincronizados com sucesso.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErro | &7Você não está dentro da sua ilha.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode se teletransportar para fora do seu alcance de proteção.'\nTELEPORT_WARMUP: '&7&oVocê será teletransportado em {0}... Não se mova!'\nTELEPORT_WARMUP_CANCEL: '&7&oVocê se moveu e então o teletransporte foi cancelado.'\nTITLE_SENT: '&e&lIlha | &7Enviado com sucesso {0} o título!'\nTELEPORTED_FAILED: '&e&lIlha | &7Parece que esta ilha não tem blocos seguros. Entre em contato com um membro da equipe.'\nTELEPORTED_SUCCESS: '&e&lIlha | &7Você foi teletransportado para sua ilha.'\nTELEPORTED_TO_WARP: '&e&lIlha | &7Teletransportado com sucesso para esta dobra de ilha.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIlha | &7O jogador {0} teletransportou-se para a ilha warp {1}.'\nTOGGLED_BYPASS_OFF: '&e&lIgnorar | &7Modo de desvio alternado &cOFF&7.'\nTOGGLED_BYPASS_ON: '&e&lIgnorar | &7Modo de desvio alternado &aON&7.'\nTOGGLED_FLY_OFF: '&e&lVoar | &7Voar ilha alternado &cOFF&7.'\nTOGGLED_FLY_ON: '&e&lVoar | &7Voar ilha alternado &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lEsquemas | &7Alternando modo esquemático &cOFF&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lschematic | &7Modo de esquemas ativado &aON&7.\n  &e&lschematic | &7Selecione uma área usando um machado dourado.\nTOGGLED_SPY_OFF: '&e&lSpy | &7Alternado bate-papo espião &cOFF&7.'\nTOGGLED_SPY_ON: '&e&lSpy | &7Alternado bate-papo espião &aON&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Alternando empilhador de blocos &cOFF&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Alternando empilhador de blocos &aON&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Alternando bate-papo da equipe &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Alternando bate-papo da equipe &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Alternando borda do mundo &cOFF&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Alternando a fronteira mundial &aON&7.'\nTRANSFER_ADMIN: '&e&lIlha | &7Você transferiu a liderança de {0} para {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lErro | &7{0} já é o líder de sua ilha.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErro | &7Estes jogadores não estão nas mesmas ilhas.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lErro | &7Este jogador não é líder de nenhuma ilha.'\nTRANSFER_ALREADY_LEADER: '&c&lErro | &7Você já é o líder desta ilha.'\nTRANSFER_BROADCAST: '&e&lIlha | &7A liderança da ilha foi transferida para {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi DESBANIDO da ilha por {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lIlha | &7{0} removeu {1} de ser um membro cooperativo.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lIlha | &7Não há membros da ilha online e, portanto, você foi descoopado automaticamente.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do jogo e não é mais um membro cooperativo.'\nUNIGNORED_ISLAND: A ilha de '&e&lIlha | &7{0}' agora não é mais ignorada das ilhas principais.'\nUNIGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora não é mais ignorada das ilhas principais.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lIlha | &7&oParece que este warp não é seguro. Tente outro warp.'\nUPDATED_PERMISSION: '&e&lIlha | &7Permissões atualizadas para {0}.'\nUPDATED_SETTINGS: '&e&lIlha | &7Configurações da ilha [{0}] atualizado.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode atualizar novamente em {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lErro | &7Você não pode usar esse comando em outras ilhas.'\nWARP_ALREADY_EXIST: '&c&lErro | &7Já existe um warp com este nome.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lWarps | &7Digite uma nova lore (digite \"-cancel\" para cancelar):\n  &e&lWarps | &7Você pode separar linhas usando \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite \"-cancel\" para cancelar):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite \"-cancel\" para cancelar):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7O ícone da categoria foi atualizado com sucesso.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lErro | &7Os nomes das categorias de warp não podem estar vazios.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lErro | Os nomes de categorias do Warp não podem ter mais de 255 caracteres.'\nWARP_CATEGORY_SLOT: '&e&lWarps | &7Digite um novo slot (digite \"-cancel\" para cancelar):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErro | &7Este slot já foi ocupado por outra categoria.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7O slot da categoria foi alterado com sucesso para {0}.'\nWARP_CATEGORY_RENAME: '&e&lWarps | &7Digite um novo nome (digite \"-cancel\" para cancelar):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi ocupado por outra categoria.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Categoria renomeada com sucesso para {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lWarps | &7Digite um novo lore (Digite \"-cancel\" para cancelar):\n  &e&lWarps | &7Você pode separar as linhas usando \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite \"-cancel\" para cancelar):'\nWARP_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite \"-cancel\" para cancelar):'\nWARP_ICON_UPDATED: '&e&lWarps | &7O ícone do warp foi atualizado com sucesso.'\nWARP_ILLEGAL_NAME: '&c&lErro | &7Os nomes do warp não podem estar vazios.'\nWARP_LOCATION_UPDATE: '&e&lWarps | &7Atualizou com sucesso a localização do warp para a sua localização.'\nWARP_NAME_TOO_LONG: '&c&lErro | Os nomes do warp não podem ter mais de 255 caracteres.'\nWARP_PUBLIC_UPDATE: '&e&lWarps | &7Abriu o warp com sucesso para o público.'\nWARP_PRIVATE_UPDATE: '&e&lWarps | &7Fechou o warp com sucesso para o público.'\nWARP_RENAME: '&e&lWarps | &7Digite um novo nome (digite \"-cancel\" para cancelar):'\nWARP_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi usado por outro warp.'\nWARP_RENAME_SUCCESS: '&e&lWarps | &7Renomeou o warp com sucesso para {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBanco | &7O banco da ilha tem apenas {0} dólares dentro dele.\n  &e&lBanco | &7&oRetirando todo o dinheiro...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} retirou ${1} do banco da ilha!'\nWITHDRAW_ERROR: '&c&lErro | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lWorlds | &7O mundo {0} ainda não está desbloqueado!'"
  },
  {
    "path": "src/main/resources/lang/ru-RU.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lОстров | &7Успешно добавлен игрок {0} на остров {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lОстров | &7Успешно добавлен игрок {0} на остров {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lБанк | &7Вы внесли ${0} на банковский счет острова {1}.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lБанк | &7Вы внесли ${0} на банковский счет острова {1}.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Разработано Ome_R'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Список команд администратора [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Используйте /is admin {0} для следующей страницы.'\nALREADY_IN_ISLAND: '&c&lОшибка | &7Вы уже на острове.'\nALREADY_IN_ISLAND_OTHER: '&c&lОшибка | &7Этот игрок уже является членом вашего острова.'\nBAN_ANNOUNCEMENT: '&e&lОстров | &7{0} был ЗАБАНЕН на острове {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете банить только игроков с более низкой ролью на острове.'\nBANK_DEPOSIT_CUSTOM: '&e&lБанк | &7Введите сумму, которую хотите внести:'\nBANK_DEPOSIT_COMPLETED: 'Внесение завершено'\nBANK_LIMIT_EXCEED: '&c&lОшибка | &7Вы превысили лимит банка.'\nBANK_WITHDRAW_CUSTOM: '&e&lБанк | &7Введите сумму, которую хотите снять:'\nBANK_WITHDRAW_COMPLETED: 'Снятие завершено'\nBANNED_FROM_ISLAND: '&c&lОшибка | &7Вы забанены на этом острове.'\nBLOCK_COUNT_CHECK: '&e&lОстров | &7На этом острове x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lОстров | &7На этом острове следующие блоки:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lОстров | &7На этом острове нет отслеживаемых блоков.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lУровень | &7Уровень блока {0} составляет {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lУровень | &7Блок {0} бесполезен.'\nBLOCK_VALUE: '&e&lЦена | &7Блок {0} стоит {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lЦена | &7Блок {0} бесполезен.'\nBONUS_SYNC_ALL: '&e&lОстров | &7Успешно синхронизирован бонус острова для всех островов.'\nBONUS_SYNC_NAME: '&e&lОстров | &7Успешно синхронизирован бонус острова для {0}.'\nBONUS_SYNC: '&e&lОстров | &7Успешно синхронизирован бонус острова для острова {0}.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Синий'\nBORDER_PLAYER_COLOR_NAME_RED: 'Красный'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Зеленый'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lГраница | &7Успешно изменен цвет вашей личной границы на {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете строить за пределами вашей защитной зоны.'\nCANNOT_SET_ROLE: '&c&lОшибка | &7Вы не можете установить роль игрока на {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lОшибка | &7Вы можете изменять права только для роли острова ниже вашей.'\nCHANGED_BANK_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит банка для острова {0}.'\nCHANGED_BANK_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит банка для всех островов.'\nCHANGED_BANK_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит банка для {0}.'\nCHANGED_BIOME: '&e&lОстров | &7Успешно изменен биом на {0}. Вам может понадобиться переподключиться к серверу, чтобы увидеть изменения.'\nCHANGED_BIOME_ALL: '&e&lОстров | &7Успешно изменен биом на {0} для всех островов.'\nCHANGED_BIOME_NAME: '&e&lОстров | &7Успешно изменен биом на {0} для острова {1}.'\nCHANGED_BIOME_OTHER: '&e&lОстров | &7Успешно изменен биом на {0} для острова {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lБлоки | &7Успешно изменено количество блоков на {0} до {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для острова {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для всех островов.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для острова {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для всех островов.'\nCHANGED_CHEST_SIZE_NAME: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для {2}.'\nCHANGED_COOP_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для острова {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для всех островов.'\nCHANGED_COOP_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для {0}.'\nCHANGED_CROP_GROWTH: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для острова {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для всех островов.'\nCHANGED_CROP_GROWTH_NAME: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для {0}.'\nCHANGED_DISCORD: '&e&lОстров | &7Успешно изменен Discord острова на {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для острова {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для всех островов.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для острова {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для всех островов.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для {1}.'\nCHANGED_ISLAND_SIZE: '&e&lУлучшения | &7Успешно обновлен размер острова {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lУлучшения | &7Успешно обновлен размер острова для всех островов.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lУлучшения | &7Успешно обновлен размер острова для {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oИгроки могут строить за пределами своего острова, поэтому размер острова не имеет значения. Вы можете отключить эту функцию в конфигурации, чтобы размер острова снова имел значение.'\nCHANGED_LANGUAGE: '&e&lЯзык | &7Успешно изменен ваш язык на русский.'\nCHANGED_MOB_DROPS: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для острова {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для всех островов.'\nCHANGED_MOB_DROPS_NAME: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для {0}.'\nCHANGED_NAME: '&e&lОстров | &7Вы изменили название вашего острова на {0}&7.'\nCHANGED_NAME_OTHER: '&e&lОстров | &7Вы изменили название острова {0} на {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lОстров | &7Вы изменили имя {0}&7 на {1}&7.'\nCHANGED_PAYPAL: '&e&lОстров | &7Успешно изменен PayPal острова на {0}.'\nCHANGED_ROLE_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для острова {1}.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для всех островов.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для {1}.'\nCHANGED_SPAWNER_RATES: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для острова {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для всех островов.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для {0}.'\nCHANGED_TEAM_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит команды для острова {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит команды для всех островов.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит команды для {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lОстров | &7Успешно обновлено местоположение телепорта.'\nCHANGED_WARPS_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит варпов для острова {0}.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит варпов для всех островов.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит варпов для {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: 'количество'\nCOMMAND_ARGUMENT_BIOME: 'биом'\nCOMMAND_ARGUMENT_BORDER_COLOR: 'цвет-границы'\nCOMMAND_ARGUMENT_COMMAND: 'команда...'\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: 'дискорд...'\nCOMMAND_ARGUMENT_EFFECT: 'эффект-зелья'\nCOMMAND_ARGUMENT_EMAIL: 'email'\nCOMMAND_ARGUMENT_ENTITY: 'сущность'\nCOMMAND_ARGUMENT_ISLAND_NAME: 'название-острова'\nCOMMAND_ARGUMENT_ISLAND_ROLE: 'роль-острова'\nCOMMAND_ARGUMENT_LEADER: 'лидер'\nCOMMAND_ARGUMENT_LEVEL: 'уровень'\nCOMMAND_ARGUMENT_LIMIT: 'лимит'\nCOMMAND_ARGUMENT_MATERIAL: 'материал'\nCOMMAND_ARGUMENT_MENU: 'название-меню'\nCOMMAND_ARGUMENT_MESSAGE: 'сообщение...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: 'название-миссии'\nCOMMAND_ARGUMENT_MODULE_NAME: 'название-модуля'\nCOMMAND_ARGUMENT_MULTIPLIER: 'множитель'\nCOMMAND_ARGUMENT_NAME: 'имя'\nCOMMAND_ARGUMENT_NEW_LEADER: 'новый-лидер'\nCOMMAND_ARGUMENT_PAGE: 'страница'\nCOMMAND_ARGUMENT_PATH: 'путь'\nCOMMAND_ARGUMENT_PERMISSION: 'разрешение'\nCOMMAND_ARGUMENT_PLAYER_NAME: 'имя-игрока'\nCOMMAND_ARGUMENT_PRIVATE: 'приватный'\nCOMMAND_ARGUMENT_RATING: 'рейтинг'\nCOMMAND_ARGUMENT_ROWS: 'строки'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: 'название-схемы'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: 'настройки'\nCOMMAND_ARGUMENT_SIZE: 'размер'\nCOMMAND_ARGUMENT_TIME: 'время'\nCOMMAND_ARGUMENT_TITLE_DURATION: 'длительность'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'появление'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'исчезновение'\nCOMMAND_ARGUMENT_UPGRADE_NAME: 'название-улучшения'\nCOMMAND_ARGUMENT_VALUE: 'значение'\nCOMMAND_ARGUMENT_WARP_NAME: 'название-варпа'\nCOMMAND_ARGUMENT_WARP_CATEGORY: 'категория-варпа'\nCOMMAND_ARGUMENT_WORLD: 'мир'\nCOMMAND_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете использовать команду только через {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: 'Принять приглашение от игрока.'\nCOMMAND_DESCRIPTION_ADMIN: 'Использовать команды администратора.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: 'Добавить пользователя на остров.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Увеличить лимит блоков для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Добавить бонус игроку.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Увеличить лимит игроков-кооператоров для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Увеличить множитель роста культур для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Добавить эффект острова для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Увеличить лимит сущностей для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Добавить процент материала для генератора булыжника.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Увеличить множитель дропа мобов для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Расширить размер острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Увеличить множитель ставок спавнера для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Увеличить лимит участников для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Увеличить лимит варпов для острова.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: 'Предоставить бонус игроку.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: 'Включить/выключить режим обхода.'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Открыть сундук острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Очистить ставки генератора для конкретного острова.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: 'Закрыть остров для публики.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Выполнить команду для всех членов островов.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: 'Проверить количество блоков на конкретном острове.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Взаимодействовать с постоянными данными игроков или островов.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: 'Включить/выключить вывод отладки.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Удалить варп для острова.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Понизить участника на острове другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Внести деньги в банк острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: 'Расформировать остров другого игрока навсегда.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Выдать расформирования игроку.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: 'Игнорировать остров в списке лучших островов.'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: 'Присоединиться к острову без приглашения.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: 'Выгнать игрока с его острова.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Управлять модулями плагина.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: 'Изменить статус миссии для игрока.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: 'Отправить игроку сообщение без префиксов.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Отправить сообщение всем участникам острова без префиксов.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: 'Изменить имя острова.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: 'Открыть остров для публики.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Открыть пользовательское меню для игрока.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Повысить участника на острове другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: 'Очистить острова.'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: 'Повысить уровень улучшения для острова.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: 'Пересчитать стоимость острова.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: 'Перезагрузить все настройки и задачи плагина.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Удалить лимит блоков с острова.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Удалить все оценки, выставленные игроком.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Создать схемы для плагина.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Установить биом для острова.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Установить количество блоков в конкретном месте.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Установить лимит блоков для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Установить количество рядов в сундуке острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Установить лимит кооператоров для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Установить множитель роста культур для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Установить количество расформирований для игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Установить уровень эффекта острова для другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Установить лимит сущностей для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Передать остров другому игроку.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Установить множитель дропа мобов для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Установить необходимую роль для разрешения для всех островов.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Установить рейтинг другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Установить лимит роли для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Настроить параметры для конкретного острова.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Изменить процент материала для генератора булыжника.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Изменить размер острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Установить место спавна для сервера.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Установить множитель ставок спавнера для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Установить лимит участников для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Установить уровень улучшения для острова другого игрока.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Установить лимит варпов для острова.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Открыть редактор настроек плагина.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: 'Получить информацию об острове.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: 'Телепортироваться к месту спавна.'\nCOMMAND_DESCRIPTION_ADMIN_SPY: 'Включить/выключить режим шпионства в чате.'\nCOMMAND_DESCRIPTION_ADMIN_STATS: 'Показать статистику о плагине.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Синхронизировать бонус острова с генерируемыми мирами.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Синхронизировать значения улучшений для острова.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Телепортироваться к другим островам.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Отправить игроку титул.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Отправить титул всем участникам острова.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Удалить игнорирование острова из списка лучших.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Разблокировать мир для острова.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Снять деньги с банка острова другого игрока.'\nCOMMAND_DESCRIPTION_BALANCE: 'Проверить количество денег в банке острова.'\nCOMMAND_DESCRIPTION_BAN: 'Забанить игрока на своем острове.'\nCOMMAND_DESCRIPTION_BANK: 'Открыть банк острова.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: 'Изменить биом острова.'\nCOMMAND_DESCRIPTION_BORDER: 'Изменить цвет границы островов.'\nCOMMAND_DESCRIPTION_CHEST: 'Открыть сундук острова.'\nCOMMAND_DESCRIPTION_CLOSE: 'Закрыть остров для публики.'\nCOMMAND_DESCRIPTION_COOP: 'Добавить игрока в кооперацию на вашем острове.'\nCOMMAND_DESCRIPTION_COOPS: 'Открыть меню кооперации.'\nCOMMAND_DESCRIPTION_COUNTS: 'Посмотреть количество блоков на вашем острове.'\nCOMMAND_DESCRIPTION_CREATE: 'Создать новый остров.'\nCOMMAND_DESCRIPTION_DEL_WARP: 'Удалить варп острова.'\nCOMMAND_DESCRIPTION_DEMOTE: 'Понизить участника на вашем острове.'\nCOMMAND_DESCRIPTION_DEPOSIT: 'Внести деньги с личного счета в банк острова.'\nCOMMAND_DESCRIPTION_DISBAND: 'Расформировать свой остров навсегда.'\nCOMMAND_DESCRIPTION_EXPEL: 'Выгнать посетителя с вашего острова.'\nCOMMAND_DESCRIPTION_FLY: 'Включить/выключить полет на острове.'\nCOMMAND_DESCRIPTION_HELP: 'Список всех команд.'\nCOMMAND_DESCRIPTION_INVITE: 'Пригласить игрока на ваш остров.'\nCOMMAND_DESCRIPTION_KICK: 'Выгнать игрока с вашего острова.'\nCOMMAND_DESCRIPTION_LANG: 'Изменить личный язык.'\nCOMMAND_DESCRIPTION_LEAVE: 'Покинуть свой остров.'\nCOMMAND_DESCRIPTION_MEMBERS: 'Открыть меню участников.'\nCOMMAND_DESCRIPTION_MISSION: 'Выполнить миссию.'\nCOMMAND_DESCRIPTION_MISSIONS: 'Открыть меню миссий.'\nCOMMAND_DESCRIPTION_NAME: 'Изменить имя вашего острова.'\nCOMMAND_DESCRIPTION_OPEN: 'Открыть остров для публики.'\nCOMMAND_DESCRIPTION_PANEL: 'Открыть панель острова.'\nCOMMAND_DESCRIPTION_PARDON: 'Снять бан с игрока на вашем острове.'\nCOMMAND_DESCRIPTION_PERMISSIONS: 'Получить все разрешения для роли острова.'\nCOMMAND_DESCRIPTION_PROMOTE: 'Повысить участника на вашем острове.'\nCOMMAND_DESCRIPTION_RANKUP: 'Повысить уровень улучшения.'\nCOMMAND_DESCRIPTION_RATE: 'Оценить остров.'\nCOMMAND_DESCRIPTION_RATINGS: 'Показать все оценки островов.'\nCOMMAND_DESCRIPTION_SETTINGS: 'Открыть меню настроек.'\nCOMMAND_DESCRIPTION_RECALC: 'Пересчитать стоимость острова.'\nCOMMAND_DESCRIPTION_SET_DISCORD: 'Установить Discord для выплат острова.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: 'Установить электронную почту PayPal для выплат острова.'\nCOMMAND_DESCRIPTION_SET_ROLE: 'Изменить роль игрока на вашем острове.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: 'Изменить место телепортации вашего острова.'\nCOMMAND_DESCRIPTION_SET_WARP: 'Создать новый варп для острова.'\nCOMMAND_DESCRIPTION_SHOW: 'Получить информацию об острове.'\nCOMMAND_DESCRIPTION_TEAM: 'Получить информацию о статусе участников острова.'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'Включить/выключить режим командного чата.'\nCOMMAND_DESCRIPTION_TELEPORT: 'Телепортироваться на свой остров.'\nCOMMAND_DESCRIPTION_TOGGLE: 'Включить/выключить границы острова и размещение сложенных блоков.'\nCOMMAND_DESCRIPTION_TOP: 'Открыть панель лучших островов.'\nCOMMAND_DESCRIPTION_TRANSFER: 'Передать руководство вашим островом.'\nCOMMAND_DESCRIPTION_UNCOOP: 'Удалить игрока из кооперации на вашем острове.'\nCOMMAND_DESCRIPTION_UPGRADE: 'Открыть панель улучшений.'\nCOMMAND_DESCRIPTION_VALUE: 'Получить стоимость блока.'\nCOMMAND_DESCRIPTION_VALUES: 'Открыть меню значений.'\nCOMMAND_DESCRIPTION_VISIT: 'Телепортироваться к месту посетителей острова.'\nCOMMAND_DESCRIPTION_VISITORS: 'Открыть меню посетителей.'\nCOMMAND_DESCRIPTION_WARP: 'Телепортироваться к варпу острова.'\nCOMMAND_DESCRIPTION_WARPS: 'Открыть меню варпов.'\nCOMMAND_DESCRIPTION_WITHDRAW: 'Снять деньги из банка вашего острова на личный счет.'\nCOMMAND_USAGE: '&cИспользование: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lОстров | &7{0} добавил {1} в качестве кооператора.'\nCOOP_BANNED_PLAYER: '&c&lОшибка | &7Этот игрок забанен на острове и не может быть кооператором.'\nCOOP_LIMIT_EXCEED: '&c&lОшибка | &7Вы достигли максимального количества кооператоров на острове.'\nCREATE_ISLAND: '&e&lОстров | &7Создан новый остров в {0} за {1}мс.'\nCREATE_ISLAND_FAILURE: '&c&lОшибка | &7Произошла ошибка при создании вашего острова. Пожалуйста, свяжитесь с администратором.'\nCREATE_WORLD_FAILURE: '&c&lОшибка | &7Произошла ошибка при генерации вашего мира. Пожалуйста, свяжитесь с администратором.'\nDEBUG_MODE_DISABLED: '&e&lОтладка | &7Режим отладки отключен.'\nDEBUG_MODE_ENABLED: '&e&lОтладка | &7Режим отладки включен.'\nDEBUG_MODE_FILTER_ADD: '&e&lОтладка | &7Фильтр отладки {0} включен.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lОтладка | &7Все фильтры отладки отключены.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lОтладка | &7Фильтр отладки {0} отключен.'\nDELETE_WARP: '&e&lОстров | &7Вы удалили варп {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oСуществует знак для этого варпа, он был сломан...'\nDEMOTE_LEADER: '&c&lОшибка | &7Вы не можете понизить лидеров острова.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете понизить только игроков с более низкой ролью, чем ваша.'\nDEMOTED_MEMBER: '&e&lОстров | &7Вы понизили {0} до роли {1} на его острове.'\nDEPOSIT_ANNOUNCEMENT: '&e&lБанк | &7{0} внес ${1} в банк острова!'\nDEPOSIT_ERROR: '&c&lОшибка | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете разрушать за пределами своей зоны защиты.'\nDISBAND_ANNOUNCEMENT: '&e&lОстров | &7Ваш остров был расформирован {0}.'\nDISBAND_GIVE: '&e&lОстров | &7Вы получили {0} расформирований.'\nDISBAND_GIVE_ALL: '&e&lОстров | &7Вы выдали {0} расформирований всем игрокам.'\nDISBAND_GIVE_OTHER: '&e&lОстров | &7Вы выдали {0} расформирований {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oВаш остров был расформирован, и ${0} долларов были возвращены на ваш счет из банка острова.'\nDISBAND_SET: '&e&lОстров | &7Ваше количество расформирований было установлено на {0}.'\nDISBAND_SET_ALL: '&e&lОстров | &7Вы установили количество расформирований всех игроков на {0}.'\nDISBAND_SET_OTHER: '&e&lОстров | &7Вы установили количество расформирований {0} на {1}.'\nDISBANDED_ISLAND: '&e&lОстров | &7Вы расформировали свой остров.'\nDISBANDED_ISLAND_OTHER: '&e&lОстров | &7Вы расформировали остров {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lОстров | &7Вы расформировали остров {0}.'\nENTER_PVP_ISLAND: '&7&oВы были телепортированы на остров, где включен PvP. Вы защищены от PvP в течение следующих 10 секунд...'\nEXPELLED_PLAYER: '&e&lОстров | &7{0} был выгнан с острова.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: 'секунд'\nFORMAT_SECOND_NAME: 'секунда'\nFORMAT_MINUTES_NAME: 'минут'\nFORMAT_MINUTE_NAME: 'минута'\nFORMAT_HOURS_NAME: 'часов'\nFORMAT_HOUR_NAME: 'час'\nFORMAT_DAYS_NAME: 'дней'\nFORMAT_DAY_NAME: 'день'\nGENERATOR_CLEARED: '&e&lОстров | &7Успешно очищены значения генератора для острова {0}.'\nGENERATOR_CLEARED_NAME: '&e&lОстров | &7Успешно очищены значения генератора для острова {0}.'\nGENERATOR_CLEARED_ALL: '&e&lОстров | &7Успешно очищены значения генератора для всех островов.'\nGENERATOR_UPDATED: '&e&lОстров | &7Успешно обновлены значения генератора {0} на остров {1}.'\nGENERATOR_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены значения генератора {0} на остров {1}.'\nGENERATOR_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены значения генератора {0} для всех островов.'\nGLOBAL_COMMAND_EXECUTED: '&e&lОстров | &7Успешно выполнена команда для участников острова {0}!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lОстров | &7Успешно выполнена команда для участников острова {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lОстров | &7Сообщение успешно отправлено участникам острова {0}!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lОстров | &7Сообщение успешно отправлено участникам острова {0}!'\nGLOBAL_TITLE_SENT: '&e&lОстров | &7Успешно отправлен титул участникам острова {0}!'\nGLOBAL_TITLE_SENT_NAME: '&e&lОстров | &7Успешно отправлен титул участникам острова {0}!'\nGOT_BANNED: '&e&lОстров | &7Вы были ЗАБАНЕНЫ на острове {0}.'\nGOT_DEMOTED: '&e&lОстров | &7Вы были понижены до {0} на вашем острове.'\nGOT_EXPELLED: '&e&lОстров | &7&oВы были выгнаны с острова {0}.'\nGOT_INVITE: '&e&lОстров | &7{0} пригласил вас на свой остров.'\nGOT_INVITE_TOOLTIP: '&7Нажмите на сообщение, чтобы принять приглашение.'\nGOT_KICKED: '&e&lОстров | &7Вы были выгнаны с вашего острова {0}.'\nGOT_PROMOTED: '&e&lОстров | &7Вы были повышены до {0} на вашем острове.'\nGOT_REVOKED: '&e&lОстров | &7{0} отменил ваше приглашение на его остров.'\nGOT_UNBANNED: '&e&lОстров | &7Вы были СНЯТЫ с бана на острове {0}.'\nHIT_ISLAND_MEMBER: '&c&lОшибка | &7Вы не можете атаковать участников своего острова.'\nHIT_PLAYER_IN_ISLAND: '&c&lОшибка | &7Вы не можете атаковать игроков на острове.'\nIGNORED_ISLAND: '&e&lОстров | &7Остров {0} теперь игнорируется в списке лучших островов.'\nIGNORED_ISLAND_NAME: '&e&lОстров | &7Остров {0} теперь игнорируется в списке лучших островов.'\nINTERACT_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете взаимодействовать за пределами своей зоны защиты.'\nINVALID_AMOUNT: '&c&lОшибка | &7Недопустимая сумма {0}.'\nINVALID_BIOME: '&c&lОшибка | &7Недопустимый биом {0}.'\nINVALID_BLOCK: '&c&lОшибка | &7Недопустимое местоположение блока {0}.'\nINVALID_BORDER_COLOR: '&c&lОшибка | &7Недопустимый цвет границы {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lОшибка | &7Недопустимый эффект {0}.'\nINVALID_ENTITY: '&c&lОшибка | &7Недопустимое существо {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lОшибка | &7Недопустимый интервал {0}.'\nINVALID_ISLAND: '&c&lОшибка | &7У вас нет острова.'\nINVALID_ISLAND_LOCATION: '&c&lОшибка | &7В вашем местоположении нет острова.'\nINVALID_ISLAND_OTHER: '&c&lОшибка | &7У {0} нет острова.'\nINVALID_ISLAND_OTHER_NAME: '&c&lОшибка | &7Нет острова с именем {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lОшибка | &7Не удалось найти разрешение острова {0}.\n  &c&lОшибка | &7Разрешения острова: {1}\nINVALID_LEVEL: '&c&lОшибка | &7Недопустимый уровень {0}.'\nINVALID_LIMIT: '&c&lОшибка | &7Недопустимый лимит {0}.'\nINVALID_MATERIAL: '&c&lОшибка | &7Недопустимый материал {0}.'\nINVALID_MATERIAL_DATA: '&c&lОшибка | &7Недопустимые данные материала {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lОшибка | &7Недопустимая миссия {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lОшибка | &7Недопустимый модуль {0}.'\nINVALID_MULTIPLIER: '&c&lОшибка | &7Недопустимый множитель {0}.'\nINVALID_PAGE: '&c&lОшибка | &7Недопустимая страница {0}.'\nINVALID_PERCENTAGE: '&c&lОшибка | &7Процент должен быть от 0 до 100.'\nINVALID_PLAYER: '&c&lОшибка | &7Не удается найти игрока с именем {0}.'\nINVALID_RATE: |\n  &c&lОшибка | &7Не удалось найти рейтинг с именем {0}.\n  &c&lОшибка | &7Рейтинги острова: {1}\nINVALID_ROWS: '&c&lОшибка | &7Недопустимое количество строк: {0}.'\nINVALID_ROLE: |\n  &c&lОшибка | &7Не удалось найти роль острова {0}.\n  &c&lОшибка | &7Роли острова: {1}\nINVALID_SCHEMATIC: '&c&lОшибка | &7Не удалось найти схему с именем {0}.'\nINVALID_SETTINGS: |\n  &c&lОшибка | &7Не удалось найти настройки острова {0}.\n  &c&lОшибка | &7Настройки острова: {1}\nINVALID_SIZE: '&c&lОшибка | &7Недопустимый размер {0}.'\nINVALID_SLOT: '&c&lОшибка | &7Недопустимый слот {0}.'\nINVALID_TITLE: '&c&lОшибка | &7Недопустимый введенный титул.'\nINVALID_TOGGLE_MODE: '&c&lОшибка | &7Не удается переключить {0}.'\nINVALID_UPGRADE: |\n  &c&lОшибка | &7Не удалось найти улучшение с названием {0}.\n  &c&lОшибка | &7Улучшения: {1}\nINVALID_VISIT_LOCATION: '&c&lОшибка | &7У этого острова нет местоположения для посетителей.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oУ вас режим обхода, телепортирую вас на остров...'\nINVALID_WARP: '&c&lОшибка | &7Недопустимый варп {0}.'\nINVALID_WORLD: '&c&lОшибка | &7Недопустимый мир {0}.'\nINVITE_ANNOUNCEMENT: '&e&lОстров | &7{0} пригласил {1} на остров.'\nINVITE_BANNED_PLAYER: '&c&lОшибка | &7Этот игрок забанен на острове и не может быть приглашен.'\nINVITE_TO_FULL_ISLAND: '&c&lОшибка | &7Вы не можете пригласить больше участников на ваш остров.'\nISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.'\nISLAND_ALREADY_EXIST: '&c&lОшибка | &7Остров с таким именем уже существует.'\nISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.'\nISLAND_BANK_EMPTY: '&e&lБанк | &7Банк острова пуст.'\nISLAND_BANK_SHOW: '&e&lБанк | &7Ваш остров имеет ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lБанк | &7Остров {0} имеет ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lБанк | &7Остров {0} имеет ${1}.'\nISLAND_BEING_CALCULATED: '&c&lОшибка | &7Вы не можете взаимодействовать с блоками, пока остров пересчитывается!'\nISLAND_CLOSED: '&e&lОстров | &7Остров успешно закрыт для публики.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lОшибка | &7У вас уже есть запущенная задача создания острова.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lОстров | &7Обработка вашего запроса...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lПолёт | &7Полёт на острове автоматически &cвыключен&7.'\nISLAND_FLY_ENABLED: '&e&lПолёт | &7Полёт на острове автоматически &aвключён&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lОстров | &7&oВы были внутри острова, который был расформирован, поэтому вы были телепортированы обратно в спаун...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lОстров | &7&oВы были внутри острова, на котором был включен PVP, поэтому вы были телепортированы обратно в спаун...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Разработано Ome_R'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Список команд [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Используйте /is help {0} для следующей страницы.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lОстров | &7Лимит банка: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lОстров | &7Лимиты блоков:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lОстров | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lОстров | &7Лимит кооперации: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lОстров | &7Множитель урожая: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lОстров | &7Множитель дропов: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lОстров | &7Эффекты острова:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lОстров | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lОстров | &7Лимиты сущностей:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lОстров | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lОстров | &7Ставки генераторов ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lОстров | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lОстров | &7Лимиты ролей:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lОстров | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lОстров | &7Размер границ: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lОстров | &7Множитель спаунеров: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lОстров | &7Лимит команды: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lОстров | &7Улучшения:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lОстров | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lОстров | &7Лимит варпов: {0}'\nISLAND_INFO_BANK: '&e&lОстров | &7Банк: {0}'\nISLAND_INFO_BONUS: '&e&lОстров | &7Бонус стоимости: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lОстров | &7Бонус уровня: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lОстров | &7Время создания: {0}'\nISLAND_INFO_DISCORD: '&e&lОстров | &7Дискорд: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lОстров | &7Последнее обновление: {0} назад'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lОстров | &7Последнее обновление: &aВ настоящее время активно'\nISLAND_INFO_LEVEL: '&e&lОстров | &7Уровень: {0}'\nISLAND_INFO_LOCATION: '&e&lОстров | &7Дом: {0}'\nISLAND_INFO_NAME: '&e&lОстров | &7Имя: {0}'\nISLAND_INFO_OWNER: '&e&lОстров | &7Лидер: {0}'\nISLAND_INFO_PAYPAL: '&e&lОстров | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lОстров | &7 - {0}'\nISLAND_INFO_RATE: '&e&lОстров | &7Рейтинг: {0} &7({1}/5) - {2} общих рейтингов.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lОстров | &7{0}ы:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lОстров | &7Количество посетителей: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lОстров | &7Стоимость: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lОстров | &7Остров успешно открыт для публики.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lПредпросмотр | &7Вы отошли слишком далеко, и режим предпросмотра больше не активен.'\nISLAND_PREVIEW_CANCEL: '&e&lПредпросмотр | &7Вы отменили режим предпросмотра.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'ПОДТВЕРДИТЬ'\nISLAND_PREVIEW_CANCEL_TEXT: 'ОТМЕНА'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lПредпросмотр | &7Вы начали режим предпросмотра для схемы {0}.\n  &e&lПредпросмотр | &7Введите &a&lПОДТВЕРДИТЬ &7для создания нового острова или &c&lОТМЕНА &7для отмены режима предпросмотра.\n  &e&lПредпросмотр | &7Вы не можете покидать территорию острова, иначе режим предпросмотра будет отменён автоматически.\nISLAND_PROTECTED: '&c&lОшибка | &7Этот остров защищён.'\nISLAND_PROTECTED_OPPED: '&7&oВы можете обойти это ограничение, используя \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lОстров | &7Члены острова {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Оффлайн)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Онлайн)'\nISLAND_TEAM_STATUS_ROLES: '&e&lОстров | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Оффлайн)'\nISLAND_TOP_STATUS_ONLINE: '&a(Онлайн)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Частный]'\nISLAND_WAS_CLOSED: '&e&lОстров | &7&oОстров, в котором вы были, был закрыт, и вы были телепортированы обратно на спавн...'\nISLAND_WORTH_ERROR: '&c&lОшибка | &7Произошла неожиданная ошибка при расчете вашего острова. Свяжитесь с администрацией, если проблема сохраняется.'\nISLAND_WORTH_RESULT: '&e&lОстров | &7Стоимость вашего острова {0} [Уровень {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lОшибка | &7Задача на расчет времени вышла за пределы. Попробуйте позже...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к вашему острову.'\nJOIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к вашему острову.'\nJOIN_FULL_ISLAND: '&c&lОшибка | &7Этот остров достиг максимального количества разрешенных участников.'\nJOIN_WHILE_IN_ISLAND: '&c&lОшибка | &7Вы уже находитесь на острове.'\nJOINED_ISLAND: '&e&lОстров | &7Вы присоединились к острову {0}.'\nJOINED_ISLAND_NAME: '&e&lОстров | &7Вы присоединились к острову {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lОстров | &7Вы теперь являетесь соучастником острова {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lОстров | &7Вы теперь являетесь соучастником острова {0}.'\nKICK_ANNOUNCEMENT: '&e&lОстров | &7{0} был исключен из острова {1}.'\nKICK_ISLAND_LEADER: '&c&lОшибка | &7Вы не можете исключить лидера острова, используйте /is admin disband вместо этого.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете исключить только игроков с ролью ниже вашей.'\nLACK_CHANGE_PERMISSION: '&c&lОшибка | &7У вас нет разрешения на изменение этой роли.'\nLAST_ROLE_DEMOTE: '&c&lОшибка | &7Вы больше не можете понижать эту роль игрока.'\nLAST_ROLE_PROMOTE: '&c&lОшибка | &7Вы больше не можете повышать эту роль игрока.'\nLEAVE_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул остров.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lОшибка | &7Вы не можете покинуть свой остров, когда вы его владелец.\n  &c&lОшибка | &7Вы можете передать право собственности, используя /is transfer.\nLEFT_ISLAND: '&e&lОстров | &7Вы покинули свой остров.'\nLEFT_ISLAND_COOP: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.'\nLEFT_ISLAND_COOP_NAME: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lОшибка | &7Вы должны предоставить твердый материал.'\nMAXIMUM_LEVEL: '&c&lОшибка | &7Максимальный уровень для этого улучшения - {0}.'\nMESSAGE_SENT: '&e&lОстров | &7Сообщение успешно отправлено {0}!'\nMISSION_CANNOT_COMPLETE: '&c&lОшибка | &7Вы не можете завершить эту миссию еще.'\nMISSION_NO_AUTO_REWARD: '&e&lМиссия | &7У вас есть все необходимые материалы для завершения {0} - используйте /is missions, чтобы завершить!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lОшибка | &7Вы должны завершить {0}, прежде чем завершить эту миссию.'\nMISSION_STATUS_COMPLETE: '&e&lМиссия | &7Изменен статус миссии {0} на завершенный для {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lМиссия | &7Изменен статус всех миссий на завершенный для {0}.'\nMISSION_STATUS_RESET: '&e&lМиссия | &7Сброшен статус миссии {0} для {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lМиссия | &7Сброшен статус всех миссий для {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lМодуль | &7Этот модуль уже загружен.'\nMODULE_INFO: |\n  &e&lМодуль | &7{0} от {1}\n  &e&lМодуль | &7&m--------------------\n  &e&lМодуль | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lМодуль | &7Успешно загружен модуль {0}.'\nMODULE_LOADED_FAILURE: '&e&lМодуль | &7Не удалось загрузить модуль {0}. Проверьте консоль для получения дополнительной информации.'\nMODULE_UNLOADED_SUCCESS: '&e&lМодуль | &7Успешно выгружен модуль.'\nMODULES_LIST: '&fМодули ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lОстров | &7{0} изменил имя своего острова на {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lОшибка | &7Вы не можете использовать это имя.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lОшибка | &7Вы не можете использовать имена игроков в качестве имен островов.'\nNAME_TOO_LONG: '&c&lОшибка | &7Имена островов не могут превышать {0} символов.'\nNAME_TOO_SHORT: '&c&lОшибка | &7Имена островов не могут быть короче {0} символов.'\nNO_BAN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы забанить игроков.'\nNO_CLOSE_BYPASS: '&c&lОшибка | &7Этот остров не открыт для публики.'\nNO_CLOSE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы закрыть остров для публики.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы добавлять игроков как соучастников.'\nNO_DELETE_WARP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы удалять варпы.'\nNO_DEMOTE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы понижать игроков.'\nNO_DEPOSIT_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы вносить деньги в банк острова.'\nNO_DISBAND_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы распустить ваш остров.'\nNO_EXPEL_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы исключать игроков из вашего острова.'\nNO_INVITE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы приглашать игроков.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы получить доступ к сундуку острова.'\nNO_ISLAND_INVITE: '&c&lОшибка | &7Не удалось найти никаких приглашений от этого острова.'\nNO_ISLANDS_TO_PURGE: '&c&lОшибка | &7Не было островов для очистки.'\nNO_KICK_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы исключать игроков.'\nNO_MORE_DISBANDS: '&c&lОшибка | &7Вы не можете распустить больше островов.'\nNO_MORE_WARPS: '&c&lОшибка | &7Ваш остров не может иметь больше варпов.'\nNO_NAME_PERMISSION: '&c&lОшибка | &7Вы не можете изменить имя вашего острова.'\nNO_OPEN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы открыть остров для публики.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы получать информацию о разрешениях.'\nNO_PROMOTE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы повышать игроков.'\nNO_RANKUP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы повысить улучшения.'\nNO_RATINGS_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы проверять рейтинги.'\nNO_SET_BIOME_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить биом острова.'\nNO_SET_DISCORD_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить Discord острова.'\nNO_SET_HOME_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить место телепорта острова.'\nNO_SET_PAYPAL_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить PayPal адрес острова.'\nNO_SET_ROLE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить роли для игроков.'\nNO_SET_SETTINGS_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить настройки острова.'\nNO_SET_WARP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить варпы острова.'\nNO_TRANSFER_PERMISSION: '&c&lОшибка | &7Вы должны быть лидером острова, чтобы передать руководство.'\nNO_UNCOOP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы удалить игроков из кооперации.'\nNO_UPGRADE_PERMISSION: '&c&lОшибка | &7У вас нет разрешения на повышение до другого уровня.'\nNO_WITHDRAW_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы снять деньги из банка острова.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lОшибка | &7У вас недостаточно денег для внесения {0} долларов в банк вашего острова.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lОшибка | &7У вас недостаточно денег.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lОшибка | &7У вас недостаточно денег для использования варпов острова.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oВам слишком лень взаимодействовать с меню, не так ли?'\nPANEL_TOGGLE_OFF: |-\n  &e&lПанель | &7Панель острова отключена &cOFF&7.\n  &e&lПанель | &7Использование /is телепортирует вас на остров.\nPANEL_TOGGLE_ON: |-\n  &e&lПанель | &7Панель острова включена &aON&7.\n  &e&lПанель | &7Использование /is откроет панель для вас.\nPERMISSION_CHANGED: '&e&lОстров | &7Успешно обновлено разрешение {0} острова {1}.'\nPERMISSION_CHANGED_NAME: '&e&lОстров | &7Успешно обновлено разрешение {0} острова {1}.'\nPERMISSION_CHANGED_ALL: '&e&lОстров | &7Успешно обновлено разрешение {0} для всех островов.'\nPERSISTENT_DATA_EMPTY: '&c&lОшибка | &7Не найдено данных для вашего запроса.'\nPERSISTENT_DATA_MODIFY: '&e&lДанные | &7Успешно установлены данные для {0} с {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lДанные | &7Данные для {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lДанные | &7Успешно удалены данные для {0} из пути {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lОстров | &7Успешно сброшены все разрешения для {0} на значения по умолчанию!'\nPERMISSIONS_RESET_ROLES: '&e&lОстров | &7Успешно сброшены все разрешения острова на значения по умолчанию!'\nPLACEHOLDER_NO: 'Нет'\nPLACEHOLDER_YES: 'Да'\nPLAYER_ALREADY_BANNED: '&c&lОшибка | &7Этот игрок уже забанен.'\nPLAYER_ALREADY_COOP: '&c&lОшибка | &7Этот игрок уже в кооперации.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lОшибка | &7Этот игрок уже на острове.'\nPLAYER_ALREADY_IN_ROLE: '&c&lОшибка | &7{0} уже является {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lОшибка | &7Этот пользователь не может быть исключен с острова.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к серверу.'\nPLAYER_NOT_BANNED: '&c&lОшибка | &7Этот игрок не забанен.'\nPLAYER_NOT_COOP: '&c&lОшибка | &7Этот игрок не в кооперации.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lОшибка | &7Этот игрок не на вашем острове.'\nPLAYER_NOT_ONLINE: '&c&lОшибка | &7Этот игрок не онлайн!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул сервер.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете повышать только игроков с более низкой ролью острова.'\nPROMOTED_MEMBER: '&e&lОстров | &7Вы повысили {0} до {1} на его острове.'\nPURGE_CLEAR: '&e&lОстров | &7Успешно очищены все запланированные для удаления острова.'\nPURGED_ISLANDS: |-\n  &e&lОстров | &7{0} островов будет удалено при перезагрузке сервера.\n  &e&lОстров | &7Вы можете отменить это в любое время, используя /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для острова {1}.'\nRANKUP_SUCCESS_ALL: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для всех островов.'\nRANKUP_SUCCESS_NAME: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lОстров | &7{0} оценил ваш остров на {1} из 5.'\nRATE_CHANGE_OTHER: '&e&lОстров | &7Вы изменили рейтинг {0} на {1}.'\nRATE_OWN_ISLAND: '&c&lОшибка | &7Вы не можете оценить свой собственный остров.'\nRATE_REMOVE_ALL: '&e&lОстров | &7Успешно удалены все оценки для {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lОстров | &7Успешно удалены все оценки всех островов.'\nRATE_SUCCESS: '&e&lОстров | &7Вы оценили этот остров на {0} звезд!'\nREACHED_BLOCK_LIMIT: '&e&lУлучшения | &7Вы достигли предела для {0} блока острова.'\nREACHED_ENTITY_LIMIT: '&e&lУлучшения | &7Вы достигли предела для сущности {0} на острове.'\nRECALC_ALREADY_RUNNING: '&c&lОшибка | &7Ваш остров уже пересчитывается.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lОшибка | &7Этот остров уже пересчитывается.'\nRECALC_ALL_ISLANDS: '&e&lОстров | &7Пересчет всех островов...'\nRECALC_ALL_ISLANDS_DONE: '&e&lОстров | &7Успешно завершен пересчет всех островов.'\nRECALC_PROCCESS_REQUEST: '&e&lОстров | &7Обработка вашего запроса...'\nRELOAD_COMPLETED: '&e&lОстров | &7Перезагрузка завершена!'\nRELOAD_PROCCESS_REQUEST: '&e&lОстров | &7Начинается перезагрузка конфигураций...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lОстров | &7{0} отозвал приглашение {1} на остров.'\nRESET_WORLD_SUCCEED: '&e&lОстров | &7Успешно сброшен мир {0} для острова {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lОстров | &7Успешно сброшен мир {0} для всех островов.'\nRESET_WORLD_SUCCEED_NAME: '&e&lОстров | &7Успешно сброшен мир {0} для {1}.'\nSAME_NAME_CHANGE: '&c&lОшибка | &7Вы должны ввести другое имя, отличное от текущего имени острова.'\nSCHEMATIC_LEFT_SELECT: '&e&lСхемы | &7Выбрана позиция #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lОшибка | &7Вы не выбрали две позиции.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lСхемы | &7Обработка вашего запроса...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lСхемы | &7Вы выбрали две позиции. Выполните /is admin schematic <name>, чтобы создать новую схему.\n  &e&lСхемы | &7Убедитесь, что вы находитесь на месте телепортации при выполнении команды.\nSCHEMATIC_RIGHT_SELECT: '&e&lСхемы | &7Выбрана позиция #1 ({0})'\nSCHEMATIC_SAVED: '&e&lСхемы | &7Схема успешно сохранена!'\nSELF_ROLE_CHANGE: '&c&lОшибка | &7Вы не можете изменить свою роль.'\nSET_UPGRADE_LEVEL: '&e&lУлучшения | &7Успешно обновлен уровень {0} для острова {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень {0} для {1}.'\nSET_WARP: '&e&lОстров | &7Успешно создан новый варп на {0}.'\nSET_WARP_OUTSIDE: '&c&lОшибка | &7Вы не можете устанавливать варпы за пределами вашего острова.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.'\nSETTINGS_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.'\nSETTINGS_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены настройки {0} для всех островов.'\nSIZE_BIGGER_MAX: '&c&lОшибка | &7Вы не можете установить размер больше максимального размера острова.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lСпавн | &7Успешно телепортирован {0} на спавн.'\nSPAWN_SET_SUCCESS: '&e&lСпавн | &7Успешно обновлено место спавна на {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Шпион] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для острова {0}.'\nSYNC_UPGRADES_ALL: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для всех островов.'\nSYNC_UPGRADES_NAME: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не находитесь на своем острове.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете телепортироваться за пределы вашей защитной зоны.'\nTELEPORT_WARMUP: '&7&oВас телепортируют через {0}... Не двигайтесь!'\nTELEPORT_WARMUP_CANCEL: '&7&oВы двинулись, поэтому телепортация отменена.'\nTITLE_SENT: '&e&lОстров | &7Успешно отправлен титул {0}!'\nTELEPORTED_FAILED: '&e&lОстров | &7Похоже, что на этом острове нет безопасных блоков. Пожалуйста, свяжитесь с администратором.'\nTELEPORTED_SUCCESS: '&e&lОстров | &7Вы были телепортированы на свой остров.'\nTELEPORTED_TO_WARP: '&e&lОстров | &7Успешно телепортирован на этот варп острова.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lОстров | &7Игрок {0} телепортировался на варп острова {1}.'\nTOGGLED_BYPASS_OFF: '&e&lОбход | &7Режим обхода отключен &cOFF&7.'\nTOGGLED_BYPASS_ON: '&e&lОбход | &7Режим обхода включен &aON&7.'\nTOGGLED_FLY_OFF: '&e&lПолет | &7Режим полета на острове отключен &cOFF&7.'\nTOGGLED_FLY_ON: '&e&lПолет | &7Режим полета на острове включен &aON&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lСхемы | &7Режим схем отключен &cOFF&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lСхемы | &7Режим схем включен &aON&7.\n  &e&lСхемы | &7Выберите область с помощью золотого топора.\nTOGGLED_SPY_OFF: '&e&lШпион | &7Шпионский чат отключен &cOFF&7.'\nTOGGLED_SPY_ON: '&e&lШпион | &7Шпионский чат включен &aON&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lСклад | &7Режим укладки блоков отключен &cOFF&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lСклад | &7Режим укладки блоков включен &aON&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lЧат | &7Командный чат отключен &cOFF&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lЧат | &7Командный чат включен &aON&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lГраница | &7Границы мира отключены &cOFF&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lГраница | &7Границы мира включены &aON&7.'\nTRANSFER_ADMIN: '&e&lОстров | &7Вы передали руководство {0} игроку {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lОшибка | &7{0} уже является лидером своего острова.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lОшибка | &7Эти игроки не находятся на одних и тех же островах.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lОшибка | &7Этот игрок не является лидером ни одного острова.'\nTRANSFER_ALREADY_LEADER: '&c&lОшибка | &7Вы уже являетесь лидером этого острова.'\nTRANSFER_BROADCAST: '&e&lОстров | &7Руководство острова было передано {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lОстров | &7{0} был разморожен на острове {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lОстров | &7{0} убрал {1} из состава кооперативов.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lОстров | &7Игроков в кооперации нет, поэтому вы были автоматически исключены.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул игру и больше не является членом кооперации.'\nUNIGNORED_ISLAND: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.'\nUNIGNORED_ISLAND_NAME: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!'\nUNSAFE_WARP: '&e&lОстров | &7&oПохоже, этот варп небезопасен. Попробуйте другой варп.'\nUPDATED_PERMISSION: '&e&lОстров | &7Обновлены права для {0}.'\nUPDATED_SETTINGS: '&e&lОстров | &7Обновлены настройки острова {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете улучшить только через {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lОшибка | &7Вы не можете использовать эту команду на других островах.'\nWARP_ALREADY_EXIST: '&c&lОшибка | &7Варп с таким именем уже существует.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lВарпы | &7Введите новую лор (введите \"-cancel\" для отмены):\n  &e&lВарпы | &7Вы можете разделять строки, используя \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lВарпы | &7Введите имя (введите \"-cancel\" для отмены):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lВарпы | &7Введите новый тип материала (введите \"-cancel\" для отмены):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lВарпы | &7Успешно обновлен значок категории.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lОшибка | &7Имена категорий варпов не могут быть пустыми.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lОшибка | Имена категорий варпов не могут превышать 255 символов.'\nWARP_CATEGORY_SLOT: '&e&lВарпы | &7Введите новый слот (введите \"-cancel\" для отмены):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lОшибка | &7Этот слот уже занят другой категорией.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lВарпы | &7Успешно изменен слот категории на {0}.'\nWARP_CATEGORY_RENAME: '&e&lВарпы | &7Введите новое имя (введите \"-cancel\" для отмены):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lОшибка | &7Это имя уже занято другой категорией.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lВарпы | &7Успешно переименована категория в {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lВарпы | &7Введите новую лор (введите \"-cancel\" для отмены):\n  &e&lВарпы | &7Вы можете разделять строки, используя \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lВарпы | &7Введите имя (введите \"-cancel\" для отмены):'\nWARP_ICON_NEW_TYPE: '&e&lВарпы | &7Введите новый тип материала (введите \"-cancel\" для отмены):'\nWARP_ICON_UPDATED: '&e&lВарпы | &7Успешно обновлен значок варпа.'\nWARP_ILLEGAL_NAME: '&c&lОшибка | &7Имена варпов не могут быть пустыми.'\nWARP_LOCATION_UPDATE: '&e&lВарпы | &7Успешно обновлено местоположение варпа на ваше текущее местоположение.'\nWARP_NAME_TOO_LONG: '&c&lОшибка | Имена варпов не могут превышать 255 символов.'\nWARP_PUBLIC_UPDATE: '&e&lВарпы | &7Успешно открыт варп для публики.'\nWARP_PRIVATE_UPDATE: '&e&lВарпы | &7Успешно закрыт варп для публики.'\nWARP_RENAME: '&e&lВарпы | &7Введите новое имя (введите \"-cancel\" для отмены):'\nWARP_RENAME_ALREADY_EXIST: '&c&lОшибка | &7Это имя уже занято другим варпом.'\nWARP_RENAME_SUCCESS: '&e&lВарпы | &7Успешно переименован варп в {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lБанк | &7В банке острова только {0} долларов.\n  &e&lБанк | &7&oСнимаю все деньги...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lБанк | &7{0} снял ${1} из банка острова!'\nWITHDRAW_ERROR: '&c&lОшибка | &7{0}.'\nWITHDRAWN_MONEY: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lМиры | &7Мир {0} еще не разблокирован!'\n"
  },
  {
    "path": "src/main/resources/lang/tr-TR.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##               Translated by losadev              ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# You can find a tutorial about configuring messages here:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lAda | &7Oyuncu {0} başarıyla {1}''in adasına eklendi.'\nADMIN_ADD_PLAYER_NAME: '&e&lAda | &7Oyuncu {0} başarıyla {1} adasına eklendi.'\nADMIN_DEPOSIT_MONEY: '&e&lBanka | &7{1}''in ada bankasına ${0} yatırdın.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasına ${0} yatırdın.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Yönetici Komutları Listesi [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is admin {0} kullan.'\nALREADY_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.'\nALREADY_IN_ISLAND_OTHER: '&c&lHata | &7Bu oyuncu zaten adanın bir üyesi.'\nBAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAKLANDI.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip\n  oyuncuları yasaklayabilirsin.'\nBANK_DEPOSIT_CUSTOM: '&e&lBanka | &7Yatırmak istediğin miktarı yaz:'\nBANK_DEPOSIT_COMPLETED: Para Yatırma Tamamlandı\nBANK_LIMIT_EXCEED: '&c&lHata | &7Banka limitini aştın.'\nBANK_WITHDRAW_CUSTOM: '&e&lBanka | &7Çekmek istediğin miktarı yaz:'\nBANK_WITHDRAW_COMPLETED: Para Çekme Tamamlandı\nBANNED_FROM_ISLAND: '&c&lHata | &7Bu adadan yasaklandın.'\nBLOCK_COUNT_CHECK: '&e&lAda | &7Bu adada x{0} {1} bulunuyor.'\nBLOCK_COUNTS_CHECK: |\n  &e&lAda | &7Bu adada aşağıdaki bloklar bulunuyor:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lAda | &7Bu adada takip edilen blok bulunmuyor.'\nBLOCK_COUNTS_CHECK_MATERIAL: x{0} {1}\nBLOCK_LEVEL: '&e&lSeviye | &7{0} bloğunun seviyesi {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lSeviye | &7{0} bloğu değersiz.'\nBLOCK_VALUE: '&e&lDeğer | &7{0} bloğunun değeri {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lDeğer | &7{0} bloğu değersiz.'\nBONUS_SYNC_ALL: '&e&lAda | &7Ada bonusu tüm adalarla başarıyla senkronize edildi.'\nBONUS_SYNC_NAME: '&e&lAda | &7Ada bonusu {0} ile başarıyla senkronize edildi.'\nBONUS_SYNC: '&e&lAda | &7Ada bonusu {0}''ın adasıyla başarıyla senkronize edildi.'\nBORDER_PLAYER_COLOR_NAME_BLUE: Mavi\nBORDER_PLAYER_COLOR_NAME_RED: Kırmızı\nBORDER_PLAYER_COLOR_NAME_GREEN: Yeşil\nBORDER_PLAYER_COLOR_UPDATED: '&e&lSınır | &7Kişisel sınır rengin başarıyla {0} olarak\n  değiştirildi.'\nBUILD_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında inşa edemezsin.'\nCANNOT_SET_ROLE: '&c&lHata | &7Oyuncunun rolünü {0} olarak ayarlayamazsın.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne\n  sahip rollerin izinlerini değiştirebilirsin.'\nCHANGED_BANK_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının banka limiti başarıyla\n  güncellendi.'\nCHANGED_BANK_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların banka limiti başarıyla\n  güncellendi.'\nCHANGED_BANK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının banka limiti başarıyla\n  güncellendi.'\nCHANGED_BIOME: '&e&lAda | &7Biyom başarıyla {0} olarak değiştirildi. Değişiklikleri\n  görmek için sunucuya tekrar bağlanman gerekebilir.'\nCHANGED_BIOME_ALL: '&e&lAda | &7Tüm adalar için biyom başarıyla {0} olarak değiştirildi.'\nCHANGED_BIOME_NAME: '&e&lAda | &7{1} adası için biyom başarıyla {0} olarak değiştirildi.'\nCHANGED_BIOME_OTHER: '&e&lAda | &7{1}''in adası için biyom başarıyla {0} olarak değiştirildi.'\nCHANGED_BLOCK_AMOUNT: '&e&lBloklar | &7{0} konumundaki blok miktarı başarıyla {1}\n  olarak değiştirildi.'\nCHANGED_BLOCK_LIMIT: '&e&lYükseltmeler | &7{0} Bloğunun {1}''in adası için limiti\n  başarıyla güncellendi.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lYükseltmeler | &7{0} Bloğunun tüm adalar için limiti\n  başarıyla güncellendi.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} Bloğunun {1} adası için limiti\n  başarıyla güncellendi.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lSandık | &7{2}''in adası için #{0} sayfasının satırları başarıyla\n  {1} olarak güncellendi.'\nCHANGED_CHEST_SIZE_ALL: '&e&lSandık | &7Tüm adalar için #{0} sayfasının satırları\n  başarıyla {1} olarak güncellendi.'\nCHANGED_CHEST_SIZE_NAME: '&e&lSandık | &7{2} adası için #{0} sayfasının satırları\n  başarıyla {1} olarak güncellendi.'\nCHANGED_COOP_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının co-op oyuncu limiti başarıyla\n  güncellendi.'\nCHANGED_COOP_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların co-op oyuncu limiti başarıyla\n  güncellendi.'\nCHANGED_COOP_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının co-op oyuncu limiti başarıyla\n  güncellendi.'\nCHANGED_CROP_GROWTH: '&e&lYükseltmeler | &7{0}''ın adasının bitki büyüme çarpanı başarıyla\n  güncellendi.'\nCHANGED_CROP_GROWTH_ALL: '&e&lYükseltmeler | &7Tüm adaların bitki büyüme çarpanı başarıyla\n  güncellendi.'\nCHANGED_CROP_GROWTH_NAME: '&e&lYükseltmeler | &7{0} adasının bitki büyüme çarpanı\n  başarıyla güncellendi.'\nCHANGED_DISCORD: '&e&lAda | &7Ada discordu başarıyla {0} olarak değiştirildi.'\nCHANGED_ENTITY_LIMIT: '&e&lYükseltmeler | &7{0} varlıklarının {1}''in adası için limiti\n  başarıyla güncellendi.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lYükseltmeler | &7{0} varlıklarının tüm adalar için\n  limiti başarıyla güncellendi.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lYükseltmeler | &7{0} varlıklarının {1} adası için\n  limiti başarıyla güncellendi.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lYükseltmeler | &7{0} ada etkisinin {1}''in adası\n  için seviyesi başarıyla güncellendi.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lYükseltmeler | &7{0} ada etkisinin tüm adalar\n  için seviyesi başarıyla güncellendi.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lYükseltmeler | &7{0} ada etkisinin {1} adası\n  için seviyesi başarıyla güncellendi.'\nCHANGED_ISLAND_SIZE: '&e&lYükseltmeler | &7{0}''ın adasının boyutu başarıyla güncellendi.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lYükseltmeler | &7Tüm adaların boyutu başarıyla güncellendi.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lYükseltmeler | &7{0} adasının boyutu başarıyla güncellendi.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oOyuncular adalarının dışında inşa edebildiği\n  için ada boyutunun bir etkisi yoktur. Bu özelliği yapılandırma dosyasından kapatırsan\n  ada boyutu tekrar etkili olacaktır.'\nCHANGED_LANGUAGE: '&e&lDil | &7Kişisel dilin başarıyla İngilizce olarak değiştirildi.'\nCHANGED_MOB_DROPS: '&e&lYükseltmeler | &7{0}''ın adasının mob düşürme çarpanı başarıyla\n  güncellendi.'\nCHANGED_MOB_DROPS_ALL: '&e&lYükseltmeler | &7Tüm adaların mob düşürme çarpanı başarıyla\n  güncellendi.'\nCHANGED_MOB_DROPS_NAME: '&e&lYükseltmeler | &7{0} adasının mob düşürme çarpanı başarıyla\n  güncellendi.'\nCHANGED_NAME: '&e&lAda | &7Adanın adını {0}&7 olarak değiştirdin.'\nCHANGED_NAME_OTHER: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdin.'\nCHANGED_NAME_OTHER_NAME: '&e&lAda | &7{0}&7 adının adını {1}&7 olarak değiştirdin.'\nCHANGED_PAYPAL: '&e&lAda | &7Ada paypalı başarıyla {0} olarak değiştirildi.'\nCHANGED_ROLE_LIMIT: '&e&lYükseltmeler | &7{0} rolünün {1}''in adası için limiti başarıyla\n  güncellendi.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lYükseltmeler | &7{0} rolünün tüm adalar için limiti başarıyla\n  güncellendi.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lYükseltmeler | &7{0} rolünün {1} adası için limiti başarıyla\n  güncellendi.'\nCHANGED_SPAWNER_RATES: '&e&lYükseltmeler | &7{0}''ın adasının spawner oranları çarpanı\n  başarıyla güncellendi.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lYükseltmeler | &7Tüm adaların spawner oranları çarpanı\n  başarıyla güncellendi.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lYükseltmeler | &7{0} adasının spawner oranları çarpanı\n  başarıyla güncellendi.'\nCHANGED_TEAM_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının takım limiti başarıyla\n  güncellendi.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların takım limiti başarıyla\n  güncellendi.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının takım limiti başarıyla\n  güncellendi.'\nCHANGED_TELEPORT_LOCATION: '&e&lAda | &7Işınlanma konumu başarıyla güncellendi.'\nCHANGED_WARPS_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının ışınlanma limiti başarıyla\n  güncellendi.'\nCHANGED_WARPS_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların ışınlanma limiti başarıyla\n  güncellendi.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının ışınlanma limiti başarıyla\n  güncellendi.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: miktar\nCOMMAND_ARGUMENT_BIOME: biyom\nCOMMAND_ARGUMENT_BORDER_COLOR: sınır-rengi\nCOMMAND_ARGUMENT_COMMAND: komut...\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: discord...\nCOMMAND_ARGUMENT_EFFECT: iksir-efekti\nCOMMAND_ARGUMENT_EMAIL: e-posta\nCOMMAND_ARGUMENT_ENTITY: varlık\nCOMMAND_ARGUMENT_ISLAND_NAME: ada-adı\nCOMMAND_ARGUMENT_ISLAND_ROLE: ada-rolü\nCOMMAND_ARGUMENT_LEADER: lider\nCOMMAND_ARGUMENT_LEVEL: seviye\nCOMMAND_ARGUMENT_LIMIT: limit\nCOMMAND_ARGUMENT_MATERIAL: materyal\nCOMMAND_ARGUMENT_MENU: menü-adı\nCOMMAND_ARGUMENT_MESSAGE: mesaj...\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: görev-adı\nCOMMAND_ARGUMENT_MODULE_NAME: modül-adı\nCOMMAND_ARGUMENT_MULTIPLIER: çarpan\nCOMMAND_ARGUMENT_NAME: isim\nCOMMAND_ARGUMENT_NEW_LEADER: yeni-lider\nCOMMAND_ARGUMENT_PAGE: sayfa\nCOMMAND_ARGUMENT_PATH: yol\nCOMMAND_ARGUMENT_PERMISSION: izin\nCOMMAND_ARGUMENT_PLAYER_NAME: oyuncu-adı\nCOMMAND_ARGUMENT_PRIVATE: özel\nCOMMAND_ARGUMENT_RATING: değerlendirme\nCOMMAND_ARGUMENT_ROWS: satırlar\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: şematik-adı\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: havayı-kaydet\nCOMMAND_ARGUMENT_SETTINGS: ayarlar\nCOMMAND_ARGUMENT_SIZE: boyut\nCOMMAND_ARGUMENT_TIME: süre\nCOMMAND_ARGUMENT_TITLE_DURATION: süre\nCOMMAND_ARGUMENT_TITLE_FADE_IN: giriş-solması\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: çıkış-solması\nCOMMAND_ARGUMENT_UPGRADE_NAME: yükseltme-adı\nCOMMAND_ARGUMENT_VALUE: değer\nCOMMAND_ARGUMENT_WARP_NAME: ışınlanma-adı\nCOMMAND_ARGUMENT_WARP_CATEGORY: ışınlanma-kategorisi\nCOMMAND_ARGUMENT_WORLD: dünya\nCOMMAND_COOLDOWN_FORMAT: '&c&lHata | &7Komutu sadece {0} içinde kullanabilirsin.'\nCOMMAND_DESCRIPTION_ACCEPT: Bir oyuncudan gelen daveti kabul et.\nCOMMAND_DESCRIPTION_ADMIN: Yönetici komutlarını kullan.\nCOMMAND_DESCRIPTION_ADMIN_ADD: Bir adaya kullanıcı ekle.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limitini\n  artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Bir oyuncuya bonus ekle.\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu\n  limitini artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme\n  çarpanını artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Başka bir oyuncunun adası için bir ada efekti\n  ekle.\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık\n  limitini artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Çakıl taşı jeneratörü için bir materyalin\n  yüzdesini ekle.\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme\n  çarpanını artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Başka bir oyuncunun ada boyutunu genişlet.\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Başka bir oyuncunun adası için spawner\n  oranları çarpanını artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini\n  artır.\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Bir adanın ışınlanma limitini artır.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: Bir oyuncuya bonus ver.\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: Bypass modunu aç/kapat.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: Başka bir adanın ada sandığını aç.\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Belirli bir ada için jeneratör oranlarını\n  temizle.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: Bir adayı halka kapat.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: Tüm adaların üyeleri için bir komut çalıştır.\nCOMMAND_DESCRIPTION_ADMIN_COUNT: Belirli bir adadaki blok sayısını kontrol et.\nCOMMAND_DESCRIPTION_ADMIN_DATA: Oyuncuların veya adaların kalıcı verileriyle etkileşime\n  geç.\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: Hata ayıklama çıktılarını aç/kapat.\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: Bir ada için bir ışınlanma noktasını sil.\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe düşür.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: Başka bir oyuncunun ada bankasına para yatır.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: Başka bir oyuncunun adasını kalıcı olarak dağıt.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Bir oyuncuya ada dağıtma hakkı ver.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: En iyi adalardan bir adayı yoksay.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: Davet olmadan bir adaya katıl.\nCOMMAND_DESCRIPTION_ADMIN_KICK: Bir oyuncuyu adasından at.\nCOMMAND_DESCRIPTION_ADMIN_MODULES: Eklentinin modüllerini yönet.\nCOMMAND_DESCRIPTION_ADMIN_MISSION: Bir oyuncu için bir görevin durumunu değiştir.\nCOMMAND_DESCRIPTION_ADMIN_MSG: Bir oyuncuya ön ek olmadan mesaj gönder.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: Tüm ada üyelerine ön ek olmadan mesaj gönder.\nCOMMAND_DESCRIPTION_ADMIN_NAME: Bir adanın adını değiştir.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: Bir adayı halka aç.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Bir oyuncu için özel bir menü aç.\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe\n  yükselt.\nCOMMAND_DESCRIPTION_ADMIN_PURGE: Adaları temizle.\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: Bir ada için bir yükseltmeyi seviye atlat.\nCOMMAND_DESCRIPTION_ADMIN_RECALC: Bir adanın değerini yeniden hesapla.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: Eklentinin tüm yapılandırmalarını ve görevlerini\n  yeniden yükle.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri\n  kaldır.\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla.\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: Bir adanın biyomunu ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Belirli bir konumdaki blok miktarını ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limiti\n  belirle.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Başka bir oyuncunun adası için sandık satırlarını\n  ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu\n  limitini ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme\n  çarpanını ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Bir oyuncunun ada dağıtma miktarını ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Başka bir oyuncunun adasının ada efekt seviyesini\n  ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık\n  limitini ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: Bir adayı başkasına devret.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme\n  çarpanını ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Tüm adalar için bir izne gerekli rolü ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: Başka bir oyuncunun değerlendirmesini ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: Başka bir oyuncunun adası için rol limitini\n  ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Belirli bir ada için ayarları aç/kapat.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Çakıl taşı jeneratörü için bir materyalin\n  yüzdesini değiştir.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: Başka bir oyuncunun ada boyutunu değiştir.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Sunucunun doğuş konumunu ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Başka bir oyuncunun adası için spawner\n  oranları çarpanını ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini\n  ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Başka bir oyuncunun adası için bir yükseltmenin\n  seviyesini ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Bir adanın ışınlanma limitini ayarla.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: Eklenti ayarları düzenleyicisini aç.\nCOMMAND_DESCRIPTION_ADMIN_SHOW: Bir ada hakkında bilgi al.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Doğuş konumuna ışınlan.\nCOMMAND_DESCRIPTION_ADMIN_SPY: Sohbet casusluk modunu aç/kapat.\nCOMMAND_DESCRIPTION_ADMIN_STATS: Eklenti hakkında istatistikleri göster.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: Bir adanın bonusunu oluşturulan dünyalarla senkronize\n  et.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Bir ada için yükseltme değerlerini senkronize\n  et.\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: Diğer adalara ışınlan.\nCOMMAND_DESCRIPTION_ADMIN_TITLE: Bir oyuncuya başlık gönder.\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: Tüm ada üyelerine başlık gönder.\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: En iyi adalardan bir adayı yoksaymayı bırak.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Bir ada için bir dünyanın kilidini aç.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: Başka bir oyuncunun ada bankasından para çek.\nCOMMAND_DESCRIPTION_BALANCE: Bir adanın bankasındaki para miktarını kontrol et.\nCOMMAND_DESCRIPTION_BAN: Adandan bir oyuncuyu yasakla.\nCOMMAND_DESCRIPTION_BANK: Adanın bankasını aç.\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: Adanın biyomunu değiştir.\nCOMMAND_DESCRIPTION_BORDER: Adaların sınır rengini değiştir.\nCOMMAND_DESCRIPTION_CHEST: Adanın sandığını aç.\nCOMMAND_DESCRIPTION_CLOSE: Adanı halka kapat.\nCOMMAND_DESCRIPTION_COOP: Adana bir oyuncuyu co-op olarak ekle.\nCOMMAND_DESCRIPTION_COOPS: co-oplar menüsünü aç.\nCOMMAND_DESCRIPTION_COUNTS: Adandaki blok sayılarını gör.\nCOMMAND_DESCRIPTION_CREATE: Yeni bir ada oluştur.\nCOMMAND_DESCRIPTION_DEL_WARP: Bir ada ışınlanmasını sil.\nCOMMAND_DESCRIPTION_DEMOTE: Adandaki bir üyeyi rütbe düşür.\nCOMMAND_DESCRIPTION_DEPOSIT: Kişisel hesabından adanın bankasına para yatır.\nCOMMAND_DESCRIPTION_DISBAND: Adanı kalıcı olarak dağıt.\nCOMMAND_DESCRIPTION_EXPEL: Adandan bir ziyaretçiyi kov.\nCOMMAND_DESCRIPTION_FLY: Ada uçuşunu aç/kapat.\nCOMMAND_DESCRIPTION_HELP: Tüm komutların listesi.\nCOMMAND_DESCRIPTION_INVITE: Adana bir oyuncuyu davet et.\nCOMMAND_DESCRIPTION_KICK: Adandan bir oyuncuyu at.\nCOMMAND_DESCRIPTION_LANG: Kişisel dilini değiştir.\nCOMMAND_DESCRIPTION_LEAVE: Adandan ayrıl.\nCOMMAND_DESCRIPTION_MEMBERS: Üyeler menüsünü aç.\nCOMMAND_DESCRIPTION_MISSION: Bir görevi tamamla.\nCOMMAND_DESCRIPTION_MISSIONS: Görevler menüsünü aç.\nCOMMAND_DESCRIPTION_NAME: Adanın adını değiştir.\nCOMMAND_DESCRIPTION_OPEN: Adanı halka aç.\nCOMMAND_DESCRIPTION_PANEL: Ada panelini aç.\nCOMMAND_DESCRIPTION_PARDON: Adandan bir oyuncunun yasağını kaldır.\nCOMMAND_DESCRIPTION_PERMISSIONS: Bir ada rolü için tüm izinleri al.\nCOMMAND_DESCRIPTION_PROMOTE: Adandaki bir üyeyi rütbe yükselt.\nCOMMAND_DESCRIPTION_RANKUP: Bir yükseltmeyi seviye atlat.\nCOMMAND_DESCRIPTION_RATE: Bir adayı değerlendir.\nCOMMAND_DESCRIPTION_RATINGS: Tüm ada değerlendirmelerini göster.\nCOMMAND_DESCRIPTION_SETTINGS: Ayarlar menüsünü aç.\nCOMMAND_DESCRIPTION_RECALC: Ada değerini yeniden hesapla.\nCOMMAND_DESCRIPTION_SET_DISCORD: Ada ödemeleri için adanın discordunu ayarla.\nCOMMAND_DESCRIPTION_SET_PAYPAL: Ada ödemeleri için adanın paypal e-postasını ayarla.\nCOMMAND_DESCRIPTION_SET_ROLE: Adandaki bir oyuncunun rolünü değiştir.\nCOMMAND_DESCRIPTION_SET_TELEPORT: Adanın ışınlanma konumunu değiştir.\nCOMMAND_DESCRIPTION_SET_WARP: Yeni bir ada ışınlanması oluştur.\nCOMMAND_DESCRIPTION_SHOW: Bir ada hakkında bilgi al.\nCOMMAND_DESCRIPTION_TEAM: Ada üyelerinin durumu hakkında bilgi al.\nCOMMAND_DESCRIPTION_TEAM_CHAT: Takım sohbet modunu aç/kapat.\nCOMMAND_DESCRIPTION_TELEPORT: Adana ışınlan.\nCOMMAND_DESCRIPTION_TOGGLE: Ada sınırlarını ve istiflenmiş blok yerleşimlerini aç/kapat.\nCOMMAND_DESCRIPTION_TOP: En iyi adalar panelini aç.\nCOMMAND_DESCRIPTION_TRANSFER: Adanın liderliğini devret.\nCOMMAND_DESCRIPTION_UNCOOP: Adandan bir oyuncuyu co-op üyeliğinden çıkar.\nCOMMAND_DESCRIPTION_UPGRADE: Yükseltmeler panelini aç.\nCOMMAND_DESCRIPTION_VALUE: Bir bloğun değerini al.\nCOMMAND_DESCRIPTION_VALUES: Değerler menüsünü aç.\nCOMMAND_DESCRIPTION_VISIT: Bir adanın ziyaretçi konumuna ışınlan.\nCOMMAND_DESCRIPTION_VISITORS: Ziyaretçiler menüsünü aç.\nCOMMAND_DESCRIPTION_WARP: Bir ada ışınlanmasına ışınlan.\nCOMMAND_DESCRIPTION_WARPS: Işınlanmalar menüsünü aç.\nCOMMAND_DESCRIPTION_WITHDRAW: Adanın bankasından kişisel hesabına para çek.\nCOMMAND_USAGE: '&cHatalı Kullanım: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyesi olarak ekledi.'\nCOOP_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve co-op olamaz.'\nCOOP_LIMIT_EXCEED: '&c&lHata | &7Ada, sahip olabileceği maksimum co-op oyuncu sayısına\n  ulaştı.'\nCREATE_ISLAND: '&e&lAda | &7Yeni bir ada {0} konumunda {1}ms içinde oluşturuldu.'\nCREATE_ISLAND_FAILURE: '&c&lHata | &7Adanı oluştururken bir hata oluştu. Lütfen sorunu\n  araştırmak için yöneticiyle iletişime geç.'\nCREATE_WORLD_FAILURE: '&c&lHata | &7Dünyanı oluştururken bir hata oluştu. Lütfen sorunu\n  araştırmak için yöneticiyle iletişime geç.'\nDEBUG_MODE_DISABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &cKAPALI&7.'\nDEBUG_MODE_ENABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &aAÇIK&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &aAÇIK&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lHata Ayıklama | &7Tüm hata ayıklama filtreleri &cKAPALI&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &cKAPALI&7.'\nDELETE_WARP: '&e&lAda | &7{0} ışınlanmasını sildin.'\nDELETE_WARP_SIGN_BROKE: '&7&oO ışınlanma için bir tabela vardı, kırıldı...'\nDEMOTE_LEADER: '&c&lHata | &7Ada liderlerini rütbe düşüremezsin.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne\n  sahip oyuncuları rütbe düşürebilirsin.'\nDEMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe düşürdün.'\nDEPOSIT_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasına ${1} yatırdı!'\nDEPOSIT_ERROR: '&c&lHata | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında kıramazsın.'\nDISBAND_ANNOUNCEMENT: '&e&lAda | &7Adan {0} tarafından dağıtıldı.'\nDISBAND_GIVE: '&e&lAda | &7{0} dağıtma hakkı aldın.'\nDISBAND_GIVE_ALL: '&e&lAda | &7Tüm oyunculara {0} dağıtma hakkı verdin.'\nDISBAND_GIVE_OTHER: '&e&lAda | &7{1}''e {0} dağıtma hakkı verdin.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oAdan dağıtıldı ve ada bankasından hesabına ${0}\n  dolar iade edildi.'\nDISBAND_SET: '&e&lAda | &7Dağıtma sayın {0} olarak ayarlandı.'\nDISBAND_SET_ALL: '&e&lAda | &7Tüm oyuncuların dağıtma sayısını {0} olarak ayarladın.'\nDISBAND_SET_OTHER: '&e&lAda | &7{0}''ın dağıtma sayısını {1} olarak ayarladın.'\nDISBANDED_ISLAND: '&e&lAda | &7Adanı dağıttın.'\nDISBANDED_ISLAND_OTHER: '&e&lAda | &7{0}''ın adasını dağıttın.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lAda | &7{0} adasını dağıttın.'\nENTER_PVP_ISLAND: '&7&oPVP etkin olan bir adaya ışınlandın. Sonraki 10 saniye boyunca\n  PVP''ye karşı dokunulmazsın...'\nEXPELLED_PLAYER: '&e&lAda | &7{0} adadan kovuldu.'\nFORMAT_QUAD: Q\nFORMAT_TRILLION: T\nFORMAT_BILLION: B\nFORMAT_MILLION: M\nFORMAT_THOUSANDS: K\nFORMAT_SECONDS_NAME: saniye\nFORMAT_SECOND_NAME: saniye\nFORMAT_MINUTES_NAME: dakika\nFORMAT_MINUTE_NAME: dakika\nFORMAT_HOURS_NAME: saat\nFORMAT_HOUR_NAME: saat\nFORMAT_DAYS_NAME: gün\nFORMAT_DAY_NAME: gün\nGENERATOR_CLEARED: '&e&lAda | &7{0}''ın adası için jeneratör miktarları başarıyla\n  temizlendi.'\nGENERATOR_CLEARED_NAME: '&e&lAda | &7{0} adasının jeneratör miktarları başarıyla temizlendi.'\nGENERATOR_CLEARED_ALL: '&e&lAda | &7Tüm adalar için jeneratör miktarları başarıyla\n  temizlendi.'\nGENERATOR_UPDATED: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1}''in adasına\n  güncellendi.'\nGENERATOR_UPDATED_NAME: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1} adasına\n  güncellendi.'\nGENERATOR_UPDATED_ALL: '&e&lAda | &7{0}''ın jeneratör miktarı tüm adalar için başarıyla\n  güncellendi.'\nGLOBAL_COMMAND_EXECUTED: '&e&lAda | &7Komut {0}''ın ada üyelerinde başarıyla çalıştırıldı!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lAda | &7Komut {0} adasının üyelerinde başarıyla\n  çalıştırıldı!'\nGLOBAL_MESSAGE_SENT: '&e&lAda | &7{0}''ın ada üyelerine mesaj başarıyla gönderildi!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine mesaj başarıyla gönderildi!'\nGLOBAL_TITLE_SENT: '&e&lAda | &7{0}''ın ada üyelerine başlık başarıyla gönderildi!'\nGLOBAL_TITLE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine başlık başarıyla gönderildi!'\nGOT_BANNED: '&e&lAda | &7{0}''ın adasından YASAKLANDIN.'\nGOT_DEMOTED: '&e&lAda | &7Adanda {0} olarak rütbe düşürüldün.'\nGOT_EXPELLED: '&e&lAda | &7&o{0} tarafından adadan kovuldun.'\nGOT_INVITE: '&e&lAda | &7{0} seni adasına davet etti.'\nGOT_INVITE_TOOLTIP: '&7Daveti kabul etmek için mesaja tıkla.'\nGOT_KICKED: '&e&lAda | &7{0} tarafından adandan atıldın.'\nGOT_PROMOTED: '&e&lAda | &7Adanda {0} olarak rütbe yükseltildin.'\nGOT_REVOKED: '&e&lAda | &7{0} adasına olan davetini geri çekti.'\nGOT_UNBANNED: '&e&lAda | &7{0}''ın adasından YASAĞIN KALDIRILDI.'\nHIT_ISLAND_MEMBER: '&c&lHata | &7Ada üyelerine vuramazsın.'\nHIT_PLAYER_IN_ISLAND: '&c&lHata | &7Adaların içindeki oyunculara vuramazsın.'\nIGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılıyor.'\nIGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılıyor.'\nINTERACT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında etkileşime geçemezsin.'\nINVALID_AMOUNT: '&c&lHata | &7Geçersiz miktar {0}.'\nINVALID_BIOME: '&c&lHata | &7Geçersiz biyom {0}.'\nINVALID_BLOCK: '&c&lHata | &7Geçersiz blok konumu {0}.'\nINVALID_BORDER_COLOR: '&c&lHata | &7Geçersiz sınır rengi {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lHata | &7Geçersiz efekt {0}.'\nINVALID_ENTITY: '&c&lHata | &7Geçersiz varlık {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lHata | &7Geçersiz aralık {0}.'\nINVALID_ISLAND: '&c&lHata | &7Bir adan yok.'\nINVALID_ISLAND_LOCATION: '&c&lHata | &7Konumunda bir ada bulunmuyor.'\nINVALID_ISLAND_OTHER: '&c&lHata | &7{0}''ın bir adası yok.'\nINVALID_ISLAND_OTHER_NAME: '&c&lHata | &7{0} adında bir ada bulunmuyor.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lHata | &7Ada izni {0} bulunamadı.\n  &c&lHata | &7Ada İzinleri: {1}\nINVALID_LEVEL: '&c&lHata | &7Geçersiz seviye {0}.'\nINVALID_LIMIT: '&c&lHata | &7Geçersiz limit {0}.'\nINVALID_MATERIAL: '&c&lHata | &7Geçersiz materyal {0}.'\nINVALID_MATERIAL_DATA: '&c&lHata | &7Geçersiz materyal-veri {0}.'\nINVALID_MENU: '&c&lError | &7Invalid menu {0}.'\nINVALID_MISSION: '&c&lHata | &7Geçersiz görev {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lHata | &7Geçersiz modül {0}.'\nINVALID_MULTIPLIER: '&c&lHata | &7Geçersiz çarpan {0}.'\nINVALID_PAGE: '&c&lHata | &7Geçersiz sayfa {0}.'\nINVALID_PERCENTAGE: '&c&lHata | &7Yüzde 0 ile 100 arasında olmalıdır.'\nINVALID_PLAYER: '&c&lHata | &7{0} adında bir oyuncu bulunamadı.'\nINVALID_RATE: |\n  &c&lHata | &7{0} adında bir değerlendirme bulunamadı.\n  &c&lHata | &7Ada Değerlendirmeleri: {1}\nINVALID_ROWS: '&c&lHata | &7Geçersiz satır sayısı: {0}'\nINVALID_ROLE: |\n  &c&lHata | &7Ada rolü {0} bulunamadı.\n  &c&lHata | &7Ada Rolleri: {1}\nINVALID_SCHEMATIC: '&c&lHata | &7{0} adında bir şematik bulunamadı.'\nINVALID_SETTINGS: |\n  &c&lHata | &7Ada ayarları {0} bulunamadı.\n  &c&lHata | &7Ada Ayarları: {1}\nINVALID_SIZE: '&c&lHata | &7Geçersiz boyut {0}.'\nINVALID_SLOT: '&c&lHata | &7Geçersiz yuva {0}.'\nINVALID_TITLE: '&c&lHata | &7Geçersiz başlık girildi.'\nINVALID_TOGGLE_MODE: '&c&lHata | &7{0} açılamaz/kapatılamaz.'\nINVALID_UPGRADE: |\n  &c&lHata | &7{0} adında bir yükseltme bulunamadı.\n  &c&lHata | &7Yükseltmeler: {1}\nINVALID_VISIT_LOCATION: '&c&lHata | &7Bu adanın ziyaretçi konumu yok.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oBypass modundasın, adaya ışınlanıyorsun...'\nINVALID_WARP: '&c&lHata | &7Geçersiz ışınlanma {0}.'\nINVALID_WORLD: '&c&lHata | &7Geçersiz dünya {0}.'\nINVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i adaya davet etti.'\nINVITE_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve davet edilemez.'\nINVITE_TO_FULL_ISLAND: '&c&lHata | &7Adana daha fazla üye davet edemezsin.'\nISLAND_ALREADY_CLOSED: '&c&lHata | &7Ada zaten halka kapalı.'\nISLAND_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ada zaten var.'\nISLAND_ALREADY_OPENED: '&c&lHata | &7Ada zaten halka açık.'\nISLAND_BANK_EMPTY: '&e&lBanka | &7Ada bankası boş.'\nISLAND_BANK_SHOW: '&e&lBanka | &7Adanda ${0} var.'\nISLAND_BANK_SHOW_OTHER: '&e&lBanka | &7{0}''ın adasında ${1} var.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanka | &7{0} adasında ${1} var.'\nISLAND_BEING_CALCULATED: '&c&lHata | &7Ada yeniden hesaplanırken bloklarla etkileşime\n  geçemezsin!'\nISLAND_CLOSED: '&e&lAda | &7Ada başarıyla halka kapatıldı.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lHata | &7Zaten devam eden bir ada oluşturma görevin\n  var.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &ckapatıldı&7.'\nISLAND_FLY_ENABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &aaçıldı&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lAda | &7&oDağıtılan bir adanın içindeydin, bu\n  yüzden doğuşa ışınlandın...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lAda | &7&oPVP''nin açıldığı bir adanın içindeydin,\n  bu yüzden doğuşa ışınlandın...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Komutlar Listesi [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is help {0} kullan.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lAda | &7Banka Limiti: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lAda | &7Blok Limitleri:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lAda | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lAda | &7co-op Limiti: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lAda | &7Bitki Çarpanı: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lAda | &7Düşürme Çarpanı: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lAda | &7Ada Efektleri:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lAda | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lAda | &7Varlık Limitleri:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lAda | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lAda | &7Jeneratör Oranları ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lAda | &7  {0}: %{1} ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lAda | &7Rol Limitleri:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lAda | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lAda | &7Sınır Boyutu: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lAda | &7Spawner Çarpanı: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lAda | &7Takım Limiti: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lAda | &7Yükseltmeler:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lAda | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lAda | &7Işınlanma Limiti: {0}'\nISLAND_INFO_BANK: '&e&lAda | &7Banka: {0}'\nISLAND_INFO_BONUS: '&e&lAda | &7Değer Bonusu: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lAda | &7Seviye Bonusu: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lAda | &7Oluşturma Süresi: {0}'\nISLAND_INFO_DISCORD: '&e&lAda | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lAda | &7Son Güncelleme: {0} önce'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lAda | &7Son Güncelleme: &aŞu\n  Anda Aktif'\nISLAND_INFO_LEVEL: '&e&lAda | &7Seviye: {0}'\nISLAND_INFO_LOCATION: '&e&lAda | &7Ev: {0}'\nISLAND_INFO_NAME: '&e&lAda | &7Adı: {0}'\nISLAND_INFO_OWNER: '&e&lAda | &7Lider: {0}'\nISLAND_INFO_PAYPAL: '&e&lAda | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lAda | &7 - {0}'\nISLAND_INFO_RATE: '&e&lAda | &7Değerlendirme: {0} &7({1}/5) - {2} toplam değerlendirme.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lAda | &7{0}lar:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme\n  modunda değilsin.'\nISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'ONAYLA'\nISLAND_PREVIEW_CANCEL_TEXT: 'İPTAL ET'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lÖnizleme | &7{0} şematiği için önizleme modunu başlattın.\n  &e&lÖnizleme | &7Yeni bir ada oluşturmak için &a&lONAYLA &7yaz, veya önizleme modunu iptal etmek için &c&lİPTAL ET &7yaz.\n  &e&lÖnizleme | &7Ada alanından ayrılamazsın, aksi takdirde önizleme modu otomatik olarak iptal edilir.\nISLAND_PROTECTED: '&c&lHata | &7Bu ada korumalı.'\nISLAND_PROTECTED_OPPED: '&7&o\"/is admin bypass\" komutunu kullanarak bu kısıtlamayı\n  atlayabilirsin.'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lAda | &7{0}''ın Adası Üyeleri &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Çevrimdışı)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Çevrimiçi)'\nISLAND_TEAM_STATUS_ROLES: '&e&lAda | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Çevrimdışı)'\nISLAND_TOP_STATUS_ONLINE: '&a(Çevrimiçi)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Özel]'\nISLAND_WAS_CLOSED: '&e&lAda | &7&oİçinde bulunduğun ada kapatıldı ve doğuşa ışınlandın...'\nISLAND_WORTH_ERROR: '&c&lHata | &7Adanı hesaplarken beklenmedik bir hata oluştu. Sorun\n  devam ederse yöneticilerle iletişime geç.'\nISLAND_WORTH_RESULT: '&e&lAda | &7Adanın değeri {0} [Seviye {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lHata | &7Hesaplama görevi zaman aşımına uğradı. Daha sonra\n  tekrar dene...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.'\nJOIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.'\nJOIN_FULL_ISLAND: '&c&lHata | &7Bu ada, izin verilen maksimum üye sayısına ulaştı.'\nJOIN_WHILE_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.'\nJOINED_ISLAND: '&e&lAda | &7{0}''ın adasına katıldın.'\nJOINED_ISLAND_NAME: '&e&lAda | &7{0} adasına katıldın.'\nJOINED_ISLAND_AS_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesisin.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesisin.'\nKICK_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan atıldı.'\nKICK_ISLAND_LEADER: '&c&lHata | &7Ada liderini atamazsın, bunun yerine /is admin disband\n  kullan.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip\n  oyuncuları atabilirsin.'\nLACK_CHANGE_PERMISSION: '&c&lHata | &7Bu izni başka rollere değiştirebilmek için bu\n  izne sahip olmalısın.'\nLAST_ROLE_DEMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe düşüremezsin.'\nLAST_ROLE_PROMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe yükseltemezsin.'\nLEAVE_ANNOUNCEMENT: '&e&lAda | &7{0} adadan ayrıldı.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lHata | &7Sahibi olduğun adandan ayrılamazsın.\n  &c&lHata | &7Liderliği /is transfer kullanarak devredebilirsin.'\nLEFT_ISLAND: '&e&lAda | &7Adandan ayrıldın.'\nLEFT_ISLAND_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesi değilsin.'\nLEFT_ISLAND_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesi değilsin.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the\n  island {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!'\nMATERIAL_NOT_SOLID: '&c&lHata | &7Katı bir materyal sağlamalısın.'\nMAXIMUM_LEVEL: '&c&lHata | &7Bu yükseltme için maksimum seviye {0}.'\nMESSAGE_SENT: '&e&lAda | &7{0}''e mesaj başarıyla gönderildi!'\nMISSION_CANNOT_COMPLETE: '&c&lHata | &7Bu görevi henüz tamamlayamazsın.'\nMISSION_NO_AUTO_REWARD: '&e&lGörev | &7{0}''i bitirmek için gerekli tüm materyallere\n  sahipsin - tamamlamak için /is missions kullan!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lHata | &7Bu görevi tamamlamadan önce\n  {0}''i tamamlamalısın.'\nMISSION_STATUS_COMPLETE: '&e&lGörev | &7{1} için {0} görevinin durumu tamamlandı olarak\n  değiştirildi.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu tamamlandı\n  olarak değiştirildi.'\nMISSION_STATUS_RESET: '&e&lGörev | &7{1} için {0} görevinin durumu sıfırlandı.'\nMISSION_STATUS_RESET_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu sıfırlandı.'\nMODULE_ALREADY_INITIALIZED: '&e&lModül | &7Bu modül zaten yüklü.'\nMODULE_INFO: |\n  &e&lModül | &7{0} geliştiren: {1}\n  &e&lModül | &7&m--------------------\n  &e&lModül | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModül | &7{0} modülü başarıyla yüklendi.'\nMODULE_LOADED_FAILURE: '&e&lModül | &7{0} modülü yüklenemedi. Daha fazla bilgi için\n  konsolu kontrol et.'\nMODULE_UNLOADED_SUCCESS: '&e&lModül | &7Modül başarıyla kaldırıldı.'\nMODULES_LIST: '&fModüller ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdi.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lHata | &7Bu adı kullanamazsın.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lHata | &7Oyuncu adlarını ada adı olarak kullanamazsın.'\nNAME_TOO_LONG: '&c&lHata | &7Ada adları {0} karakterden uzun olamaz.'\nNAME_TOO_SHORT: '&c&lHata | &7Ada adları {0} karakterden kısa olamaz.'\nNO_BAN_PERMISSION: '&c&lHata | &7Oyuncuları yasaklayabilmek için en az {0} olmalısın.'\nNO_CLOSE_BYPASS: '&c&lHata | &7Bu ada halka açık değil.'\nNO_CLOSE_PERMISSION: '&c&lHata | &7Adanı halka kapatabilmek için en az {0} olmalısın.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyesi olarak ekleyebilmek için\n  en az {0} olmalısın.'\nNO_DELETE_WARP_PERMISSION: '&c&lHata | &7Işınlanmaları silebilmek için en az {0} olmalısın.'\nNO_DEMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe düşürebilmek için en az {0} olmalısın.'\nNO_DEPOSIT_PERMISSION: '&c&lHata | &7Ada bankasına para yatırabilmek için en az {0}\n  olmalısın.'\nNO_DISBAND_PERMISSION: '&c&lHata | &7Adanı dağıtabilmek için en az {0} olmalısın.'\nNO_EXPEL_PERMISSION: '&c&lHata | &7Adandan oyuncuları kovabilmek için en az {0} olmalısın.'\nNO_INVITE_PERMISSION: '&c&lHata | &7Oyuncuları davet edebilmek için en az {0} olmalısın.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lHata | &7Ada sandığına erişebilmek için en az {0}\n  olmalısın.'\nNO_ISLAND_INVITE: '&c&lHata | &7Bu adadan herhangi bir davet bulunamadı.'\nNO_ISLANDS_TO_PURGE: '&c&lHata | &7Temizlenecek ada bulunamadı.'\nNO_KICK_PERMISSION: '&c&lHata | &7Oyuncuları atabilmek için en az {0} olmalısın.'\nNO_MORE_DISBANDS: '&c&lHata | &7Daha fazla ada dağıtamazsın.'\nNO_MORE_WARPS: '&c&lHata | &7Adanın daha fazla ışınlanma noktası olamaz.'\nNO_NAME_PERMISSION: '&c&lHata | &7Adanın adını değiştiremezsin.'\nNO_OPEN_PERMISSION: '&c&lHata | &7Adanı halka açabilmek için en az {0} olmalısın.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lHata | &7İzinler hakkında bilgi alabilmek için\n  en az {0} olmalısın.'\nNO_PROMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe yükseltebilmek için en az {0}\n  olmalısın.'\nNO_RANKUP_PERMISSION: '&c&lHata | &7Yükseltmeleri seviye atlamak için iznin yok.'\nNO_RATINGS_PERMISSION: '&c&lHata | &7Değerlendirmeleri kontrol edebilmek için en az\n  {0} olmalısın.'\nNO_SET_BIOME_PERMISSION: '&c&lHata | &7Ada biyomunu değiştirebilmek için en az {0}\n  olmalısın.'\nNO_SET_DISCORD_PERMISSION: '&c&lHata | &7Ada discordunu değiştirebilmek için en az\n  {0} olmalısın.'\nNO_SET_HOME_PERMISSION: '&c&lHata | &7Adanın ışınlanma konumunu ayarlayabilmek için\n  en az {0} olmalısın.'\nNO_SET_PAYPAL_PERMISSION: '&c&lHata | &7Ada paypal e-postasını değiştirebilmek için\n  en az {0} olmalısın.'\nNO_SET_ROLE_PERMISSION: '&c&lHata | &7Oyuncular için rol ayarlayabilmek için en az\n  {0} olmalısın.'\nNO_SET_SETTINGS_PERMISSION: '&c&lHata | &7Ada ayarlarını değiştirebilmek için en az\n  {0} olmalısın.'\nNO_SET_WARP_PERMISSION: '&c&lHata | &7Ada ışınlanmalarını ayarlayabilmek için en az\n  {0} olmalısın.'\nNO_TRANSFER_PERMISSION: '&c&lHata | &7Liderliği devredebilmek için adanın lideri olmalısın.'\nNO_UNCOOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyeliğinden çıkarabilmek için\n  en az {0} olmalısın.'\nNO_UPGRADE_PERMISSION: '&c&lHata | &7Başka bir seviyeye yükseltmek için iznin yok.'\nNO_WITHDRAW_PERMISSION: '&c&lHata | &7Ada bankasından para çekebilmek için en az {0}\n  olmalısın.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lHata | &7Adanın bankasına {0} dolar yatırmak için\n  yeterli paran yok.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lHata | &7Yeterli paran yok.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lHata | &7Ada ışınlanmalarını kullanmak için yeterli\n  paran yok.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oMenülerle etkileşime geçmek için çok mu yorgunsun,\n  sence de öyle değil mi?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7Ada paneli &cKAPALI&7.\n  &e&lPanel | &7/is çalıştırmak seni adaya ışınlayacak.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7Ada paneli &aAÇIK&7.\n  &e&lPanel | &7/is çalıştırmak paneli senin için açacak.\nPERMISSION_CHANGED: '&e&lAda | &7{1}''in adasının {0} izni başarıyla güncellendi.'\nPERMISSION_CHANGED_NAME: '&e&lAda | &7{1} adasının {0} izni başarıyla güncellendi.'\nPERMISSION_CHANGED_ALL: '&e&lAda | &7Tüm adalar için {0} izni başarıyla güncellendi.'\nPERSISTENT_DATA_EMPTY: '&c&lHata | &7Sorgun için veri bulunamadı.'\nPERSISTENT_DATA_MODIFY: '&e&lVeri | &7{0} için veri {1} ile {2} olarak başarıyla ayarlandı.'\nPERSISTENT_DATA_SHOW: '&e&lVeri | &7{0} verisi: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lVeri | &7{0} için {1} yolundan veri başarıyla kaldırıldı.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lAda | &7{0} için tüm izinler varsayılan değerlere başarıyla\n  sıfırlandı!'\nPERMISSIONS_RESET_ROLES: '&e&lAda | &7Adanın tüm izinleri varsayılan değerlere başarıyla\n  sıfırlandı!'\nPLACEHOLDER_NO: Hayır\nPLACEHOLDER_YES: Evet\nPLAYER_ALREADY_BANNED: '&c&lHata | &7Bu oyuncu zaten yasaklı.'\nPLAYER_ALREADY_COOP: '&c&lHata | &7Bu oyuncu zaten co-op.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lHata | &7Bu oyuncu zaten bir adada.'\nPLAYER_ALREADY_IN_ROLE: '&c&lHata | &7{0} zaten bir {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lHata | &7Bu kullanıcı adadan kovulamaz.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lAda | &7{0} sunucuya katıldı.'\nPLAYER_NOT_BANNED: '&c&lHata | &7Bu oyuncu yasaklı değil.'\nPLAYER_NOT_COOP: '&c&lHata | &7Bu oyuncu co-op değil.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lHata | &7Bu oyuncu adanın içinde değil.'\nPLAYER_NOT_ONLINE: '&c&lHata | &7Bu oyuncu çevrimiçi değil!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lAda | &7{0} sunucudan ayrıldı.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne\n  sahip oyuncuları rütbe yükseltebilirsin.'\nPROMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe yükselttin.'\nPURGE_CLEAR: '&e&lAda | &7Temizlenecek tüm sıralanmış adalar başarıyla temizlendi.'\nPURGED_ISLANDS: |-\n  &e&lAda | &7Sunucu yeniden başladığında {0} ada temizlenecek.\n  &e&lAda | &7İstediğin zaman /is admin purge cancel kullanarak iptal edebilirsin.'\nRANKUP_SUCCESS: '&e&lAda | &7{1}''in adası için {0} yükseltmesinin seviyesi başarıyla\n  güncellendi.'\nRANKUP_SUCCESS_ALL: '&e&lAda | &7Tüm adalar için {0} yükseltmesinin seviyesi başarıyla\n  güncellendi.'\nRANKUP_SUCCESS_NAME: '&e&lAda | &7{1} adası için {0} yükseltmesinin seviyesi başarıyla\n  güncellendi.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lAda | &7{0} adanı 5 üzerinden {1} olarak değerlendirdi!.'\nRATE_CHANGE_OTHER: '&e&lAda | &7{0}''ın değerlendirmesini {1} olarak değiştirdin.'\nRATE_OWN_ISLAND: '&c&lHata | &7Kendi adanı değerlendiremezsin.'\nRATE_REMOVE_ALL: '&e&lAda | &7{0}''ın tüm değerlendirmeleri başarıyla kaldırıldı.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lAda | &7Tüm adaların tüm değerlendirmeleri başarıyla\n  kaldırıldı.'\nRATE_SUCCESS: '&e&lAda | &7Bu adayı {0} yıldızla değerlendirdin!'\nREACHED_BLOCK_LIMIT: '&e&lYükseltmeler | &7Ada için {0} Bloğu limitine ulaştın.'\nREACHED_ENTITY_LIMIT: '&e&lYükseltmeler | &7Varlık {0} için adanın limitine ulaştın.'\nRECALC_ALREADY_RUNNING: '&c&lHata | &7Adan zaten yeniden hesaplanıyor.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lHata | &7Bu ada zaten yeniden hesaplanıyor.'\nRECALC_ALL_ISLANDS: '&e&lAda | &7Tüm adalar yeniden hesaplanıyor...'\nRECALC_ALL_ISLANDS_DONE: '&e&lAda | &7Tüm adaların yeniden hesaplanması başarıyla\n  tamamlandı.'\nRECALC_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...'\nRELOAD_COMPLETED: '&e&lAda | &7Yeniden yükleme tamamlandı!'\nRELOAD_PROCCESS_REQUEST: '&e&lAda | &7Yapılandırmalar yeniden yükleniyor...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''e adaya olan davetini geri çekti.'\nRESET_WORLD_SUCCEED: '&e&lAda | &7{1}''in adası için {0} dünyası başarıyla sıfırlandı.'\nRESET_WORLD_SUCCEED_ALL: '&e&lAda | &7Tüm adalar için {0} dünyası başarıyla sıfırlandı.'\nRESET_WORLD_SUCCEED_NAME: '&e&lAda | &7{1} adası için {0} dünyası başarıyla sıfırlandı.'\nSAME_NAME_CHANGE: '&c&lHata | &7Mevcut ada adından farklı bir ad girmelisin.'\nSCHEMATIC_LEFT_SELECT: '&e&lŞematikler | &7Konum #2 ({0}) seçildi.'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lHata | &7İki konum seçmedin.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lŞematikler | &7İsteğiniz işleniyor...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lŞematikler | &7İki konum seçtin. Yeni bir şematik oluşturmak için /is admin schematic <adı> komutunu çalıştır.\n  &e&lŞematikler | &7Komutu çalıştırırken ışınlanma konumunda durduğundan emin ol.\nSCHEMATIC_RIGHT_SELECT: '&e&lŞematikler | &7Konum #1 ({0}) seçildi.'\nSCHEMATIC_SAVED: '&e&lŞematikler | &7Şematik başarıyla kaydedildi!'\nSELF_ROLE_CHANGE: '&c&lHata | &7Kendi rolünü değiştiremezsin.'\nSET_UPGRADE_LEVEL: '&e&lYükseltmeler | &7{1}''in adası için {0} seviyesi başarıyla\n  güncellendi.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi başarıyla\n  güncellendi.'\nSET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.'\nSET_WARP_OUTSIDE: '&c&lHata | &7Adanın dışında ışınlanma noktası ayarlayamazsın.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla güncellendi.'\nSETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.'\nSETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.'\nSIZE_BIGGER_MAX: '&c&lHata | &7Maksimum ada boyutundan daha büyük bir boyut ayarlayamazsın.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lDoğuş | &7{0} başarıyla doğuşa ışınlandı.'\nSPAWN_SET_SUCCESS: '&e&lDoğuş | &7Doğuş konumu {0} olarak başarıyla güncellendi.'\nSPY_TEAM_CHAT_FORMAT: '&7[Casus] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lYükseltmeler | &7{0}''ın adasının tüm yükseltme değerleri başarıyla\n  senkronize edildi.'\nSYNC_UPGRADES_ALL: '&e&lYükseltmeler | &7Tüm adaların tüm yükseltme değerleri başarıyla\n  senkronize edildi.'\nSYNC_UPGRADES_NAME: '&e&lYükseltmeler | &7{0} adasının tüm yükseltme değerleri başarıyla\n  senkronize edildi.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lHata | &7Adanın içinde değilsin.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışına ışınlanamazsın.'\nTELEPORT_WARMUP: '&7&o{0} içinde ışınlanacaksın... Hareket etme!'\nTELEPORT_WARMUP_CANCEL: '&7&oHareket ettin ve ışınlanma iptal edildi.'\nTITLE_SENT: '&e&lAda | &7{0}''e başlık başarıyla gönderildi!'\nTELEPORTED_FAILED: '&e&lAda | &7Görünüşe göre bu adanın güvenli blokları yok. Lütfen\n  bir yetkiliyle iletişime geç.'\nTELEPORTED_SUCCESS: '&e&lAda | &7Adana ışınlandın.'\nTELEPORTED_TO_WARP: '&e&lAda | &7Bu ada ışınlanmasına başarıyla ışınlandın.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lAda | &7Oyuncu {0} {1} ada ışınlanmasına ışınlandı.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Bypass modu &cKAPALI&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Bypass modu &aAÇIK&7.'\nTOGGLED_FLY_OFF: '&e&lUçuş | &7Ada uçuşu &cKAPALI&7.'\nTOGGLED_FLY_ON: '&e&lUçuş | &7Ada uçuşu &aAÇIK&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lŞematikler | &7Şematik modu &cKAPALI&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lŞematikler | &7Şematik modu &aAÇIK&7.\n  &e&lŞematikler | &7Altın bir balta kullanarak bir alan seç.\nTOGGLED_SPY_OFF: '&e&lCasus | &7Sohbet casusluğu &cKAPALI&7.'\nTOGGLED_SPY_ON: '&e&lCasus | &7Sohbet casusluğu &aAÇIK&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lİstifleyici | &7Blok istifleyici &cKAPALI&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lİstifleyici | &7Blok istifleyici &aAÇIK&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lSohbet | &7Takım sohbeti &cKAPALI&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lSohbet | &7Takım sohbeti &aAÇIK&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lSınır | &7Dünya sınırı &cKAPALI&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lSınır | &7Dünya sınırı &aAÇIK&7.'\nTRANSFER_ADMIN: '&e&lAda | &7{0}''ın liderliğini {1}''e devrettin.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lHata | &7{0} zaten adasının lideri.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lHata | &7Bu oyuncular aynı adalarda değil.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lHata | &7Bu oyuncu hiçbir adanın lideri değil.'\nTRANSFER_ALREADY_LEADER: '&c&lHata | &7Zaten bu adanın liderisin.'\nTRANSFER_BROADCAST: '&e&lAda | &7Adanın liderliği {0}''e devredildi.'\nUNBAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAĞI KALDIRILDI.'\nUNCOOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyeliğinden çıkardı.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lAda | &7Çevrimiçi ada üyesi yok ve bu yüzden otomatik\n  olarak co-op üyeliğinden çıkarıldın.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lAda | &7{0} oyundan ayrıldı ve artık co-op üyesi değil.'\nUNIGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılmıyor.'\nUNIGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılmıyor.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all\n  islands!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for\n  the island {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lDünyalar | &7{0} dünyan artık kilitli değil!'\nUNSAFE_WARP: '&e&lAda | &7&oBu ışınlanma güvensiz görünüyor. Lütfen başka bir ışınlanmayı\n  dene.'\nUPDATED_PERMISSION: '&e&lAda | &7{0} için izinler güncellendi.'\nUPDATED_SETTINGS: '&e&lAda | &7Ada ayarları {0} güncellendi.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lHata | &7Sadece {0} içinde tekrar yükseltme yapabilirsin.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lHata | &7Bu komutu başka adalarda kullanamazsın.'\nWARP_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ışınlanma noktası zaten var.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için \"-cancel\" yaz):\n  &e&lIşınlanmalar | &7Satırları \"\\n\" kullanarak ayırabilirsin.\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için \"-cancel\"\n  yaz):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal\n  etmek için \"-cancel\" yaz):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lIşınlanmalar | &7Kategorinin simgesi başarıyla güncellendi.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lHata | &7Işınlanma kategorisi adları boş olamaz.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lHata | Işınlanma kategorisi adları 255 karakterden\n  uzun olamaz.'\nWARP_CATEGORY_SLOT: '&e&lIşınlanmalar | &7Yeni bir yuva gir (İptal etmek için \"-cancel\"\n  yaz):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lHata | &7Bu yuva zaten başka bir kategori tarafından\n  alınmış.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lIşınlanmalar | &7Kategorinin yuvası başarıyla {0}\n  olarak değiştirildi.'\nWARP_CATEGORY_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için \"-cancel\"\n  yaz):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir kategori tarafından\n  alınmış.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Kategori adı başarıyla {0} olarak\n  değiştirildi.'\nWARP_ICON_NEW_LORE: |\n  &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için \"-cancel\" yaz):\n  &e&lIşınlanmalar | &7Satırları \"\\n\" kullanarak ayırabilirsin.\nWARP_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için \"-cancel\" yaz):'\nWARP_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal etmek\n  için \"-cancel\" yaz):'\nWARP_ICON_UPDATED: '&e&lIşınlanmalar | &7Işınlanmanın simgesi başarıyla güncellendi.'\nWARP_ILLEGAL_NAME: '&c&lHata | &7Işınlanma adları boş olamaz.'\nWARP_LOCATION_UPDATE: '&e&lIşınlanmalar | &7Işınlanmanın konumu senin konumuna başarıyla\n  güncellendi.'\nWARP_NAME_TOO_LONG: '&c&lHata | Işınlanma adları 255 karakterden uzun olamaz.'\nWARP_PUBLIC_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka açıldı.'\nWARP_PRIVATE_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka kapatıldı.'\nWARP_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için \"-cancel\" yaz):'\nWARP_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir ışınlanma tarafından\n  alınmış.'\nWARP_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Işınlanma adı başarıyla {0} olarak değiştirildi.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lBanka | &7Ada bankasında sadece {0} dolar var.\n  &e&lBanka | &7&oTüm para çekiliyor...'\nWITHDRAW_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasından ${1} çekti!'\nWITHDRAW_ERROR: '&c&lHata | &7{0}.'\nWITHDRAWN_MONEY: '&e&lBanka | &7{1}''in ada bankasından ${0} çektin!'\nWITHDRAWN_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasından ${0} çektin!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lDünyalar | &7{0} dünyası henüz kilitli değil!'"
  },
  {
    "path": "src/main/resources/lang/vi-VN.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##               Phát triển bởi Ome_R               ##\n##                                                  ##\n######################################################\n\n# If you wish to create a new language file, please copy this one.\n# Make sure you give the name a correct language name.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# Bạn có thể xem hướng dẫn chỉnh sửa tệp ngôn ngữ này tại đây:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&lĐảo | &7Thêm thành công người chơi {0} vào đảo của {1}.'\nADMIN_ADD_PLAYER_NAME: '&e&lĐảo | &7Thêm thành công người chơi {0} vào đảo {1}.'\nADMIN_DEPOSIT_MONEY: '&e&lNgân Hàng | &7Bạn đã gửi ${0} vào ngân hàng đảo của\n  {1}.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã gửi ${0} vào ngân hàng đảo tên\n  {1}.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Phát triển bởi Ome_R'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Danh sách các lệnh cho quản trị viên [{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Dùng /is admin {0} để xem trang kế tiếp.'\nALREADY_IN_ISLAND: '&c&lLỗi | &7Bạn đã ở trong đảo rồi.'\nALREADY_IN_ISLAND_OTHER: '&c&lLỗi | &7Người chơi này đã là thành viên trong đảo của\n  bạn.'\nBAN_ANNOUNCEMENT: '&e&lĐảo | &7{0} vừa bị&c&n Cấm&7 trong đảo bởi {1}.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể cấm người chơi có vai trò\n  trong đảo thấp hơn bạn.'\nBANK_DEPOSIT_CUSTOM: '&e&lNgân Hàng | &7Nhập số lượng tiền bạn muốn gửi:'\nBANK_DEPOSIT_COMPLETED: 'Gửi tiền thành công'\nBANK_LIMIT_EXCEED: '&c&lLỗi | &7Bạn đã vượt quá giới hạn của ngân hàng.'\nBANK_WITHDRAW_CUSTOM: '&e&lNgân Hàng | &7Nhập số lượng tiền bạn muốn rút:'\nBANK_WITHDRAW_COMPLETED: 'Rút tiền thành công'\nBANNED_FROM_ISLAND: '&c&lLỗi | &7Bạn đã bị cấm trong hòn đảo này.'\nBLOCK_COUNT_CHECK: '&e&lĐảo | &7Đảo này có x{0} {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&lĐảo | &7Hòn đảo này có các khối sau:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&lĐảo | &7Đảo này không có khối được theo dõi.'\nBLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}'\nBLOCK_LEVEL: '&e&lCấp Độ | &7Khối {0} có giá trị cấp độ là {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&lCấp Độ | &7Khối {0} vô giá trị.'\nBLOCK_VALUE: '&e&lĐáng giá | &7Khối {0} được đánh giá với {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&lĐáng giá | &7Khối {0} vô giá trị.'\nBONUS_SYNC_ALL: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến tất cả các đảo.'\nBONUS_SYNC_NAME: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến {0}.'\nBONUS_SYNC: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo của {0}.'\nBORDER_PLAYER_COLOR_NAME_BLUE: 'Xanh dương'\nBORDER_PLAYER_COLOR_NAME_RED: 'Đỏ'\nBORDER_PLAYER_COLOR_NAME_GREEN: 'Xanh lá'\nBORDER_PLAYER_COLOR_UPDATED: '&e&lBiên Giới | &7Thành công thay đổi màu giới hạn đảo\n  của bạn thành {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể xây dựng ngoài phạm vi bảo vệ của\n  đảo bạn.'\nCANNOT_SET_ROLE: '&c&lLỗi | &7Bạn không thể đặt vai trò của người chơi thành {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể thay đổi quyền thành\n  vai trò trong đảo thấp hơn vai trò của bạn.'\nCHANGED_BANK_LIMIT: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn ngân hàng đảo của {0}.'\nCHANGED_BANK_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn ngân hàng của tất cả đảo.'\nCHANGED_BANK_LIMIT_NAME: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn ngân hàng của {0}.'\nCHANGED_BIOME: '&e&lĐảo | &7Thay đổi thành công quần xã thành {0}. Bạn có thể\n  cần kết nối lại với máy chủ để xem các thay đổi.'\nCHANGED_BIOME_ALL: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho tất cả các đảo.'\nCHANGED_BIOME_NAME: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho đảo {1}.'\nCHANGED_BIOME_OTHER: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho đảo của {1}.'\nCHANGED_BLOCK_AMOUNT: '&e&lKhối | &7Thành công thay đổi số lượng khối từ {0} thành {1}.'\nCHANGED_BLOCK_LIMIT: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn khối {0} đảo của\n  {1}.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp {0} giới hạn khối của tất cả các đảo.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn khối {0}\n  đảo của {1}.'\nCHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.'\nCHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.'\nCHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.'\nCHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.'\nCHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.'\nCHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.'\nCHANGED_CHEST_SIZE: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho đảo của {2}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho tất cả các đảo.'\nCHANGED_CHEST_SIZE_NAME: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho đảo {2}.'\nCHANGED_COOP_LIMIT: '&e&lNâng Cấp | &7Thành công nâng cấp số lượng thành viên đảo co-op của {0}.'\nCHANGED_COOP_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp số lượng thành viên đảo co-op của tất cả các đảo.'\nCHANGED_COOP_LIMIT_NAME: '&e&lNâng Cấp | &7Thành công nâng cấp số lượng thành viên đảo co-op của đảo {0}.'\nCHANGED_CROP_GROWTH: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây trồng\n  của đảo {0}.'\nCHANGED_CROP_GROWTH_ALL: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây trồng\n  của tất cả các đảo.'\nCHANGED_CROP_GROWTH_NAME: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây\n  trồng của đảo {0}.'\nCHANGED_DISCORD: '&e&lĐảo | &7Thay đổi thành công discord của đảo thành {0}.'\nCHANGED_ENTITY_LIMIT: '&e&lNâng Cấp | &7Thành công cập nhật số lượng giới hạn của vật thể {0} cho đảo của {1}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công cập nhật số lượng giới hạn của vật thể {0} cho tất cả các đảo.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&lNâng Cấp | &7Thành công cập nhật số lượng giới hạn của vật thể {0} cho đảo {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&lNâng Cấp | &7Thành công nâng cấp cấp độ của hiệu ứng đảo {0} cho đảo của {1}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp cấp độ của hiệu ứng đảo {0} cho tất cả các đảo.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lNâng Cấp | &7Thành công nâng cấp cấp độ của hiệu ứng đảo {0} cho đảo {1}.'\nCHANGED_ISLAND_SIZE: '&e&lNâng Cấp | &7Nâng cấp thành công kích thước đảo của {0}.'\nCHANGED_ISLAND_SIZE_ALL: '&e&lNâng Cấp | &7Thay đổi thành công kích thước đảo của tất cả các đảo.'\nCHANGED_ISLAND_SIZE_NAME: '&e&lNâng Cấp | &7Thay đổi thành công kích thước đảo {0}.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oNgười chơi có thể xây dựng bên ngoài hòn đảo của họ, vì vậy kích thước đảo không ảnh hưởng. Bạn có thể tắt tính năng đó trong cấu hình để kích thước đảo có ảnh hưởng trở lại.'\nCHANGED_LANGUAGE: '&e&lNgôn Ngữ | &7Thành công thay đổi ngôn ngữ của bạn thành Tiếng\n  Việt.'\nCHANGED_MOB_DROPS: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật của\n  đảo {0}.'\nCHANGED_MOB_DROPS_ALL: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật\n  của tất cả các đảo.'\nCHANGED_MOB_DROPS_NAME: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật\n  của đảo {0}.'\nCHANGED_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên đảo bạn thành {0}&7.'\nCHANGED_NAME_OTHER: '&e&lĐảo | &7Bạn đã thay đổi tên đảo của {0} thành {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên của {0}&7 thành {1}&7.'\nCHANGED_PAYPAL: '&e&lNâng Cấp | &7Thay đổi thành công paypal của đảo thành {0}.'\nCHANGED_ROLE_LIMIT: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn của vai trò {0} cho đảo của {1}.'\nCHANGED_ROLE_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn của vai trò {0} cho tất cả các đảo.'\nCHANGED_ROLE_LIMIT_NAME: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn của vai trò {0} cho đảo {1}.'\nCHANGED_SPAWNER_RATES: '&e&lNâng Cấp | &7Nâng cấp thành công tỉ lệ lồng sinh sản đảo của\n  {0}.'\nCHANGED_SPAWNER_RATES_ALL: '&e&lNâng Cấp | &7Cập nhật thành công tỷ lệ nhân giống\n  sinh sản của tất cả các đảo.'\nCHANGED_SPAWNER_RATES_NAME: '&e&lNâng Cấp | &7Cập nhật thành công tỷ lệ nhân giống\n  sinh sản của đảo {0}.'\nCHANGED_TEAM_LIMIT: '&e&lNâng Cấp | &7Nâng cấp thành công giới hạn người đảo của {0}.'\nCHANGED_TEAM_LIMIT_ALL: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn đội của tất\n  cả các đảo.'\nCHANGED_TEAM_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn đội của\n  đảo {0}.'\nCHANGED_TELEPORT_LOCATION: '&e&lĐảo | &7Cập nhật thành công vị trí dịch chuyển.'\nCHANGED_WARPS_LIMIT: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực đải\n  của {0}'\nCHANGED_WARPS_LIMIT_ALL: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực\n  của tất cả các đảo.'\nCHANGED_WARPS_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực\n  của đảo {0}.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: so-luong\nCOMMAND_ARGUMENT_BIOME: quan-xa\nCOMMAND_ARGUMENT_BORDER_COLOR: 'border-color'\nCOMMAND_ARGUMENT_COMMAND: lenh...\nCOMMAND_ARGUMENT_DIMENSION: 'dimension'\nCOMMAND_ARGUMENT_DISCORD: discord...\nCOMMAND_ARGUMENT_EFFECT: hieu-ung-thuoc\nCOMMAND_ARGUMENT_EMAIL: email\nCOMMAND_ARGUMENT_ENTITY: vat-the\nCOMMAND_ARGUMENT_ISLAND_NAME: ten-dao\nCOMMAND_ARGUMENT_ISLAND_ROLE: vai-tro-dao\nCOMMAND_ARGUMENT_LEADER: lanh-dao\nCOMMAND_ARGUMENT_LEVEL: cap-do\nCOMMAND_ARGUMENT_LIMIT: gioi-han\nCOMMAND_ARGUMENT_MATERIAL: vat-lieu\nCOMMAND_ARGUMENT_MENU: ten-giao-dien\nCOMMAND_ARGUMENT_MESSAGE: tin-nhan...\nCOMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category'\nCOMMAND_ARGUMENT_MISSION_NAME: ten-nhiem-vu\nCOMMAND_ARGUMENT_MODULE_NAME: ten-module\nCOMMAND_ARGUMENT_MULTIPLIER: he-so\nCOMMAND_ARGUMENT_NAME: ten\nCOMMAND_ARGUMENT_NEW_LEADER: lanh-dao-moi\nCOMMAND_ARGUMENT_PAGE: trang\nCOMMAND_ARGUMENT_PATH: 'path'\nCOMMAND_ARGUMENT_PERMISSION: quyen\nCOMMAND_ARGUMENT_PLAYER_NAME: ten-nguoi-choi\nCOMMAND_ARGUMENT_PRIVATE: rieng-tu\nCOMMAND_ARGUMENT_RATING: danh-gia\nCOMMAND_ARGUMENT_ROWS: so-dong\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: ten-schematic\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: cai-dat\nCOMMAND_ARGUMENT_SIZE: kich-thuoc\nCOMMAND_ARGUMENT_TIME: thoi-gian\nCOMMAND_ARGUMENT_TITLE_DURATION: thoi-luong\nCOMMAND_ARGUMENT_TITLE_FADE_IN: 'mo-vao(fade-in)'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: 'mo-ra(fade-out)'\nCOMMAND_ARGUMENT_UPGRADE_NAME: ten-nang-cap\nCOMMAND_ARGUMENT_VALUE: gia-tri\nCOMMAND_ARGUMENT_WARP_NAME: ten-khu-vuc\nCOMMAND_ARGUMENT_WARP_CATEGORY: danh-sach-khu-vuc\nCOMMAND_ARGUMENT_WORLD: the-gioi\nCOMMAND_COOLDOWN_FORMAT: '&c&lLỗi | &7Bạn chỉ có thể sử dụng lệnh trong {0}.'\nCOMMAND_DESCRIPTION_ACCEPT: Chấp nhận lời mời từ người chơi.\nCOMMAND_DESCRIPTION_ADMIN: Sử dụng các lệnh của admin.\nCOMMAND_DESCRIPTION_ADMIN_BONUS: Cấp tiền thưởng cho người chơi.\nCOMMAND_DESCRIPTION_ADMIN_ADD: Thêm người vào đảo.\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Tăng giới hạn khối cho đảo của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Thêm thưởng cho người chơi.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Tăng giới hạn thành viên đảo co-op của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Tăng hệ số tăng trưởng cây trồng của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Thêm hiệu ứng đảo của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Tăng giới hạn vật thể của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Thêm phần trăm vật liệu cho máy tạo đá cuội.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Tăng hệ số vật phẩm của quái rớt ra của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Mở rộng đảo của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Tăng hệ số tỷ lệ lồng sinh sản của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Tăng giới hạn thành viên đảo của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Tăng giới hạn khu vực của một hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: Chuyển đổi chế độ bypass.\nCOMMAND_DESCRIPTION_ADMIN_CHEST: 'Mở rương của hòn đảo của hòn đảo khác.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Xóa một tỷ lệ máy tạo quặng cho một hòn đảo cụ thể.\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: Đóng một hòn đảo thành công cộng.\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Thực hiện một lệnh cho tất cả các thành viên của các hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: Kiểm tra số khối trên một hòn đảo cụ thể.\nCOMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: Chuyển đổi đầu ra gỡ lỗi.\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Xóa một khu vực cho một hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: Hạ cấp thành viên ở đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: Gửi tiền vào ngân hàng đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: Giải tán vĩnh viễn hòn đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Giải tán cho người chơi.\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: Bỏ qua một hòn đảo từ những hòn đảo hàng đầu.\nCOMMAND_DESCRIPTION_ADMIN_JOIN: Tham gia một hòn đảo mà không cần lời mời.\nCOMMAND_DESCRIPTION_ADMIN_KICK: Đá một người chơi khỏi đảo.\nCOMMAND_DESCRIPTION_ADMIN_MODULES: 'Quản lý các module của plugin.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: Thay đổi trạng thái của một nhiệm vụ cho người\n  chơi.\nCOMMAND_DESCRIPTION_ADMIN_MSG: Gửi cho người chơi một tin nhắn mà không có bất kỳ\n  tiền tố.\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: Gửi cho tất cả các thành viên đảo một tin nhắn\n  mà không cần bất kỳ prefixes.\nCOMMAND_DESCRIPTION_ADMIN_NAME: Thay đổi tên của một hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_OPEN: Mở một hòn đảo cho công cộng.\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Mở một giao diện tùy chọn cho người chơi.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: Thăng chức thành viên ở đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_PURGE: Lọc bỏ số lượng lớn đảo.\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: Cập nhật mức độ nâng cấp cho hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_RECALC: Tính lại giá trị của một hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: Tải lại tất cả các config và tác vụ của plugin.\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Xóa giới hạn khối khỏi một hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Xóa tất cả các xếp hạng được cung cấp bởi\n  một người chơi.\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Tái tạo lại thế giới cho một hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Tạo các schematic cho plugin.\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: Đặt quần xã cho đảo.\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Đặt số lượng khối ở một vị trí cụ thể.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Đặt giới hạn khối cho đảo của người chơi\n  khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Đặt số dòng rương của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Đặt giới hạn người chơi co-op của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Đặt hệ số tăng trưởng cây trồng cho đảo\n  của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Đặt số lượng người cho đảo của người chơi.\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Đặt hiệu ứng đảo của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Đặt giới hạn vật thể của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: Chuyển một hòn đảo cho người khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Đặt số lượng vật phẩm quái rớt cho đảo của người chơi\n  khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Đặt vai trò bắt buộc để cấp quyền cho tất\n  cả các đảo.\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: Đặt đánh giá của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Đặt giới hạn vai trò của người chơi khác.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Chuyển đổi cài đặt cho một hòn đảo cụ thể.\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Thay đổi tỷ lệ phần trăm của vật liệu cho\n  máy tạo quặng.\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: Thay đổi kích thước đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Đặt vị trí trung tâm của máy chủ.\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Đặt tỉ lệ nhân đôi lồng sinh sản cho hòn đảo\n  của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Đặt giới hạn thành viên cho đảo của người\n  chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Đặt mức nâng cấp cho đảo của người chơi khác.\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Đặt giới hạn khu vực của một hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: Mở cài đặt điều chỉnh plugin.\nCOMMAND_DESCRIPTION_ADMIN_SHOW: Lấy thông tin của một hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: Dịch chuyển đến vị trí trung tâm.\nCOMMAND_DESCRIPTION_ADMIN_SPY: Chuyển đổi chế độ gián điệp trò chuyện\nCOMMAND_DESCRIPTION_ADMIN_STATS: Coi thông kê về plugin.\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Đồng bộ hóa các giá trị nâng cấp cho một hòn đảo.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: Dịch chuyển đến hòn đảo khác\nCOMMAND_DESCRIPTION_ADMIN_TITLE: 'Gửi cho người chơi một title.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Gửi cho tất cả thành viên đảo một title.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: Ngừng bỏ qua một hòn đảo từ những hòn đảo hàng\n  đầu.\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Mở khóa một thế giới cho một hòn đảo.\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: Rút tiền từ ngân hàng đảo của người chơi khác.\nCOMMAND_DESCRIPTION_BALANCE: 'Kiểm tra số tiền bên trong ngân hàng của một hòn đảo.'\nCOMMAND_DESCRIPTION_BAN: Cấm một người chơi từ đảo của bạn.\nCOMMAND_DESCRIPTION_BANK: 'Mở ngân hàng đảo.'\nCOMMAND_DESCRIPTION_BANS: 'Open the bans menu.'\nCOMMAND_DESCRIPTION_BIOME: Thẩy đổi quần xã của hòn đảo.\nCOMMAND_DESCRIPTION_BORDER: Thay đổi màu giới hạn đảo.\nCOMMAND_DESCRIPTION_CHEST: 'Mở rương đảo.'\nCOMMAND_DESCRIPTION_CLOSE: Đóng đảo thành công cộng.\nCOMMAND_DESCRIPTION_COOP: Thêm thành viên co-op cho đảo bạn.\nCOMMAND_DESCRIPTION_COOPS: Mở menu co-op.\nCOMMAND_DESCRIPTION_COUNTS: Xem số khối trong đảo của bạn.\nCOMMAND_DESCRIPTION_CREATE: Tạo một hòn đảo mới.\nCOMMAND_DESCRIPTION_DEL_WARP: Xóa một khu vực của đảo.\nCOMMAND_DESCRIPTION_DEMOTE: Hạ cấp một thành viên trong hòn đảo của bạn.\nCOMMAND_DESCRIPTION_DEPOSIT: Gửi tiền từ tài khoản cá nhân của bạn vào ngân hàng của\n  đảo.\nCOMMAND_DESCRIPTION_DISBAND: Giải tán hòn đảo của bạn vĩnh viễn.\nCOMMAND_DESCRIPTION_EXPEL: Kick một vị khách từ đảo của bạn.\nCOMMAND_DESCRIPTION_FLY: Chuyển chế độ bay cho đảo.\nCOMMAND_DESCRIPTION_HELP: Danh sách tất cả các lệnh.\nCOMMAND_DESCRIPTION_INVITE: Mời một người chơi đến đảo của bạn.\nCOMMAND_DESCRIPTION_KICK: Kick một người chơi từ đảo của bạn.\nCOMMAND_DESCRIPTION_LANG: Thay đổi ngôn ngữ cá nhân của bạn.\nCOMMAND_DESCRIPTION_LEAVE: Rời khỏi hòn đảo của bạn.\nCOMMAND_DESCRIPTION_MEMBERS: Mở menu thành viên.\nCOMMAND_DESCRIPTION_MISSION: Hoàn thành nhiệm vụ.\nCOMMAND_DESCRIPTION_MISSIONS: Mở menu nhiệm vụ.\nCOMMAND_DESCRIPTION_NAME: Thay đảo tên đảo của bạn.\nCOMMAND_DESCRIPTION_OPEN: Mở đảo cho công cộng.\nCOMMAND_DESCRIPTION_PANEL: Mở bảng điều khiển của đảo.\nCOMMAND_DESCRIPTION_PARDON: Bỏ cấm một người chơi từ đảo của bạn.\nCOMMAND_DESCRIPTION_PERMISSIONS: Xem tất cả các quyền cho vai trò đảo.\nCOMMAND_DESCRIPTION_PROMOTE: Thăng chức một thành viên trong hòn đảo của bạn.\nCOMMAND_DESCRIPTION_RANKUP: Tăng cấp một bản nâng cấp.\nCOMMAND_DESCRIPTION_RATE: Đánh giá một hòn đảo.\nCOMMAND_DESCRIPTION_RATINGS: Hiện thị tất cả đánh giá đảo.\nCOMMAND_DESCRIPTION_SETTINGS: Mở menu cài đặt đảo.\nCOMMAND_DESCRIPTION_RECALC: Tính lại giá trị đảo.\nCOMMAND_DESCRIPTION_SET_DISCORD: Đặt discord của đảo đối với các khoản thanh toán\n  trên đảo.\nCOMMAND_DESCRIPTION_SET_PAYPAL: Đặt email paypal của đảo cho các khoản thanh toán\n  trên đảo.\nCOMMAND_DESCRIPTION_SET_ROLE: Thay đổi vai trò của một người chơi trong hòn đảo của\n  bạn.\nCOMMAND_DESCRIPTION_SET_TELEPORT: Thay đổi vị trí dịch chuyển trên đảo của bạn.\nCOMMAND_DESCRIPTION_SET_WARP: Tạo một khu vực đảo mới.\nCOMMAND_DESCRIPTION_SHOW: Xem thông tin về một hòn đảo.\nCOMMAND_DESCRIPTION_TEAM: Xem thông tin về tình trạng thành viên đảo.\nCOMMAND_DESCRIPTION_TEAM_CHAT: Chuyển đổi chế độ trò chuyện nhóm.\nCOMMAND_DESCRIPTION_TELEPORT: Dịch chuyển đến đảo của bạn.\nCOMMAND_DESCRIPTION_TOGGLE: Chuyển đổi biên giới đảo và vị trí khối xếp chồng lên\n  nhau.\nCOMMAND_DESCRIPTION_TOP: Mở bảng đảo hàng đầu.\nCOMMAND_DESCRIPTION_TRANSFER: Chuyển lãnh đạo đảo của bạn.\nCOMMAND_DESCRIPTION_UNCOOP: Loại bỏ người chơi thành viên co-op trong đảo bạn.\nCOMMAND_DESCRIPTION_UPGRADE: Mở bảng nâng cấp.\nCOMMAND_DESCRIPTION_VALUE: Xem giá trị giá trị của một khối.\nCOMMAND_DESCRIPTION_VALUES: Mở menu giá trị.\nCOMMAND_DESCRIPTION_VISIT: Dịch chuyển đến vị trí của du khách trên đảo.\nCOMMAND_DESCRIPTION_VISITORS: Mở menu khách.\nCOMMAND_DESCRIPTION_WARP: Dịch chuyển đến một khu vực đảo.\nCOMMAND_DESCRIPTION_WARPS: Mở menu khu vực.\nCOMMAND_DESCRIPTION_WITHDRAW: Rút tiền từ ngân hàng đảo vào tài khoản cá nhân\n  của bạn.\nCOMMAND_USAGE: '&cCách dùng: /{0}'\nCOOP_ANNOUNCEMENT: '&e&lĐảo | &7{0} thêm {1} với tư cách thành viên co-op.'\nCOOP_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này đang bị cấm khỏi đảo và không thể trở thành\n  thành viên co-op.'\nCOOP_LIMIT_EXCEED: '&c&lLỗi | &7Bạn đã đạt số lượng người chơi co-op tối đa mà hòn đảo có thể có.'\nCREATE_ISLAND: '&e&lĐảo | &7Tạo một hòn đảo mới tại {0} trong {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&lLỗi | &7Đã xảy ra lỗi khi tạo đảo của bạn. Vui lòng liên hệ với quản trị viên để điều tra vấn đề.'\nCREATE_WORLD_FAILURE: '&c&lLỗi | &7Đã xảy ra lỗi khi tạo thế giới của bạn. Vui lòng liên hệ với quản trị viên để điều tra vấn đề.'\nDEBUG_MODE_DISABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &cTẮT&7.'\nDEBUG_MODE_ENABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &aBẬT&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lGỡ lỗi | &7Đã bật bộ lọc gỡ lỗi {0} &aBẬT&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lGỡ lỗi | &7Đã xóa tất cả bộ lọc gỡ lỗi &cTẮT&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lGỡ lỗi | &7Đã tắt bộ lọc gỡ lỗi {0} &cTẮT&7.'\nDELETE_WARP: '&e&lĐảo | &7Bạn đã xóa khu vực {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&oChỗ đó từng có một bảng khu vực, nhưng nó đã bị hỏng...'\nDEMOTE_LEADER: '&c&lLỗi | &7Bạn không thể hạ cấp lãnh đạo đảo.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể hạ cấp người chơi có\n  vai trò đảo thấp hơn của bạn.'\nDEMOTED_MEMBER: '&e&lĐảo | &7Bạn đã hạ cấp {0} thành {1} trong đảo của họ.'\nDEPOSIT_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} đã gửi {1}$ vào ngân hàng đảo!'\nDEPOSIT_ERROR: '&c&lLỗi | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể phá hủy bên ngoài phạm vi bảo vệ\n  của đảo bạn.'\nDISBAND_ANNOUNCEMENT: '&e&lĐảo | &7Đảo của bạn đã bị giải tán bởi {0}.'\nDISBAND_GIVE: '&e&lĐảo | &7Bạn đã nhận được {0} lượt giải tán.'\nDISBAND_GIVE_ALL: '&e&lĐảo | &7Bạn đã đưa số lần {0} tạo lại đảo cho tất cả người chơi.'\nDISBAND_GIVE_OTHER: '&e&lĐảo | &7Bạn đã cho {0} giải tán đến {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&oHòn đảo của bạn đã bị giải tán và ${0} tiền đã được hoàn trả vào tài khoản của bạn từ ngân hàng đảo.'\nDISBAND_SET: '&e&lĐảo | &7Số lượng giải tán của bạn đã được đặt thành {0}.'\nDISBAND_SET_ALL: '&e&lĐảo | &7Bạn đặt số lượng tạo lại đảo của tất cả người chơi thành {0}.'\nDISBAND_SET_OTHER: '&e&lĐảo | &7Bạn đã đặt số lần giải tán của {0} thành {1}.'\nDISBANDED_ISLAND: '&e&lĐảo | &7Bạn đã giải tán hòn đảo của bạn.'\nDISBANDED_ISLAND_OTHER: '&e&lĐảo | &7Bạn đã giải tán đảo của {0}.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&lĐảo | &7Bạn đã giải tán đảo {0}.'\nENTER_PVP_ISLAND: '&7&oBạn đã được dịch chuyển đến một hòn đảo có bật PVP. Bạn được\n  miễn sát thương với PVP trong 10 giây tiếp theo...'\nEXPELLED_PLAYER: '&e&lĐảo | &7{0} đã bị trục xuất khỏi đảo.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: giây\nFORMAT_SECOND_NAME: giây\nFORMAT_MINUTES_NAME: phút\nFORMAT_MINUTE_NAME: phút\nFORMAT_HOURS_NAME: giờ\nFORMAT_HOUR_NAME: giờ\nFORMAT_DAYS_NAME: ngày\nFORMAT_DAY_NAME: ngày\nGENERATOR_CLEARED: '&e&lĐảo | &7Xóa thành công số lượng máy tạo quặng cho đảo của {0}.'\nGENERATOR_CLEARED_NAME: '&e&lĐảo | &7Xóa thành công số lượng máy tạo quặng cho đảo {0}.'\nGENERATOR_CLEARED_ALL: '&e&lĐảo | &7Xóa thành công số lượng máy tạo quặng cho tất cả các đảo.'\nGENERATOR_UPDATED: '&e&lĐảo | &7Cập nhật thành công số lượng máy tạo quặng của {0} cho đảo của {1}.'\nGENERATOR_UPDATED_NAME: '&e&lĐảo | &7Cập nhật thành công số lượng máy tạo quặng của {0} cho đảo {1}.'\nGENERATOR_UPDATED_ALL: '&e&lĐảo | &7Cập nhật thành công số lượng máy tạo quặng của {0} cho tất cả các đảo.'\nGLOBAL_COMMAND_EXECUTED: '&e&lĐảo | &7Thành công thực hiện lệnh cho tất cả thành viên đảo của {0}!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&lĐảo | &7Thành công thực hiện lệnh cho tất cả thành viên đảo {0}!'\nGLOBAL_MESSAGE_SENT: '&e&lĐảo | &7Gửi thành công tin nhắn đến thành viên\n  đảo của {0}!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&lĐảo | &7Gửi thành công tin nhắn đến thành\n  viên của đảo {0}!'\nGLOBAL_TITLE_SENT: '&e&lĐảo | &7Gửi title cho thành viên đảo của {0} thành công!'\nGLOBAL_TITLE_SENT_NAME: '&e&lĐảo | &7Gửi title cho thành viên đảo {0} thành công!'\nGOT_BANNED: '&e&lĐảo | &7Bạn đã bị &cCẤM&7 khỏi đảo của {0}.'\nGOT_DEMOTED: '&e&lĐảo | &7Bạn đã bị hạ cấp xuống thành {0} trong đảo của bạn.'\nGOT_EXPELLED: '&e&lĐảo | &7&oBạn đã bị trục xuất khỏi đảo bởi {0}...'\nGOT_INVITE: '&e&lĐảo | &7{0} mời bạn đến đảo của họ.'\nGOT_INVITE_TOOLTIP: '&7Nhấp vào tin nhắn để chấp nhận lời mời.'\nGOT_KICKED: '&e&lĐảo | &7Bạn đã bị kick khỏi đảo của bạn bởi {0}.'\nGOT_PROMOTED: '&e&lĐảo | &7Bạn đã được thăng chức {0} trong đảo của bạn.'\nGOT_REVOKED: '&e&lĐảo | &7{0} đã thu hồi lời mời bạn đến đảo của họ.'\nGOT_UNBANNED: '&e&lĐảo | &7Bạn đã được dỡ bỏ lệnh cấm khỏi đảo của {0}.'\nHIT_ISLAND_MEMBER: '&c&lLỗi| &7Bạn không thể đánh thành viên đảo của bạn.'\nHIT_PLAYER_IN_ISLAND: '&c&lLỗi | &7Bạn không thể đánh người chơi trong đảo.'\nIGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không còn hiển thị trong\n  danh sách đảo hàng đầu.'\nIGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không còn hiển thị trong\n  danh sách đảo hàng đầu.'\nINTERACT_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể tương tác ngoài phạm vi bảo\n  vệ của đảo bạn.'\nINVALID_AMOUNT: '&c&lLỗi | &7Số lượng không hợp lệ {0}.'\nINVALID_BIOME: '&c&lLỗi | &7Quần xã không chính xác {0}.'\nINVALID_BLOCK: '&c&lLỗi | &7Vị trí khối không hợp lệ {0}.'\nINVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.'\nINVALID_COMMAND: '&c&lError | &7Invalid command {0}.'\nINVALID_EFFECT: '&c&lLỗi | &7Hiệu ứng không hợp lệ {0}.'\nINVALID_ENTITY: '&c&lLỗi | &7Vật thể không chính xác {0}.'\nINVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.'\nINVALID_INTERVAL: '&c&lLỗi | &7Thời gian nghỉ không hợp lệ {0}.'\nINVALID_ISLAND: '&c&lLỗi | &7Bạn không có một hòn đảo.'\nINVALID_ISLAND_LOCATION: '&c&lLỗi | &7Không có đảo nào ở vị trí của bạn.'\nINVALID_ISLAND_OTHER: '&c&lLỗi | &7{0} không có đảo.'\nINVALID_ISLAND_OTHER_NAME: '&c&lLỗi | &7Không có đảo nào với tên {0}.'\nINVALID_ISLAND_PERMISSION: |\n  &c&lLỗi | &7Không thể tìm thấy quyền của đảo {0}.\n  &c&lLỗi | &7Quyền của đảo: {1}\nINVALID_LEVEL: '&c&lLỗi | &7Cấp độ không hợp lệ {0}.'\nINVALID_LIMIT: '&c&lLỗi | &7Giới hạn không hợp lệ {0}.'\nINVALID_MATERIAL: '&c&lLỗi | &7Vật liệu không hợp lệ {0}.'\nINVALID_MATERIAL_DATA: '&c&lLỗi | &7Dữ liệu-vật liệu không hợp lệ {0}.'\nINVALID_MENU: '&c&lLỗi | &7Menu không hợp lệ {0}.'\nINVALID_MISSION: '&c&lLỗi | &7Nhiệm vụ không hợp lệ {0}.'\nINVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.'\nINVALID_MODULE: '&c&lLỗi | &7Module không hợp lệ {0}.'\nINVALID_MULTIPLIER: '&c&lLỗi | &7Hệ số không hợp lệ {0}.'\nINVALID_PAGE: '&c&lLỗi | &7Trang không hợp lệ {0}.'\nINVALID_PERCENTAGE: '&c&lLỗi | &7Tỷ lệ phần trăm phải nằm trong khoảng từ 0 đến 100.'\nINVALID_PLAYER: '&c&lLỗi | &7Không thể tìm thấy người chơi tên {0}'\nINVALID_RATE: |\n  &c&lLỗi | &7Không thể tìm thấy một đánh giá với tên {0}.\n  &c&lLỗi | &7Các đánh giá đảo: {1}\nINVALID_ROWS: '&c&lLỗi | &7Số lượng dòng không hợp lệ: {0}'\nINVALID_ROLE: |\n  &c&lLỗi | &7Không thể tìm thấy vai trò đảo {0}.\n  &c&lLỗi | &7Các vai trò của đảo: {1}\nINVALID_SCHEMATIC: '&c&lLỗi | &7không thể tìm thấy schematic với tên {0}.'\nINVALID_SETTINGS: |\n  &c&lLỗi | &7Không thể tìm thấy cài đặt đảo {0}.\n  &c&lLỗi | &7Các điều chỉnh đảo: {1}\nINVALID_SIZE: '&c&lLỗi | &7Kích thước không hợp lệ {0}.'\nINVALID_SLOT: '&c&lLỗi | &7Vị trí không hợp lệ {0}.'\nINVALID_TITLE: '&c&lLỗi | &7Đã nhập title không hợp lệ.'\nINVALID_TOGGLE_MODE: '&c&lLỗi | &7Không thể chuyển đổi {0}.'\nINVALID_UPGRADE: |\n  &c&lLỗi | &7Không thể tìm thấy bản nâng cấp được gọi là {0}.\n  &c&lLỗi | &7Nâng cấp: {1}\nINVALID_VISIT_LOCATION: '&c&lLỗi | &7Hòn đảo này không có vị trí du khách.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&oBạn có chế độ bypass, dịch chuyển bạn đến đảo...'\nINVALID_WARP: '&c&lLỗi | &7Khu vực không hợp lệ {0}.'\nINVALID_WORLD: '&c&lLỗi | &7Thế giới không hợp lệ {0}.'\nINVITE_ANNOUNCEMENT: '&e&lĐảo | &7{0} mời {1} vào đảo.'\nINVITE_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này bị cấm từ đảo và không thể được\n  mời.'\nINVITE_TO_FULL_ISLAND: '&c&lLỗi | &7Bạn không thể mời thêm thành viên đến đảo của\n  bạn.'\nISLAND_ALREADY_CLOSED: '&c&lLỗi | &7Đảo đã được đóng cửa biên giới.'\nISLAND_ALREADY_EXIST: '&c&lLỗi | &7Một hòn đảo với tên đó đã tồn tại.'\nISLAND_ALREADY_OPENED: '&c&lLỗi | &7Đảo đã được mở cửa biên giới.'\nISLAND_BANK_EMPTY: '&e&lNgân Hàng | &7Đảo ngân hàng trống rỗng.'\nISLAND_BANK_SHOW: '&e&lNgân Hàng | &7Đảo bạn có ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&lNgân Hàng | &7Đảo của {0} có ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&lNgân Hàng | &7Hòn đảo {0} có ${1}.'\nISLAND_BEING_CALCULATED: '&c&lLỗi | &7Bạn không thể tương tác với các khối khi đảo đang tính toán lại!'\nISLAND_CLOSED: '&e&lĐảo | &7Thành công đóng cửa đảo cho công cộng.'\nISLAND_CREATE_PROCESS_FAIL: '&c&lLỗi | &7Bạn đã có một nhiệm vụ tạo đảo đang diễn ra.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&lĐảo | &7Đang xử lý yêu cầu của bạn...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&lBay | &7Bay trong đảo đã tự động &cvô hiệu hóad&7.'\nISLAND_FLY_ENABLED: '&e&lBay | &7Bay trong đảo đã tự động &akích hoạt&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lĐảo | &7&oBạn đã ở trong một hòn đảo đã\n  bị giải tán, vì vậy bạn sẽ được dịch chuyển trở lại spawn...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lĐảo | &7&oBạn đã ở trong một hòn đảo\n  đã bật pvp, vì vậy bạn đã được dịch chuyển trở lại trung tâm...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Được phát triển bởi Ome_R'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Danh sách lệnh [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Dùng /is help {0} cho trang tiếp theo.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lĐảo | &7Giới Hạn Ngân Hàng: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&lĐảo | &7Giới Hạn Các Khối:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lĐảo | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lĐảo | &7Giới Hạn Co-op: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&lĐảo | &7Các hiệu ứng đảo:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lĐảo | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&lĐảo | &7Giới hạn các vật thể:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lĐảo | &7  {0}: {1}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lĐảo | &7Cây trồng đa cấp: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lĐảo | &7Drops đa cấp: {0}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&lĐảo | &7Tỉ lệ máy tạo quặng ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lĐảo | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&lĐảo | &7Giới Hạn Vai Trò:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lĐảo | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&lĐảo | &7Kích thước đảo: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lĐảo | &7Hệ số lồng sinh sản: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lĐảo | &7Giới hạn thành viên: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&lĐảo | &7Các Nâng Cấp:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lĐảo | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lĐảo | &7Giới hạn khu vực: {0}'\nISLAND_INFO_BANK: '&e&lĐảo | &7Ngân hàng: {0}'\nISLAND_INFO_BONUS: '&e&lĐảo | &7Giá trị đi kèm: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&lĐảo | &7Cấp độ đi kèm: {0}'\nISLAND_INFO_CREATION_TIME: '&e&lĐảo | &7Thời gian tạo đảo: {0}'\nISLAND_INFO_DISCORD: '&e&lĐảo | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&lĐảo | Cập nhật lần cuối: {0} trước'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lĐảo | &7Cập nhật lần cuối: &aHiện đang hoạt động'\nISLAND_INFO_LEVEL: '&e&lĐảo | &7Cấp độ: {0}'\nISLAND_INFO_LOCATION: '&e&lĐảo | &7Nhà: {0}'\nISLAND_INFO_NAME: '&e&lĐảo | &7Tên: {0}'\nISLAND_INFO_OWNER: '&e&lĐảo | &7Lãnh đạo: {0}'\nISLAND_INFO_PAYPAL: '&e&lĐảo | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&lĐảo | &7 - {0}'\nISLAND_INFO_RATE: '&e&lĐảo | &7Đánh giá: {0} &7({1}/5) - tất cả {2} đánh giá.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: ✦\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&lĐảo | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&lĐảo | &7Số lượt khách: {0} ({1} unique visitors)'\nISLAND_INFO_WORTH: '&e&lĐảo | &7Đáng giá: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&lĐảo | &7Mở đảo thành công cho công cộng.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lXem Trước | &7Bạn đã đi ra quá xa và thoát chế độ xem trước.'\nISLAND_PREVIEW_CANCEL: '&e&lXem Trước | &7Bạn đã hủy chế độ xem trước.'\nISLAND_PREVIEW_CONFIRM_TEXT: 'DONG-Y'\nISLAND_PREVIEW_CANCEL_TEXT: 'HUY-BO'\nISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.'\nISLAND_PREVIEW_START: |\n  &e&lXem Trước | &7Bạn đã bắt đầu chế độ xem trước schematic {0}.\n  &e&lXem Trước | &7Nhập &a&lDONG-Y &7để tạo đảo mới, hoặc &c&lHUY-BO &7để dừng chế độ xem trước.\n  &e&lXem Trước | &7Bạn không thể rời khỏi khu vực của hòn đảo, nếu không chế độ xem trước sẽ tự động bị hủy.\nISLAND_PROTECTED: '&c&lLỗi | &7Hòn đảo này được bảo vệ.'\nISLAND_PROTECTED_OPPED: '&7&oBạn có thể bỏ qua hạn chế này bằng cách sử dụng \"/is admin bypass\".'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&lĐảo | &7Thành viên đảo của {0} &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(Ngoại tuyến)'\nISLAND_TEAM_STATUS_ONLINE: '&a(Trực tuyến)'\nISLAND_TEAM_STATUS_ROLES: '&e&lĐảo | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(Ngoại Tuyến)'\nISLAND_TOP_STATUS_ONLINE: '&a(Trực Tuyến)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[Riêng Tư]'\nISLAND_WAS_CLOSED: '&e&lĐảo | &7&oHòn đảo bạn đang ở đã bị đóng cửa và bạn sẽ\n  dịch chuyển trở lại spawn...'\nISLAND_WORTH_ERROR: '&c&lLỗi | &7Đã xảy ra lỗi không mong muốn khi tính toán đảo của bạn. Liên hệ quản trị viên nếu vấn đề vẫn tiếp diễn.'\nISLAND_WORTH_RESULT: '&e&lĐảo | &7Giá trị đảo của bạn là {0} [Cấp độ {1}]'\nISLAND_WORTH_TIME_OUT: '&c&lLỗi | &7Quá trình tính toán đã hết thời gian. Vui lòng thử lại sau...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.'\nJOIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.'\nJOIN_FULL_ISLAND: '&c&lLỗi | &7Hòn đảo này đạt số lượng thành viên tối đa được phép.'\nJOIN_WHILE_IN_ISLAND: '&c&lLỗi | &7Bạn đã ở trong một hòn đảo rồi.'\nJOINED_ISLAND: '&e&lĐảo | &7Bạn đã tham gia đảo của {0}.'\nJOINED_ISLAND_NAME: '&e&lĐảo | &7Bạn đã vào đảo {0}.'\nJOINED_ISLAND_AS_COOP: '&e&lĐảo | &7Bây giờ bạn là thành viên co-op đảo của {0}.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&lĐảo | &7Bây giờ bạn là thành viên co-op đảo\n  {0}.'\nKICK_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã bị kick khỏi đảo bởi {1}.'\nKICK_ISLAND_LEADER: '&c&lLỗi | &7Bạn không thể đá người chủ đảo, thay vào đó sử dụng /is admin disband.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể kick người chơi có vai trò\n  đảo thấp hơn bạn.'\nLACK_CHANGE_PERMISSION: '&c&Lỗi | &7Bạn phải có quyền này để thay đổi nó thành các\n  vai trò khác.'\nLAST_ROLE_DEMOTE: '&c&lLỗi | &7Bạn không thể hạ cấp người chơi này nữa.'\nLAST_ROLE_PROMOTE: '&c&lLỗi | &7Bạn không thể thăng chức cho người chơi này nữa.'\nLEAVE_ANNOUNCEMENT: '&e&lĐảo | &7{0} vừa rời đảo.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&lLỗi | &7Bạn không thể rời đảo khi sở hữu nó.\n  &c&lLỗi | &7Bạn có thể chuyển quyền sở hữu bằng cách sử dụng /is transfer.\nLEFT_ISLAND: '&e&lĐảo | &7Bạn đã rời đảo của bạn.'\nLEFT_ISLAND_COOP: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo của {0}\n  nữa.'\nLEFT_ISLAND_COOP_NAME: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo {0}\n  nữa.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với tất cả các hòn đảo!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòn đảo {1}!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòa đảo của {1}!'\nMATERIAL_NOT_SOLID: '&c&lLỗi | &7Bạn phải cung cấp một vật liệu rắn.'\nMAXIMUM_LEVEL: '&c&lLỗi | &7Mức tối đa cho việc nâng cấp này là {0}.'\nMESSAGE_SENT: '&e&lĐảo | &7Gửi thành công {0} tin nhắn!'\nMISSION_CANNOT_COMPLETE: '&c&lLỗi | &7Bạn chưa thể hoàn thành nhiệm vụ này.'\nMISSION_NO_AUTO_REWARD: '&e&lNhiệm vụ | &7Bạn đã có tất cả các vật liệu cần thiết\n  để hoàn thành {0} - sử dụng /is missions để hoàn thành!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lLỗi | &7Bạn cần hoàn thành {0} trước\n  khi hoàn thahf nhiệm vụ này.'\nMISSION_STATUS_COMPLETE: '&e&lNhiệm Vụ | &7Thay đổi trạng thái của nhiệm vụ {0} hoàn thành cho {1}.'\nMISSION_STATUS_COMPLETE_ALL: '&e&lNhiệm Vụ | &7Đã thay đổi trạng thái của tất cả các nhiệm vụ thành đã hoàn thành cho {0}.'\nMISSION_STATUS_RESET: '&e&lNhiệm Vụ | &7Đặt lại trạng thái của nhiệm vụ {0} cho {1}.'\nMISSION_STATUS_RESET_ALL: '&e&lNhiệm Vụ | &7Đặt lại tất cả các nhiệm vụ cho {0}.'\nMODULE_ALREADY_INITIALIZED: '&e&lModule | &7Module đã đước tải sẵn trước đó.'\nMODULE_INFO: |\n  &e&lModule | &7{0} bởi {1}\n  &e&lModule | &7&m--------------------\n  &e&lModule | &7{2}\nMODULE_LOADED_SUCCESS: '&e&lModule | &7Thành công tải module {0}.'\nMODULE_LOADED_FAILURE: '&e&lModule | &7Không thể tải module {0}. Hãy kiểm tra console để có thêm thông tin.'\nMODULE_UNLOADED_SUCCESS: '&e&lModule | &7Đã hủy tải thành công module.'\nMODULES_LIST: '&fModules ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thay đổi tên đảo của anh/cô ấy thành {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.'\nNAME_BLACKLISTED: '&c&lLỗi | &7Bạn không thể sử dụng tên này.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&lLỗi | &7Bạn không thể dùng tên người chơi là tên đảo.'\nNAME_TOO_LONG: '&c&lLỗi | &7Tên đảo không thể dài hơn {0} kí tự.'\nNAME_TOO_SHORT: '&c&lLỗi | &7Tên đảo không thể ngắn hơn {0} ký tự.'\nNO_BAN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để cấm người chơi.'\nNO_CLOSE_BYPASS: '&c&lLỗi | &7Hòn đảo này không mở cửa cho công cộng.'\nNO_CLOSE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đóng đảo với công cộng.'\nNO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})'\nNO_COOP_PERMISSION: '&c&lLỗi | &7Bạn phải là {0} hoặc cao hơn để thêm người chơi\n  với tư cách là thành viên co-op.'\nNO_DELETE_WARP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để xóa khu vực.'\nNO_DEMOTE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để hạ cấp người chơi.'\nNO_DEPOSIT_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để gửi tiền vào ngân hàng\n  đảo.'\nNO_DISBAND_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để giải tán hòn đảo của\n  bạn.'\nNO_EXPEL_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để trục xuất người chơi khỏi\n  hòn đảo của bạn.'\nNO_INVITE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để mời người chơi.'\nNO_ISLAND_INVITE: '&c&lLỗi | &7Không thể tìm thấy bất kỳ lời mời từ hòn đảo này.'\nNO_ISLAND_CHEST_PERMISSION: '&c&lLỗi | &7Bạn phải cần ít nhất quyền {0} để truy cập rương đảo.'\nNO_ISLANDS_TO_PURGE: '&c&lLỗi | &7Không có đảo để lọc.'\nNO_KICK_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để để kick người chơi.'\nNO_MORE_DISBANDS: '&c&lLỗi | &7Bạn không thể giải tán đảo nữa.'\nNO_MORE_WARPS: '&c&lLỗi | &7Đảo của bạn không thể có thêm khu vực.'\nNO_NAME_PERMISSION: '&c&lLỗi | &7Bạn không thể thay đổi tên đảo.'\nNO_OPEN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để mở đảo thành công cộng.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để có được thông\n  tin về quyền.'\nNO_PROMOTE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thăng chức người chơi.'\nNO_RANKUP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để nâng cấp rank.'\nNO_RATINGS_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để kiểm tra đánh giá.'\nNO_SET_BIOME_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi biome của\n  đảo.'\nNO_SET_DISCORD_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi discord\n  của đảo.'\nNO_SET_HOME_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thiết lập vị trí dịch\n  chuyển của hòn đảo.'\nNO_SET_PAYPAL_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi email paypal\n  của đảo.'\nNO_SET_ROLE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thiết lập vai trò cho\n  người chơi.'\nNO_SET_SETTINGS_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để thay đổi điều chỉnh\n  đảo.'\nNO_SET_WARP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đặt khu vực cho đảo.'\nNO_TRANSFER_PERMISSION: '&cBạn phải là người lãnh đạo của hòn đảo để chuyển giao quyền\n  lãnh đạo.'\nNO_UNCOOP_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để loại bỏ người chơi từ\n  thành viên co-op.'\nNO_UPGRADE_PERMISSION: '&c&lLỗi | &7Bạn đang thiếu sự cho phép nâng cấp lên một cấp độ khác.'\nNO_WITHDRAW_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để rút tiền từ ngân hàng\n  của đảo.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lLỗi | &7Bạn không có đủ tiền để gửi {0}$ vào ngân\n  hàng đảo của bạn.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lLỗi | &7Bạn không có đủ tiền để nâng cấp.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&lLỗi | &7Bạn không có đủ tiền để dùng các khu vực đảo.'\nOPEN_MENU_WHILE_SLEEPING: '&7&oBạn quá mệt mỏi để tương tác với các menu, bạn không nghĩ vậy sao?'\nPANEL_TOGGLE_OFF: |-\n  &e&lBảng điều khiển | &7Chuyển đổi chế độ bảng điều khiển đảo: &cTẮT&7.\n  &e&lBảng điều khiển | &7Xài /is sẽ dịch chuyển bạn về đảo.'\nPANEL_TOGGLE_ON: |-\n  &e&lBảng điều khiển | &7Chuyển đổi chế độ bảng điều khiển đảo: &aBẬT&7.\n  &e&lBảng điều khiển | &7Dùng /is sẽ mở bảng điều khiển cho bạn.\nPERMISSION_CHANGED: '&e&lNâng Cấp | &7Thay đổi thành công quyền {0} đảo của {1}.'\nPERMISSION_CHANGED_NAME: '&e&lQuyền Lợi | &7Thay đổi thành công quyền {0} cho đảo\n  {1}.'\nPERMISSION_CHANGED_ALL: '&e&lNâng Cấp | &7Thay đổi thành công quyền {0} cho tất cả\n  các đảo.'\nPERSISTENT_DATA_EMPTY: '&c&lLỗi | &7Không tìm thấy dữ liệu nào cho truy vấn của bạn.'\nPERSISTENT_DATA_MODIFY: '&e&lDữ liệu | &7Đã đặt thành công dữ liệu cho {0} với {1}: {2}'\nPERSISTENT_DATA_SHOW: '&e&lDữ liệu | &7Dữ liệu của {0}: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&lDữ liệu | &7Đã xóa thành công dữ liệu cho {0} từ đường dẫn {1}.'\nPERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!'\nPERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!'\nPERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!'\nPERMISSIONS_RESET_PLAYER: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền cho {0} thành giá trị mặc định!'\nPERMISSIONS_RESET_ROLES: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền của hòn đảo thành giá trị mặc định!'\nPLACEHOLDER_NO: 'No'\nPLACEHOLDER_YES: 'Yes'\nPLAYER_ALREADY_BANNED: '&c&lLỗi | &7Người chơi này đã bị cấm.'\nPLAYER_ALREADY_COOP: '&c&lLỗi | &7Người chơi này đã hợp tác.'\nPLAYER_ALREADY_IN_ISLAND: '&c&lLỗi | &7Người chơi này đã có sẵn trong đảo.'\nPLAYER_ALREADY_IN_ROLE: '&c&lLỗi | &7{0} đã là một {1}.'\nPLAYER_EXPEL_BYPASS: '&c&lLỗi | &7Người chơi này không thể bị trục xuất khỏi đảo.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã vào server.'\nPLAYER_NOT_BANNED: '&c&lLỗi | &7Người chơi này không bị cấm.'\nPLAYER_NOT_COOP: '&c&lLỗi | &7Người chơi này không phải thành viên co-op.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&lLỗi | &7Người chơi này không ở trong hòn đảo của bạn.'\nPLAYER_NOT_ONLINE: '&c&Lỗi | &7Người chơi này không hoạt động!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thoát server.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể thăng chức người chơi\n  có vai trò đảo thấp hơn bạn.'\nPROMOTED_MEMBER: '&e&lĐảo | &7Bạn đã thăng chức {0} thành {1} ở đảo của họ.'\nPURGE_CLEAR: '&e&lĐảo | &7Thành công xóa tất cả các đảo xếp hàng đã lọc.'\nPURGED_ISLANDS: |-\n  &e&lĐảo | &7{0} các đảo sẽ bị lọc khi máy chủ tải lại.\n  &e&lĐảo | &7Bạn có thể huỷ bỏ nó mọi lúc bằng cách sử dụng /is admin purge cancel.\nRANKUP_SUCCESS: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho đảo của {1}.'\nRANKUP_SUCCESS_ALL: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho tất cả các đảo.'\nRANKUP_SUCCESS_NAME: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho {1}.'\nRATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.'\nRATE_ANNOUNCEMENT: '&e&lĐánh giá | &7{0} đã đánh giá đảo của bạn {1} trên 5!.'\nRATE_CHANGE_OTHER: '&e&lĐánh giá | &7Bạn đã thay đổi đánh giá của đảo {0} thành {1}.'\nRATE_OWN_ISLAND: '&c&lLỗi | &7Bạn không thể đánh giả đảo của bạn.'\nRATE_REMOVE_ALL: '&e&lĐánh giá | &7Thành công xóa bỏ tất cả đánh giá của đảo {0}.'\nRATE_REMOVE_ALL_ISLANDS: '&e&lĐảo | &7Thành công xóa bỏ tất cả đánh giá của tất cả các đảo.'\nRATE_SUCCESS: '&e&lĐánh giá | &7Bạn đánh giả đảo này với {0} sao!'\nREACHED_BLOCK_LIMIT: '&e&lNâng Cấp | &7Bạn đã đạt giới hạn {0} khối của đảo.'\nREACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.'\nRECALC_ALREADY_RUNNING: '&c&lLỗi | &7Đảo của bạn đang được tính toán lại, vui lòng chờ.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&lLỗi | &7Hòn đảo này đang được tính toán lại, vui lòng chờ.'\nRECALC_ALL_ISLANDS: '&e&lĐảo | &7Recalculating all islands...'\nRECALC_ALL_ISLANDS_DONE: '&e&lĐảo | &7Thành công tính toán lại tất cả các đảo.'\nRECALC_PROCCESS_REQUEST: '&e&lĐảo | &7Đang xử lý yêu cầu của bạn...'\nRELOAD_COMPLETED: '&e&lĐảo | &7Tải lại xong!'\nRELOAD_PROCCESS_REQUEST: '&e&lĐảo | &7Bắt đầu tải lại config...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&lĐảo | &7{0} thu hồi lời mời của {1} đến hòn\n  đảo.'\nRESET_WORLD_SUCCEED: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho đảo của {1}.'\nRESET_WORLD_SUCCEED_ALL: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho tất cả các đảo.'\nRESET_WORLD_SUCCEED_NAME: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho đảo {1}.'\nSAME_NAME_CHANGE: '&c&lLỗi | &7Bạn phải nhập một tên khác với tên đảo hiện tại của\n  bạn.'\nSCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Đã chọn vị trí #2 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&lLỗi | &7Bạn chưa chọn hai vị trí.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Đang xử lý yêu cầu của bạn...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&lSchematics | &7Bạn đã chọn hai vị trí. Xài /is admin schematic <tên> để tạo schematic mới.\n  &e&lSchematics | &7Hãy chắc chắn rằng bạn đứng ở vị trí dịch chuyển khi thực hiện lệnh.\nSCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Đã chọn vị trí #1 ({0})'\nSCHEMATIC_SAVED: '&e&lSchematics | &7Lưu thành công schematic!'\nSELF_ROLE_CHANGE: '&c&lLỗi | &7Bạn không thể thay đổi vai trò của chính mình.'\nSET_UPGRADE_LEVEL: '&e&lNâng Cấp | &7Nâng cấp thành công cấp độ của {0} cho đảo của\n  {1}.'\nSET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.'\nSET_UPGRADE_LEVEL_NAME: '&e&lNâng Cấp | &7Thay đổi thành công cấp độ {0} cho đảo {1}.'\nSET_WARP: '&e&lĐảo | &7Tạo thành công một khu vực mới tại {0}.'\nSET_WARP_OUTSIDE: '&c&lLỗi | &7Bạn không thể đặt khu vực bên ngoài hòn đảo của bạn.'\nSETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!'\nSETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!'\nSETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!'\nSETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!'\nSETTINGS_UPDATED: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho đảo của\n  {1}.'\nSETTINGS_UPDATED_NAME: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho\n  đảo {1}.'\nSETTINGS_UPDATED_ALL: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho tất\n  cả các đảo.'\nSIZE_BIGGER_MAX: '&c&lLỗi | &7Bạn không thể đặt kích thước lớn hơn kích thước tối đa của đảo.'\nSPAWN_PROTECTED: '&c&lError | &7Spawn is protected.'\nSPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using \"/is admin bypass\".'\nSPAWN_TELEPORT_SUCCESS: '&e&lTrung Tâm | &7Dịch chuyển thành công {0} đến trung tâm.'\nSPAWN_SET_SUCCESS: '&e&lTrung Tâm | &7Cập nhật thành công vị trí trung tâm thành {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[Bí Mật] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&lNâng Cấp | &7Đã đồng bộ hóa thành công tất cả các giá trị nâng cấp đảo của {0}.'\nSYNC_UPGRADES_ALL: '&e&lNâng Cấp | &7Đã đồng bộ hóa thành công tất cả các giá trị nâng cấp cho tất cả các đảo.'\nSYNC_UPGRADES_NAME: '&e&lNâng Cấp | &7Đã đồng bộ hóa thành công tất cả các giá trị nâng cấp của đảo {0}.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không ở trong đảo của bạn.'\nTELEPORT_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể dịch chuyển ra ngoài phạm vi bảo vệ đảo của bạn.'\nTELEPORT_WARMUP: '&7&oBạn sẽ được dịch chuyển trong {0}... Đừng di chuyển!'\nTELEPORT_WARMUP_CANCEL: '&7&oBạn đã di chuyển và do đó dịch chuyển tức thời đã bị\n  hủy.'\nTITLE_SENT: '&e&lĐảo | &7Thành công gửi người chơi {0} title!'\nTELEPORTED_FAILED: '&e&lĐảo | &7Có vẻ như hòn đảo này không có vị trí nào an toàn.\n  Xin vui lòng liên lạc với ban quản trị.'\nTELEPORTED_SUCCESS: '&e&lĐảo | &7Bạn đã được dịch chuyển đến hòn đảo của bạn.'\nTELEPORTED_TO_WARP: '&e&lĐảo | &7Dịch chuyển thành công đến khu vực của hòn đảo\n  này.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lĐảo | &7Người chơi {0} đã dịch chuyển đến khu vực đảo {1}.'\nTOGGLED_BYPASS_OFF: '&e&lBypass | &7Chuyển đổi chế độ bypass: &cTẮT&7.'\nTOGGLED_BYPASS_ON: '&e&lBypass | &7Chuyển đổi chế độ bypass: &aBẬT&7.'\nTOGGLED_FLY_OFF: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &cTẮT&7.'\nTOGGLED_FLY_ON: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &aBẬT&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.'\nTOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.'\nTOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Chuyển đổi chế độ schematic: &cTẮT&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&lSchematics | &7Chuyển đổi chế độ schematic: &aBẬT&7.\n  &e&lSchematics | &7Chọn một khu vực bằng rìu vàng (golden axe).\nTOGGLED_SPY_OFF: '&e&lBí Mật | &7Chế độ nói chuyện bí mật: &cTẮT&7.'\nTOGGLED_SPY_ON: '&e&lBí Mật | &7Chế độ nói chuyện bí mật: &aBẬT&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Chuyển đổi chế độ stack khối: &cTẮT&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Chuyển đổi chế độ stack khối: &aBẬT&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&lTrò chuyện | &7Chuyển đổi chế độ trò chuyện đôi &cTẮT&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&lTrò chuyện | &7Chuyển đổi chế độ trò chuyện đội: &aBẬT&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&lBiên giới | &7Chuyển đổi chế độ biên giới: &cTẮT&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&lBiên giới | &7Chuyển đổi chế độ biên giới: &aBẬT&7.'\nTRANSFER_ADMIN: '&e&lĐảo | &7Bạn đã chuyển vai trò lãnh đạo {0} cho {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&lLỗi | &7{0} đã là người lãnh đạo hòn đảo của họ.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lLỗi | &7Những người chơi này không ở cùng một\n  hòn đảo.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&lLỗi | &7Người chơi này không phải là một người lãnh\n  đạo của bất kỳ hòn đảo nào.'\nTRANSFER_ALREADY_LEADER: '&cBạn đã là người lãnh đạo của hòn đảo này.'\nTRANSFER_BROADCAST: '&e&lĐảo | &7Lãnh đạo của hòn đảo đã được chuyển cho {0}.'\nUNBAN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã được dỡ bỏ lệnh cấm trong đảo bởi {1}.'\nUNCOOP_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã huỷ bỏ tư cách thành viên coop\n  của {1}'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&lĐảo | &7Không có thành viên đảo nào trực tuyến và do đó bạn đã tự động bị hủy chế độ co-op.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thoát khỏi trò chơi và không\n  còn là một thành viên co-op.'\nUNIGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không được bỏ qua từ các\n  đảo hàng đầu.'\nUNIGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không được bỏ qua từ các\n  đảo hàng đầu.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho tất cả đảo!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho đảo {1}!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho hòn đảo của {1}!'\nUNSAFE_WARP: '&e&lĐảo | &7&oCó vẻ như khu vực này không an toàn. Vui lòng thử\n  lại với khu vực khác.'\nUPDATED_PERMISSION: '&e&lĐảo | &7Đã cập nhật quyền cho {0}.'\nUPDATED_SETTINGS: '&e&lĐảo | &7Thay đổi thành công điều chỉnh của đảo {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&lLỗi | &77Bạn có thể nâng cấp lại trong {0}.'\nVAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.'\nVISITOR_BLOCK_COMMAND: '&c&lLỗi | &7Bạn không thể sử dụng lệnh này trên đảo khác.'\nWARP_ALREADY_EXIST: '&c&lLỗi | &7Đã có một khu vực đã được đặt với tên này.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&lKhu Vực | &7Hãy nhập mô tả mới (Nhập \"-cancel\" để hủy):\n  &e&lKhu Vực | &7Bạn có thể xuống dòng bằng cách thêm chữ \"\\n\".\nWARP_CATEGORY_ICON_NEW_NAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập \"-cancel\" để hủy):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&lKhu Vực | &7Vui lòng nhập một nguyên liệu mới (Nhập \"-cancel\" để hủy):'\nWARP_CATEGORY_ICON_UPDATED: '&e&lKhu Vực | &7Cập nhật thành công biểu tượng danh mục.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&lLỗi | &7Bạn chỉ có thể sử dụng các chữ cái theo thứ tự bảng chữ cái, số và ''_'' cho tên danh mục khu vực.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&lLỗi | &7Tên danh mục khu vực không thể dài hơn 255 kí tự.'\nWARP_CATEGORY_SLOT: '&e&lKhu Vực | &7Vui lòng nhập vị trí mới (Nhập \"-cancel\" để hủy):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lLỗi | &7Vị trí đã được dùng bởi một danh mục khu vực khác.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&lKhu Vực | &7Thành công thay đổi danh mục tới vị trí {0}.'\nWARP_CATEGORY_RENAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập \"-cancel\" để hủy):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lLỗi | &7Tên này đã được dùng bởi một danh mục khu vực khác.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&lKhu Vực | &7Thành công đổi tên danh mục thành {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&lKhu Vực | &7Hãy nhập mô tả mới (Nhập \"-cancel\" để hủy):\n  &e&lKhu Vực | &7Bạn có thể xuống dòng bằng cách thêm chữ \"\\n\".\nWARP_ICON_NEW_NAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập \"-cancel\" để hủy):'\nWARP_ICON_NEW_TYPE: '&e&lKhu Vực | &7Vui lòng nhập một nguyên liệu mới (Nhập \"-cancel\" để hủy):'\nWARP_ICON_UPDATED: '&e&lKhu Vực | &7Cập nhật thành công biểu tượng danh mục.'\nWARP_ILLEGAL_NAME: '&c&lLỗi | &7Bạn chỉ có thể sử dụng các chữ cái theo thứ tự bảng chữ cái, số và ''_'' cho tên danh mục khu vực.'\nWARP_LOCATION_UPDATE: '&e&lKhu Vực | &7Đã cập nhật thành công vị trí của khu vực vào vị trí của bạn.'\nWARP_NAME_TOO_LONG: '&c&lLỗi | &7Tên khu vực không thể dài hơn 255 kí tự.'\nWARP_PUBLIC_UPDATE: '&e&lKhu Vực | &7Thành công mở khu vực cho công chúng.'\nWARP_PRIVATE_UPDATE: '&e&lKhu Vực | &7Thành công đóng khu vực đối với công chúng.'\nWARP_RENAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập \"-cancel\" để hủy):'\nWARP_RENAME_ALREADY_EXIST: '&c&lLỗi | &7Tên này đã được dùng bởi một danh mục khu vực khác.'\nWARP_RENAME_SUCCESS: '&e&lKhu Vực | &7Thành công đổi tên danh mục thành {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&lNgân Hàng | &7Đảo ngân hàng chỉ có {0}$ bên trong.\n  &e&lNgân Hàng | &7&oRút toàn bộ tiền...\"\nWITHDRAW_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} rút {1}$ từ ngân hàng của đảo!'\nWITHDRAW_ERROR: '&c&lLỗi | &7{0}.'\nWITHDRAWN_MONEY: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo của {1}!'\nWITHDRAWN_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo {1}!'\nWORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.'\nWORLD_NOT_UNLOCKED: '&e&lThế Giới | &7Thế giới {0} hiện chưa được mở khóa!'"
  },
  {
    "path": "src/main/resources/lang/zh-CN.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                  插件作者 Ome_R                   ##\n##                                                  ##\n######################################################\n\n# 若你需要创建一个新的语言文件, 那么请复制这个.\n# 请确保你使用了正确的语言命名格式.\n# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html\n# 可以在这里找到如何正确配置消息文本的教程:\n# https://wiki.bg-software.com/superiorskyblock/messages\n\nADMIN_ADD_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 添加至了玩家 {1} 的岛屿.'\nADMIN_ADD_PLAYER_NAME: '&e&l岛屿 | &7成功将玩家 {0} 添加至了岛屿 {1}.'\nADMIN_DEPOSIT_MONEY: '&e&l银行 | &7你将 ${0} 存入了 {1} 的岛屿银行.'\nADMIN_DEPOSIT_MONEY_NAME: '&e&l银行 | &7你存入了 ${0} 至岛屿 {1} 的银行.'\nADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7由 Ome_R 开发'\nADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7管理员命令列表[{0}/{1}]:'\nADMIN_HELP_LINE: '&e/{0} &f- &7{1}'\nADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7使用 /is admin {0} 来翻到下一页.'\nALREADY_IN_ISLAND: '&c&l错误 | &7你已经处于一个岛屿中了.'\nALREADY_IN_ISLAND_OTHER: '&c&l错误 | &7此玩家已经是其他的岛屿成员了.'\nBAN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 已被 {1} 从该岛屿封禁.'\nBAN_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能封禁等级低于你的玩家.'\nBANK_DEPOSIT_CUSTOM: '&e&l银行 | &7输入你需要存入的货币数量:'\nBANK_DEPOSIT_COMPLETED: '存入成功'\nBANK_LIMIT_EXCEED: '&c&l错误 | &7你已经达到了银行存量上限.'\nBANK_WITHDRAW_CUSTOM: '&e&l银行 | &7输入你需要取出的货币数量:'\nBANK_WITHDRAW_COMPLETED: '取出成功'\nBANNED_FROM_ISLAND: '&c&l错误 | &7你已被该岛屿封禁.'\nBLOCK_COUNT_CHECK: '&e&l岛屿 | &7该岛屿有 {0} 个 {1}.'\nBLOCK_COUNTS_CHECK: |\n  &e&l岛屿 | &7该岛屿包含下列方块:\n  &7{0}\nBLOCK_COUNTS_CHECK_EMPTY: '&e&l岛屿 | &7该岛屿中不包含任何在追踪列表内的方块.'\nBLOCK_COUNTS_CHECK_MATERIAL: '{1} x{0}'\nBLOCK_LEVEL: '&e&l等级 | &7方块 {0} 的等级为 {1}.'\nBLOCK_LEVEL_WORTHLESS: '&e&l等级 | &7方块 {0} 没有价格.'\nBLOCK_VALUE: '&e&l价值 | &7方块 {0} 的价值为 {1}.'\nBLOCK_VALUE_WORTHLESS: '&e&l价值 | &7方块 {0} 没有价格.'\nBONUS_SYNC_ALL: '&e&l岛屿 | &7成功将该岛屿奖励同步至所有岛屿'\nBONUS_SYNC_NAME: '&e&l岛屿 | &7成功将该岛屿奖励同步为 {0}.'\nBONUS_SYNC: '&e&l岛屿 | &7成功将该岛屿奖励同步至了玩家 {0} 的岛屿.'\nBORDER_PLAYER_COLOR_NAME_BLUE: '蓝'\nBORDER_PLAYER_COLOR_NAME_RED: '红'\nBORDER_PLAYER_COLOR_NAME_GREEN: '绿'\nBORDER_PLAYER_COLOR_UPDATED: '&e&l边界 | &7成功将个人的边界颜色设置为了 {0}.'\nBUILD_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外进行建筑行为.'\nCANNOT_SET_ROLE: '&c&l错误 | &7你不能将玩家的等级设置为 {0}.'\nCHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&l错误 | &7你只能修改等级低于你的玩家的权限.'\nCHANGED_BANK_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿银行存款上限.'\nCHANGED_BANK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的银行存款上限.'\nCHANGED_BANK_LIMIT_NAME: '&e&l升级 | &7成功更新了 {0} 的岛屿银行上限.'\nCHANGED_BIOME: '&e&l岛屿 | &7成功将生物群系修改为了 {0}. 你可能需要重新进入服务器才可看见改动.'\nCHANGED_BIOME_ALL: '&e&l岛屿 | &7成功将所有岛屿的生物群系修改为了 {0}.'\nCHANGED_BIOME_NAME: '&e&l岛屿 | &7成功将岛屿 {1} 的生物群系修改为了 {0}.'\nCHANGED_BIOME_OTHER: '&e&l岛屿 | &7成功将玩家 {1} 的岛屿生物群系修改为了 {0}.'\nCHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7成功将 {0} 的方块数量设置为了 {1}.'\nCHANGED_BLOCK_LIMIT: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.'\nCHANGED_BLOCK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的方块 {0} 限制.'\nCHANGED_BLOCK_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.'\nCHANGED_BONUS_LEVEL: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿等级奖励.'\nCHANGED_BONUS_LEVEL_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的等级奖励.'\nCHANGED_BONUS_LEVEL_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的等级奖励.'\nCHANGED_BONUS_WORTH: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿价值奖励.'\nCHANGED_BONUS_WORTH_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的价值奖励.'\nCHANGED_BONUS_WORTH_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的价值奖励.'\nCHANGED_CHEST_SIZE: '&e&lChest | &7成功将玩家 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.'\nCHANGED_CHEST_SIZE_ALL: '&e&lChest | &7成功将所有岛屿的岛屿仓库 #{0} 的行数更新为了 {1}.'\nCHANGED_CHEST_SIZE_NAME: '&e&lChest | &7成功将岛屿 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.'\nCHANGED_COOP_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿成员数量限制.'\nCHANGED_COOP_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的岛屿成员数量限制.'\nCHANGED_COOP_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的岛屿成员数量限制.'\nCHANGED_CROP_GROWTH: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿作物生长速率.'\nCHANGED_CROP_GROWTH_ALL: '&e&l升级 | &7成功更新了所有岛屿的作物生长速率.'\nCHANGED_CROP_GROWTH_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的作物生长速率.'\nCHANGED_DISCORD: '&e&l岛屿 | &7成功将岛屿的 Discord 群组聊天设置为了 {0}.'\nCHANGED_ENTITY_LIMIT: '&e&l升级 | &7成功将玩家 {1} 的岛屿实体限制修改为了 {0}.'\nCHANGED_ENTITY_LIMIT_ALL: '&e&l升级 | &7成功将所有岛屿的实体限制修改为了 {0}.'\nCHANGED_ENTITY_LIMIT_NAME: '&e&l升级 | &7成功将岛屿 {1} 的实体限制修改为了 {0}.'\nCHANGED_ISLAND_EFFECT_LEVEL: '&e&l升级 | &7成功将玩家 {1} 的岛屿效果等级修改为了 {0}.'\nCHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&l升级 | &7成功将所有岛屿的效果等级修改为了 {0}.'\nCHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&l升级 | &7成功将岛屿 {1} 的效果等级修改为了 {0}.'\nCHANGED_ISLAND_SIZE: '&e&l升级 | &7成功修改了玩家 {0} 的岛屿边界大小.'\nCHANGED_ISLAND_SIZE_ALL: '&e&l升级 | &7成功更新了所有岛屿的边界大小.'\nCHANGED_ISLAND_SIZE_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的边界大小.'\nCHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&o玩家可以在他们岛屿的外部进行建筑行为, 所以岛屿大小限制功能无效. 可以在配置文本对这些设置进行调整以使其再次有效.'\nCHANGED_LANGUAGE: '&e&l语言 | &7成功将你的语言修改为了简体中文.'\nCHANGED_MOB_DROPS: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿掉落物翻倍量.'\nCHANGED_MOB_DROPS_ALL: '&e&l升级 | &7成功更新了所有岛屿的掉落物翻倍量.'\nCHANGED_MOB_DROPS_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的掉落物翻倍量.'\nCHANGED_NAME: '&e&l岛屿 | &7你将岛屿的名称修改为了 {0}&7.'\nCHANGED_NAME_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的岛屿名称修改为了 {1}&7.'\nCHANGED_NAME_OTHER_NAME: '&e&l岛屿 | &7你将岛屿 {0}&7 的名称修改为了 {1}&7.'\nCHANGED_PAYPAL: '&e&l岛屿 | &7成功将岛屿的 Paypal 支付链接修改为了 {0}.'\nCHANGED_ROLE_LIMIT: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿角色 {0} 的限制.'\nCHANGED_ROLE_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的角色 {0} 限制.'\nCHANGED_ROLE_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的角色 {0} 限制.'\nCHANGED_SPAWNER_RATES: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的刷怪翻倍量.'\nCHANGED_SPAWNER_RATES_ALL: '&e&l升级 | &7成功更新了所有岛屿的刷怪翻倍量.'\nCHANGED_SPAWNER_RATES_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的刷怪翻倍量.'\nCHANGED_TEAM_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的团队限制.'\nCHANGED_TEAM_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的团队限制.'\nCHANGED_TEAM_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的团队限制.'\nCHANGED_TELEPORT_LOCATION: '&e&l岛屿 | &7成功更新了传送点的位置.'\nCHANGED_WARPS_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的传送点数量限制.'\nCHANGED_WARPS_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的传送点数量限制.'\nCHANGED_WARPS_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的传送点数量限制.'\nCOMMAND_ARGUMENT_ALL_ISLANDS: '*'\nCOMMAND_ARGUMENT_ALL_MATERIALS: '*'\nCOMMAND_ARGUMENT_ALL_MISSIONS: '*'\nCOMMAND_ARGUMENT_ALL_PLAYERS: '*'\nCOMMAND_ARGUMENT_AMOUNT: '数量'\nCOMMAND_ARGUMENT_BIOME: '群系'\nCOMMAND_ARGUMENT_BORDER_COLOR: '边界颜色'\nCOMMAND_ARGUMENT_COMMAND: '命令...'\nCOMMAND_ARGUMENT_DIMENSION: '维度'\nCOMMAND_ARGUMENT_DISCORD: 'discord...'\nCOMMAND_ARGUMENT_EFFECT: '药水效果'\nCOMMAND_ARGUMENT_EMAIL: '邮箱'\nCOMMAND_ARGUMENT_ENTITY: '实体'\nCOMMAND_ARGUMENT_ISLAND_NAME: '岛屿名称'\nCOMMAND_ARGUMENT_ISLAND_ROLE: '岛屿角色'\nCOMMAND_ARGUMENT_LEADER: '领袖'\nCOMMAND_ARGUMENT_LEVEL: '等级'\nCOMMAND_ARGUMENT_LIMIT: '限制'\nCOMMAND_ARGUMENT_MATERIAL: '材料'\nCOMMAND_ARGUMENT_MENU: '菜单名称'\nCOMMAND_ARGUMENT_MESSAGE: '消息...'\nCOMMAND_ARGUMENT_MISSION_CATEGORY: '任务分类'\nCOMMAND_ARGUMENT_MISSION_NAME: '任务名称'\nCOMMAND_ARGUMENT_MODULE_NAME: '模块名称'\nCOMMAND_ARGUMENT_MULTIPLIER: '翻倍卡'\nCOMMAND_ARGUMENT_NAME: '名称'\nCOMMAND_ARGUMENT_NEW_LEADER: '新领袖'\nCOMMAND_ARGUMENT_PAGE: '页码'\nCOMMAND_ARGUMENT_PATH: '路径'\nCOMMAND_ARGUMENT_PERMISSION: '权限'\nCOMMAND_ARGUMENT_PLAYER_NAME: '玩家名称'\nCOMMAND_ARGUMENT_PRIVATE: '私有'\nCOMMAND_ARGUMENT_RATING: '评分'\nCOMMAND_ARGUMENT_ROWS: '行数'\nCOMMAND_ARGUMENT_SCHEMATIC_NAME: '结构名称'\nCOMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air'\nCOMMAND_ARGUMENT_SETTINGS: '设置'\nCOMMAND_ARGUMENT_SIZE: '大小'\nCOMMAND_ARGUMENT_TIME: '事件'\nCOMMAND_ARGUMENT_TITLE_DURATION: '持续时间'\nCOMMAND_ARGUMENT_TITLE_FADE_IN: '淡入时间'\nCOMMAND_ARGUMENT_TITLE_FADE_OUT: '淡出时间'\nCOMMAND_ARGUMENT_UPGRADE_NAME: '升级名称'\nCOMMAND_ARGUMENT_VALUE: '值'\nCOMMAND_ARGUMENT_WARP_NAME: '传送点名称'\nCOMMAND_ARGUMENT_WARP_CATEGORY: '传送点分类'\nCOMMAND_ARGUMENT_WORLD: '世界'\nCOMMAND_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 中使用该命令.'\nCOMMAND_DESCRIPTION_ACCEPT: '接受玩家的邀请.'\nCOMMAND_DESCRIPTION_ADMIN: '使用管理员命令.'\nCOMMAND_DESCRIPTION_ADMIN_ADD: '将玩家添加至岛屿.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: '为指定玩家的岛屿增加银行存款上限.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: '为指定玩家的岛屿增加方块数量上限.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_BONUS: '向指定玩家添加奖励.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: '为指定玩家的岛屿增加合作玩家数量上限.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: '为指定玩家的岛屿提升作物生长速度速率.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: '为指定岛屿添加岛屿效果.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: '为指定岛屿添加实体数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: '为岛屿刷石机增加指定方块生成的百分比.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: '为指定玩家的岛屿增加刷怪掉落物倍率.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SIZE: '提升指定玩家的岛屿大小.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: '为指定玩家的岛屿提升刷怪笼刷怪倍率.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: '为指定玩家的岛屿增加团队上限.'\nCOMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: '为指定玩家的岛屿设置传送点数量上限.'\nCOMMAND_DESCRIPTION_ADMIN_BONUS: '使指定玩家获得奖励.'\nCOMMAND_DESCRIPTION_ADMIN_BYPASS: '切换绕过模式.'\nCOMMAND_DESCRIPTION_ADMIN_CHEST: '打开指定岛屿的仓库.'\nCOMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: '为指定岛屿清除生成器几率.'\nCOMMAND_DESCRIPTION_ADMIN_CLOSE: '将指定岛屿设置为私有.'\nCOMMAND_DESCRIPTION_ADMIN_CMD_ALL: '为指定岛屿上的所有成员执行命令.'\nCOMMAND_DESCRIPTION_ADMIN_COUNT: '检查指定岛屿上的所有方块数量.'\nCOMMAND_DESCRIPTION_ADMIN_DATA: '交互指定玩家或岛屿的持久化数据.'\nCOMMAND_DESCRIPTION_ADMIN_DEBUG: '切换调试模式.'\nCOMMAND_DESCRIPTION_ADMIN_DEL_WARP: '删除指定岛屿的传送点.'\nCOMMAND_DESCRIPTION_ADMIN_DEMOTE: '将岛屿中的指定玩家升职.'\nCOMMAND_DESCRIPTION_ADMIN_DEPOSIT: '向指定岛屿的银行中存款.'\nCOMMAND_DESCRIPTION_ADMIN_DISBAND: '永久解散指定岛屿.'\nCOMMAND_DESCRIPTION_ADMIN_FLY: '切换指定玩家的岛屿飞行.'\nCOMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: '使指定玩家从其团队中解散.'\nCOMMAND_DESCRIPTION_ADMIN_IGNORE: '将指定岛屿设置为不参与排行榜排名.'\nCOMMAND_DESCRIPTION_ADMIN_JOIN: '强制加入岛屿.'\nCOMMAND_DESCRIPTION_ADMIN_KICK: '将指定玩家从其岛屿中踢出.'\nCOMMAND_DESCRIPTION_ADMIN_MODULES: '管理插件模块.'\nCOMMAND_DESCRIPTION_ADMIN_MISSION: '修改指定玩家的任务状态.'\nCOMMAND_DESCRIPTION_ADMIN_MSG: '向玩家发送不带前缀的消息.'\nCOMMAND_DESCRIPTION_ADMIN_MSG_ALL: '向岛屿上的所有玩家发送不带前缀的消息.'\nCOMMAND_DESCRIPTION_ADMIN_NAME: '修改指定岛屿的名称.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN: '将指定岛屿设置为公开状态.'\nCOMMAND_DESCRIPTION_ADMIN_OPEN_MENU: '为指定玩家打开自定义菜单.'\nCOMMAND_DESCRIPTION_ADMIN_PROMOTE: '将岛屿中的指定玩家升职.'\nCOMMAND_DESCRIPTION_ADMIN_PURGE: '转化岛屿.'\nCOMMAND_DESCRIPTION_ADMIN_RANKUP: '为指定岛屿提升等级.'\nCOMMAND_DESCRIPTION_ADMIN_RECALC: '重新计算指定岛屿的价值.'\nCOMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: '去除指定岛屿的实体数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: '重置指定岛屿的所有权限.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: '重置指定岛屿的所有设置.'\nCOMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.'\nCOMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: '设置指定玩家的岛屿银行存款上限.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BIOME: '设置指定岛屿的生物群系.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: '设置指定位置的方块数量.'\nCOMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: '设置指定岛屿的方块数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: '设置指定岛屿的仓库容量.'\nCOMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: '设置指定岛屿的合作玩家数量.'\nCOMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: '设置指定岛屿的作物生长倍率.'\nCOMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: '设置岛屿解散所需玩家数量.'\nCOMMAND_DESCRIPTION_ADMIN_SET_EFFECT: '设置指定岛屿的效果等级.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: '设置指定岛屿的实体数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: '设置岛屿的预览位置.'\nCOMMAND_DESCRIPTION_ADMIN_SET_LEADER: '将岛屿所有权转移给其他玩家.'\nCOMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: '设置指定岛屿的生物掉落物倍率.'\nCOMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: '设置所有岛屿上的指定权限所需的职位.'\nCOMMAND_DESCRIPTION_ADMIN_SET_RATE: '设置指定玩家的评分.'\nCOMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: '设置指定岛屿的角色限制.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: '为指定岛屿设置角色限制.'\nCOMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: '设置刷石机生成的指定材料几率.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SIZE: '修改指定岛屿的边界大小.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWN: '设置服务器的出生点区域.'\nCOMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: '设置指定岛屿的刷怪笼生成效率.'\nCOMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: '设置指定岛屿的成员数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: '设置指定岛屿的指定功能等级.'\nCOMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: '设置指定岛屿的传送点数量限制.'\nCOMMAND_DESCRIPTION_ADMIN_SETTINGS: '打开插件的设置编辑器.'\nCOMMAND_DESCRIPTION_ADMIN_SHOW: '获取岛屿有关信息.'\nCOMMAND_DESCRIPTION_ADMIN_SPAWN: '传送至出生点.'\nCOMMAND_DESCRIPTION_ADMIN_SPY: '切换聊天窃听模式'\nCOMMAND_DESCRIPTION_ADMIN_STATS: '显示有关插件的信息.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: '同步指定岛屿与指定世界的奖励.'\nCOMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: '同步指定岛屿的升级数值.'\nCOMMAND_DESCRIPTION_ADMIN_TELEPORT: '传送至指定岛屿.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE: '向玩家发送标题消息.'\nCOMMAND_DESCRIPTION_ADMIN_TITLE_ALL: '向指定岛屿的所有成员发送标题消息.'\nCOMMAND_DESCRIPTION_ADMIN_UNIGNORE: '将指定岛屿重新设置为参与排行榜排名.'\nCOMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: '解锁指定岛屿的世界.'\nCOMMAND_DESCRIPTION_ADMIN_WITHDRAW: '从指定岛屿的银行中取款.'\nCOMMAND_DESCRIPTION_BALANCE: '检查指定岛屿银行中的存款.'\nCOMMAND_DESCRIPTION_BAN: '将指定玩家从你的岛屿上封禁.'\nCOMMAND_DESCRIPTION_BANK: '打开岛屿银行.'\nCOMMAND_DESCRIPTION_BANS: '打开封禁菜单.'\nCOMMAND_DESCRIPTION_BIOME: '更换岛屿生物群系.'\nCOMMAND_DESCRIPTION_BORDER: '更换岛屿边界颜色.'\nCOMMAND_DESCRIPTION_CHEST: '打开岛屿仓库.'\nCOMMAND_DESCRIPTION_CLOSE: '将岛屿设置为不对外开放.'\nCOMMAND_DESCRIPTION_COOP: '将指定玩家添加为合作伙伴.'\nCOMMAND_DESCRIPTION_COOPS: '打开合作玩家菜单.'\nCOMMAND_DESCRIPTION_COUNTS: '查看岛屿中的方块限制.'\nCOMMAND_DESCRIPTION_CREATE: '创建一个新的岛屿.'\nCOMMAND_DESCRIPTION_DEL_WARP: '删除指定的岛屿传送点.'\nCOMMAND_DESCRIPTION_DEMOTE: '降职岛屿中的指定玩家.'\nCOMMAND_DESCRIPTION_DEPOSIT: '从你的个人钱包中将钱转入岛屿银行.'\nCOMMAND_DESCRIPTION_DISBAND: '永久解散岛屿.'\nCOMMAND_DESCRIPTION_EXPEL: '踢出岛屿上的指定参观者.'\nCOMMAND_DESCRIPTION_FLY: '切换岛屿飞行.'\nCOMMAND_DESCRIPTION_HELP: '列出所有命令.'\nCOMMAND_DESCRIPTION_INVITE: '将指定玩家邀请至你的岛屿.'\nCOMMAND_DESCRIPTION_KICK: '将指定玩家从你的岛屿踢出.'\nCOMMAND_DESCRIPTION_LANG: '修改你所使用的语言.'\nCOMMAND_DESCRIPTION_LEAVE: '离开你的岛屿.'\nCOMMAND_DESCRIPTION_MEMBERS: '打开成员菜单.'\nCOMMAND_DESCRIPTION_MISSION: '完成任务.'\nCOMMAND_DESCRIPTION_MISSIONS: '打开任务菜单.'\nCOMMAND_DESCRIPTION_NAME: '修改岛屿的名称.'\nCOMMAND_DESCRIPTION_OPEN: '将岛屿设置为对外开放.'\nCOMMAND_DESCRIPTION_PANEL: '打开岛屿控制界面.'\nCOMMAND_DESCRIPTION_PARDON: '解除对指定玩家的岛屿封禁.'\nCOMMAND_DESCRIPTION_PERMISSIONS: '获取指定岛屿职位的所有权限.'\nCOMMAND_DESCRIPTION_PROMOTE: '升职岛屿中的指定成员.'\nCOMMAND_DESCRIPTION_RANKUP: '提升指定功能的等级.'\nCOMMAND_DESCRIPTION_RATE: '为指定岛屿评分.'\nCOMMAND_DESCRIPTION_RATINGS: '显示所有岛屿评分.'\nCOMMAND_DESCRIPTION_SETTINGS: '打开设置菜单.'\nCOMMAND_DESCRIPTION_RECALC: '重新计算岛屿价值.'\nCOMMAND_DESCRIPTION_SET_DISCORD: '设置岛屿成员使用的 Discord 聊天群组.'\nCOMMAND_DESCRIPTION_SET_PAYPAL: '设置岛屿成员使用的 Paypal 聊天群组.'\nCOMMAND_DESCRIPTION_SET_ROLE: '更换指定玩家的职位.'\nCOMMAND_DESCRIPTION_SET_TELEPORT: '修改岛屿的传送点位置.'\nCOMMAND_DESCRIPTION_SET_WARP: '创建一个新的岛屿传送点.'\nCOMMAND_DESCRIPTION_SHOW: '获取指定岛屿的信息.'\nCOMMAND_DESCRIPTION_TEAM: '获取指定岛屿的成员信息.'\nCOMMAND_DESCRIPTION_TEAM_CHAT: 'T切换聊天模式.'\nCOMMAND_DESCRIPTION_TELEPORT: '传送至你的岛屿.'\nCOMMAND_DESCRIPTION_TOGGLE: '切换岛屿边界和方块堆叠放置模式.'\nCOMMAND_DESCRIPTION_TOP: '打开岛屿设置界面.'\nCOMMAND_DESCRIPTION_TRANSFER: '转移岛屿拥有权.'\nCOMMAND_DESCRIPTION_UNCOOP: '移除岛屿中指定玩家的成员关系.'\nCOMMAND_DESCRIPTION_UPGRADE: '打开升级界面.'\nCOMMAND_DESCRIPTION_VALUE: '获取指定方块的价值.'\nCOMMAND_DESCRIPTION_VALUES: '打开价值菜单.'\nCOMMAND_DESCRIPTION_VISIT: '传送至岛屿的访客传送点.'\nCOMMAND_DESCRIPTION_VISITORS: '打开岛屿访客菜单.'\nCOMMAND_DESCRIPTION_WARP: '传送至岛屿的指定传送点.'\nCOMMAND_DESCRIPTION_WARPS: '打开岛屿传送点菜单.'\nCOMMAND_DESCRIPTION_WITHDRAW: '从岛屿银行中取出指定数额的硬币至你的钱包.'\nCOMMAND_USAGE: '&c用法: /{0}'\nCOOP_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 添加为了合作成员.'\nCOOP_BANNED_PLAYER: '&c&l错误 | &7该玩家已被该岛屿封禁, 不可成为该岛屿的合作成员.'\nCOOP_LIMIT_EXCEED: '&c&l错误 | &7该岛屿已达到了可设置的合作成员的最大数量.'\nCREATE_ISLAND: '&e&l岛屿 | &7成功在 {0} 位置创建了岛屿, 耗时 {1}ms.'\nCREATE_ISLAND_FAILURE: '&c&l错误 | &7创建岛屿时遇到未知错误. 请联系服务器管理员以排查该问题.'\nCREATE_WORLD_FAILURE: '&c&l错误 | &7创建你的世界时遇到位置错误. 请联系服务器管理员以排查该问题.'\nDEBUG_MODE_DISABLED: '&e&lDebug | &7调试模式已 &c关闭&7.'\nDEBUG_MODE_ENABLED: '&e&lDebug | &7调试模式 &a开启&7.'\nDEBUG_MODE_FILTER_ADD: '&e&lDebug | &7调试模式过滤 {0} 已 &a开启&7.'\nDEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7所有调试模式过滤已 &c关闭&7.'\nDEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7调试模式过滤 {0} 已 &c关闭&7.'\nDELETE_WARP: '&e&l岛屿 | &7你删除了传送点 {0}.'\nDELETE_WARP_SIGN_BROKE: '&7&o检测到有木牌绑定了该传送点, 将会自动失效...'\nDEMOTE_LEADER: '&c&l错误 | &7你不能降级岛屿领袖.'\nDEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能降级角色职位低于你的玩家.'\nDEMOTED_MEMBER: '&e&l岛屿 | &7你将岛屿中的玩家 {0} 降级为了 {1}.'\nDEPOSIT_ANNOUNCEMENT: '&e&l银行 | &7{0} 向岛屿银行存入了 ${1} !'\nDEPOSIT_ERROR: '&c&l错误 | &7{0}.'\nDESTROY_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外破坏.'\nDISBAND_ANNOUNCEMENT: '&e&l岛屿 | &7你的岛屿已经被玩家 {0} 解散.'\nDISBAND_GIVE: '&e&l岛屿 | &7你收到了 {0} 个解散.'\nDISBAND_GIVE_ALL: '&e&l岛屿 | &7你对所有玩家进行了 {0} 个解散.'\nDISBAND_GIVE_OTHER: '&e&l岛屿 | &7你将 {0} 个解散给予了玩家 {1}.'\nDISBAND_ISLAND_BALANCE_REFUND: '&7&o你的岛屿已被解散, 根据岛屿银行的存款记录, 你已被退还 ${0}'\nDISBAND_SET: '&e&l岛屿 | &7你的解散数量已被设置为 {0}.'\nDISBAND_SET_ALL: '&e&l岛屿 | &7你将所有玩家的解散数量设置为了 {0}.'\nDISBAND_SET_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的解散数量设置为了 {1}.'\nDISBANDED_ISLAND: '&e&l岛屿 | &7你解散了你的岛屿.'\nDISBANDED_ISLAND_OTHER: '&e&l岛屿 | &7你解散了玩家 {0} 的岛屿.'\nDISBANDED_ISLAND_OTHER_NAME: '&e&l岛屿 | &7你解散了岛屿 {0}.'\nENTER_PVP_ISLAND: '&7&o你被传送至了开启了 PVP 的岛屿. 接下来的 10 秒内你将处于无敌状态...'\nEXPELLED_PLAYER: '&e&l岛屿 | &7{0} 已从该岛屿被开除.'\nFORMAT_QUAD: 'Q'\nFORMAT_TRILLION: 'T'\nFORMAT_BILLION: 'B'\nFORMAT_MILLION: 'M'\nFORMAT_THOUSANDS: 'K'\nFORMAT_SECONDS_NAME: '秒'\nFORMAT_SECOND_NAME: '秒'\nFORMAT_MINUTES_NAME: '分'\nFORMAT_MINUTE_NAME: '分'\nFORMAT_HOURS_NAME: '时'\nFORMAT_HOUR_NAME: '时'\nFORMAT_DAYS_NAME: '天'\nFORMAT_DAY_NAME: '天'\nGENERATOR_CLEARED: '&e&l岛屿 | &7成功清除了玩家 {0} 的岛屿上的所有生成器.'\nGENERATOR_CLEARED_NAME: '&e&l岛屿 | &7成功清除了岛屿 {0} 上的所有生成器.'\nGENERATOR_CLEARED_ALL: '&e&l岛屿 | &7成功清除了所有岛屿上的所有生成器.'\nGENERATOR_UPDATED: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿上的 {0} 生成器数量 .'\nGENERATOR_UPDATED_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 上的 {0} 生成器数量.'\nGENERATOR_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿上的 {0} 生成器数量.'\nGLOBAL_COMMAND_EXECUTED: '&e&l岛屿 | &7成功为玩家 {0} 的岛屿成员执行了命令!'\nGLOBAL_COMMAND_EXECUTED_NAME: '&e&l岛屿 | &7成功为岛屿 {0} 上的所有成员执行了命令!'\nGLOBAL_MESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送至玩家 {0} 岛屿上的所有成员!'\nGLOBAL_MESSAGE_SENT_NAME: '&e&l岛屿 | &7成功将消息发送至岛屿 {0} 上的所有成员!'\nGLOBAL_TITLE_SENT: '&e&l岛屿 | &7成功将标题消息发送至玩家 {0} 岛屿上的所有成员!'\nGLOBAL_TITLE_SENT_NAME: '&e&l岛屿 | &7成功将标题消息发送至岛屿 {0} 上的所有成员!'\nGOT_BANNED: '&e&l岛屿 | &7你已被玩家 {0} 的岛屿封禁.'\nGOT_DEMOTED: '&e&l岛屿 | &7你在你的岛屿中被降职为 {0} 角色.'\nGOT_EXPELLED: '&e&l岛屿 | &7&o你已被岛屿 {0} 开除.'\nGOT_INVITE: '&e&l岛屿 | &7{0} 邀请了你至他的岛屿.'\nGOT_INVITE_TOOLTIP: '&7点击该消息来同意请求.'\nGOT_KICKED: '&e&l岛屿 | &7你被玩家 {0} 踢出了岛屿.'\nGOT_PROMOTED: '&e&l岛屿 | &7你在你的岛屿中被升职为 {0} 角色.'\nGOT_REVOKED: '&e&l岛屿 | &7{0} 撤回了对你的邀请.'\nGOT_UNBANNED: '&e&l岛屿 | &7你已从岛屿 {0} 被解除封禁.'\nHIT_ISLAND_MEMBER: '&c&l错误 | &7你不能攻击你的岛屿成员.'\nHIT_PLAYER_IN_ISLAND: '&c&l错误 | &7你不能攻击岛屿内的成员.'\nIGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已不参与排行榜计算.'\nIGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已不参与岛屿排行榜计算.'\nINTERACT_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外进行交互.'\nINVALID_AMOUNT: '&c&l错误 | &7无效数量 {0}.'\nINVALID_BIOME: '&c&l错误 | &7无效生物群系 {0}.'\nINVALID_BLOCK: '&c&l错误 | &7无效方块位置 {0}.'\nINVALID_BORDER_COLOR: '&c&l错误 | &7无效边界颜色 {0}.'\nINVALID_COMMAND: '&c&l错误 | &7无效命令 {0}.'\nINVALID_EFFECT: '&c&l错误 | &7无效效果 {0}.'\nINVALID_ENTITY: '&c&l错误 | &7无效实体 {0}.'\nINVALID_ENVIRONMENT: '&c&l错误 | &7无效维度 {0}.'\nINVALID_INTERVAL: '&c&l错误 | &7无效间隔 {0}.'\nINVALID_ISLAND: '&c&l错误 | &7你没有岛屿.'\nINVALID_ISLAND_LOCATION: '&c&l错误 | &7你当前位置没有岛屿.'\nINVALID_ISLAND_OTHER: '&c&l错误 | &7{0} 没有岛屿.'\nINVALID_ISLAND_OTHER_NAME: '&c&l错误 | &7找不到名称为 {0} 的岛屿.'\nINVALID_ISLAND_PERMISSION: |\n  &c&l错误 | &7找不到岛屿权限 {0}.\n  &c&l错误 | &7岛屿权限: {1}\nINVALID_LEVEL: '&c&l错误 | &7无效等级 {0}.'\nINVALID_LIMIT: '&c&l错误 | &7无效限制 {0}.'\nINVALID_MATERIAL: '&c&l错误 | &7无效材料名 {0}.'\nINVALID_MATERIAL_DATA: '&c&l错误 | &7无效材料数据 {0}.'\nINVALID_MENU: '&c&l错误 | &7无效菜单 {0}.'\nINVALID_MISSION: '&c&l错误 | &7无效任务 {0}.'\nINVALID_MISSION_CATEGORY: '&c&l错误 | &7无效任务分类 {0}.'\nINVALID_MODULE: '&c&l错误 | &7无效模块 {0}.'\nINVALID_MULTIPLIER: '&c&l错误 | &7无效翻倍 {0}.'\nINVALID_PAGE: '&c&l错误 | &7无效页码 {0}.'\nINVALID_PERCENTAGE: '&c&l错误 | &7百分比数值必须介于 0 和 100.'\nINVALID_PLAYER: '&c&l错误 | &7找不到名为 {0} 的玩家'\nINVALID_RATE: |\n  &c&l错误 | &7找不到名为 {0} 的评分.\n  &c&l错误 | &7岛屿评分: {1}\nINVALID_ROWS: '&c&l错误 | &7无效行数: {0}'\nINVALID_ROLE: |\n  &c&l错误 | &7找不到名为 {0} 的角色.\n  &c&l错误 | &7岛屿角色: {1}\nINVALID_SCHEMATIC: '&c&l错误 | &7找不到名为 {0} 的结构文件.'\nINVALID_SETTINGS: |\n  &c&l错误 | &7找不到名为 {0} 的岛屿设置.\n  &c&l错误 | &7岛屿设置: {1}\nINVALID_SIZE: '&c&l错误 | &7无效大小 {0}.'\nINVALID_SLOT: '&c&l错误 | &7无效位置 {0}.'\nINVALID_TITLE: '&c&l错误 | &7输入的标题信息无效.'\nINVALID_TOGGLE_MODE: '&c&l错误 | &7不能切换模式 {0}.'\nINVALID_UPGRADE: |\n  &c&l错误 | &7找不到名为 {0} 的可升级功能.\n  &c&l错误 | &7可升级功能: {1}\nINVALID_VISIT_LOCATION: '&c&l错误 | &7该岛屿没有访客传送位置.'\nINVALID_VISIT_LOCATION_BYPASS: '&7&o你开启了岛屿绕过保护模式, 正在为你传送至该岛屿...'\nINVALID_WARP: '&c&l错误 | &7无效传送点 {0}.'\nINVALID_WORLD: '&c&l错误 | &7I无效世界 {0}.'\nINVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 邀请至了岛屿.'\nINVITE_BANNED_PLAYER: '&c&l错误 | &7该玩家已从岛屿被封禁, 不可接受任何邀请.'\nINVITE_TO_FULL_ISLAND: '&c&l错误 | &7你不能再向岛屿邀请更多成员了.'\nISLAND_ALREADY_CLOSED: '&c&l错误 | &7该岛屿已经设置为不对公众开放了.'\nISLAND_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的岛屿.'\nISLAND_ALREADY_OPENED: '&c&l错误 | &7该岛屿已经设置为对公众开放了.'\nISLAND_BANK_EMPTY: '&e&l银行 | &7岛屿银行中没有存款.'\nISLAND_BANK_SHOW: '&e&l银行 | &7你的岛屿银行存款为 ${0}.'\nISLAND_BANK_SHOW_OTHER: '&e&l银行 | &7玩家 {0} 的岛屿银行存款为 ${1}.'\nISLAND_BANK_SHOW_OTHER_NAME: '&e&l银行 | &7岛屿 {0} 的银行存款为 ${1}.'\nISLAND_BEING_CALCULATED: '&c&l错误 | &7正在进行计算, 不可以与方块交互!'\nISLAND_CLOSED: '&e&l岛屿 | &7成功将岛屿设置为不对公众开放.'\nISLAND_CREATE_PROCESS_FAIL: '&c&l错误 | &7你已经有一个正在进行的岛屿创建进程了.'\nISLAND_CREATE_PROCCESS_REQUEST: '&e&l岛屿 | &7正在处理你的请求...'\nISLAND_DESCRIPTION_NONE: None\nISLAND_FLY_DISABLED: '&e&l飞行 | &7岛屿飞行已自动 &c关闭&7.'\nISLAND_FLY_ENABLED: '&e&l飞行 | &7岛屿飞行已自动 &a打开&7.'\nISLAND_GOT_DELETED_WHILE_INSIDE: '&e&l岛屿 | &7&o你正处于一个被解散的岛屿, 正在将你传送回主城...'\nISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&l岛屿 | &7&o你正处于一个开启了 PVP 的岛屿, 正在将你传送回主城...'\nISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock&7, 由 Ome_R 开发'\nISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7命令列表 [{0}/{1}]:'\nISLAND_HELP_LINE: '&e/{0} &f- &7{1}'\nISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7使用 /is help {0} 来翻到下一页.'\nISLAND_INFO_ADMIN_BANK_LIMIT: '&e&l岛屿 | &7银行限制: {0}'\nISLAND_INFO_ADMIN_BLOCKS_LIMITS: |\n  &e&l岛屿 | &7方块限制:\n  {0}\nISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&l岛屿 | &7  {0}: {1}'\nISLAND_INFO_ADMIN_COOP_LIMIT: '&e&l岛屿 | &7合作成员数量限制: {0}'\nISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&l岛屿 | &7作物生长速率: {0}'\nISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&l岛屿 | &7掉落物翻倍: {0}'\nISLAND_INFO_ADMIN_ISLAND_EFFECTS: |\n  &e&l岛屿 | &7岛屿效果:\n  {0}\nISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&l岛屿 | &7  {0}: {1}'\nISLAND_INFO_ADMIN_ENTITIES_LIMITS: |\n  &e&l岛屿 | &7实体限制:\n  {0}\nISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&l岛屿 | &7  {0}: {1}'\nISLAND_INFO_ADMIN_GENERATOR_RATES: |\n  &e&l岛屿 | &7刷怪比率 ({1}):\n  {0}\nISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&l岛屿 | &7  {0}: {1}% ({2})'\nISLAND_INFO_ADMIN_ROLE_LIMITS: |\n  &e&l岛屿 | &7角色限制:\n  {0}\nISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&l岛屿 | &7  {0}: {1}'\nISLAND_INFO_ADMIN_SIZE: '&e&l岛屿 | &7边界大小: {0}'\nISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&l岛屿 | &7刷怪笼生成倍率: {0}'\nISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&l岛屿 | &7团队限制: {0}'\nISLAND_INFO_ADMIN_UPGRADES: |\n  &e&l岛屿 | &7功能升级:\n  {0}\nISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&l岛屿 | &7  {0}: {1}'\nISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞'\nISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&l岛屿 | &7传送点限制: {0}'\nISLAND_INFO_BANK: '&e&l岛屿 | &7银行: {0}'\nISLAND_INFO_BONUS: '&e&l岛屿 | &7价值奖励: {0}'\nISLAND_INFO_BONUS_LEVEL: '&e&l岛屿 | &7等级奖励: {0}'\nISLAND_INFO_CREATION_TIME: '&e&l岛屿 | &7创建时间: {0}'\nISLAND_INFO_DISCORD: '&e&l岛屿 | &7Discord: {0}'\nISLAND_INFO_FOOTER: ''\nISLAND_INFO_HEADER: ''\nISLAND_INFO_LAST_TIME_UPDATED: '&e&l岛屿 | &7最后更新: {0} 前'\nISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&l岛屿 | &7最后更新: &a正在活跃'\nISLAND_INFO_LEVEL: '&e&l岛屿 | &7等级: {0}'\nISLAND_INFO_LOCATION: '&e&l岛屿 | &7家: {0}'\nISLAND_INFO_NAME: '&e&l岛屿 | &7名称: {0}'\nISLAND_INFO_OWNER: '&e&l岛屿 | &7领袖: {0}'\nISLAND_INFO_PAYPAL: '&e&l岛屿 | &7Paypal: {0}'\nISLAND_INFO_PLAYER_LINE: '&e&l岛屿 | &7 - {0}'\nISLAND_INFO_RATE: '&e&l岛屿 | &7评分: {0} &7({1}/5) - 共 {2} 个评分.'\nISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧'\nISLAND_INFO_RATE_SYMBOL: '✦'\nISLAND_INFO_RATE_ONE_COLOR: '&4'\nISLAND_INFO_RATE_TWO_COLOR: '&6'\nISLAND_INFO_RATE_THREE_COLOR: '&e'\nISLAND_INFO_RATE_FOUR_COLOR: '&a'\nISLAND_INFO_RATE_FIVE_COLOR: '&2'\nISLAND_INFO_ROLES: |\n  &e&l岛屿 | &7{0}s:\n  {1}\nISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0} ({1} 位独立访客)'\nISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}'\nISLAND_NAME_NONE: None\nISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.'\nISLAND_OWNER_NONE: None\nISLAND_PREVIEW_BLOCK_COMMAND: '&c&l错误 | &7你不能在预览模式中使用该命令.'\nISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动退出预览模式.'\nISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.'\nISLAND_PREVIEW_CONFIRM_TEXT: '确认'\nISLAND_PREVIEW_CANCEL_TEXT: '取消'\nISLAND_PREVIEW_SET: '&e&l预览 | &7成功将结构 {0} 的预览位置设置为 {1}.'\nISLAND_PREVIEW_START: |\n  &e&l结构 | &7你正在预览结构 {0}.\n  &e&l结构 | &7输入 &a&lCONFIRM &7来创建一个新岛屿, 或 &c&lCANCEL &7取消预览模式.\n  &e&l结构 | &7你不能离开该岛屿的区域, 否则将会自动退出岛屿预览.\nISLAND_PROTECTED: '&c&l错误 | &7该岛屿受到保护.'\nISLAND_PROTECTED_OPPED: '&7&o你可通过输入命令 \"/is admin bypass\" 来绕过该限制.'\nISLAND_TEAM_STATUS_FOOTER: ''\nISLAND_TEAM_STATUS_HEADER: '&e&l岛屿 | &7成员 {0} 的岛屿 &8[&e{1}&8/&e{2}&8]&7:'\nISLAND_TEAM_STATUS_OFFLINE: '&c(离线)'\nISLAND_TEAM_STATUS_ONLINE: '&a(在线)'\nISLAND_TEAM_STATUS_ROLES: '&e&l岛屿 | &7 * [{0}] {1} {2} &7({3})'\nISLAND_TOP_STATUS_OFFLINE: '&c(离线)'\nISLAND_TOP_STATUS_ONLINE: '&a(在线)'\nISLAND_WARP_PUBLIC: ''\nISLAND_WARP_PRIVATE: '&c[私有]'\nISLAND_WAS_CLOSED: '&e&l岛屿 | &7&o你所处的岛屿已关闭, 你已被自动传送回主城...'\nISLAND_WORTH_ERROR: '&c&l错误 | &7进行岛屿计算时出现错误. 若问题持续出现请尝试联系管理员.'\nISLAND_WORTH_RESULT: '&e&l岛屿 | &7你的岛屿价值为 {0} [等级 {1}]'\nISLAND_WORTH_TIME_OUT: '&c&l错误 | &7计算超时. 稍后再试...'\nJOIN_ADMIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了你的岛屿.'\nJOIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了你的岛屿.'\nJOIN_FULL_ISLAND: '&c&l错误 | &7该岛屿成员数量已达上限.'\nJOIN_WHILE_IN_ISLAND: '&c&l错误 | &7你已经处于一个岛屿中了.'\nJOINED_ISLAND: '&e&l岛屿 | &7你加入了 {0} 的岛屿.'\nJOINED_ISLAND_NAME: '&e&l岛屿 | &7你加入了岛屿 {0}.'\nJOINED_ISLAND_AS_COOP: '&e&l岛屿 | &7你现在是玩家 {0} 的岛屿合作成员.'\nJOINED_ISLAND_AS_COOP_NAME: '&e&l岛屿 | &7你现在是岛屿 {0} 的合作成员.'\nKICK_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 被玩家 {1} 从岛屿中踢出.'\nKICK_ISLAND_LEADER: '&c&l错误 | &7你不能踢出岛屿的领袖, 若要如此请输入命令 /is admin disband instead.'\nKICK_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能踢出角色职位低于你的玩家.'\nLACK_CHANGE_PERMISSION: '&c&l错误 | &7你必须拥有更改其他成员职位的权限.'\nLAST_ROLE_DEMOTE: '&c&l错误 | &7你不能再对该玩家降职了.'\nLAST_ROLE_PROMOTE: '&c&l错误 | &7你不能再对该玩家升职了.'\nLEAVE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了岛屿.'\nLEAVE_ISLAND_AS_LEADER: |-\n  &c&l错误 | &7你不能离开你拥有的岛屿.\n  &c&l错误 | &7你可以使用命令 /is transfer 转移岛屿拥有权.\nLEFT_ISLAND: '&e&l岛屿 | &7你离开了你的岛屿.'\nLEFT_ISLAND_COOP: '&e&l岛屿 | &7你不再是玩家 {0} 的岛屿合作成员.'\nLEFT_ISLAND_COOP_NAME: '&e&l岛屿 | &7你不再是岛屿 {0} 的合作成员.'\nLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿锁定!'\nLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 锁定!'\nLOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿锁定!'\nMATERIAL_NOT_SOLID: '&c&l错误 | &7你必须提供一个固体方块材料名.'\nMAXIMUM_LEVEL: '&c&l错误 | &7该功能的最大等级为 {0}.'\nMESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送给了 {0}!'\nMISSION_CANNOT_COMPLETE: '&c&l错误 | &7你现在还不能完成该任务.'\nMISSION_NO_AUTO_REWARD: '&e&l任务 | &7你已拥有了完成任务 {0} 的所有条件 - 使用 /is missions 完成任务并领取奖励!'\nMISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&l错误 | &7你必须在完成该任务之前完成任务 {0}.'\nMISSION_STATUS_COMPLETE: '&e&l任务 | &7成功修改了玩家 {1} 的任务 {0} 状态为完成.'\nMISSION_STATUS_COMPLETE_ALL: '&e&l任务 | &7成功修改了玩家 {0} 的所有任务状态为完成.'\nMISSION_STATUS_RESET: '&e&l任务 | &7成功将玩家 {1} 的任务 {0} 状态重置.'\nMISSION_STATUS_RESET_ALL: '&e&l任务 | &7成功将玩家 {0} 的所有任务状态重置.'\nMODULE_ALREADY_INITIALIZED: '&e&l模块 | &7该模块已载入.'\nMODULE_INFO: |\n  &e&l模块 | &7{0} 作者 {1}\n  &e&l模块 | &7&m--------------------\n  &e&l模块 | &7{2}\nMODULE_LOADED_SUCCESS: '&e&l模块 | &7成功载入了模块 {0}.'\nMODULE_LOADED_FAILURE: '&e&l模块 | &7无法载入模块 {0}. 检查控制台以获得更多信息.'\nMODULE_UNLOADED_SUCCESS: '&e&l模块 | &7成功卸载了模块.'\nMODULES_LIST: '&f模块 ({0}): {1}'\nMODULES_LIST_MODULE_NAME: '&a{0}'\nMODULES_LIST_SEPARATOR: '&f, '\nNAME_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将岛屿名称修改为了 {1}&7.'\nNAME_ANNOUNCEMENT_OTHER: '&e&l岛屿 | &7{0} 将玩家 {1} 的岛屿名称修改为了 {2}&7.'\nNAME_ANNOUNCEMENT_OTHER_NAME: '&e&l岛屿 | &7{0} 将岛屿 {1}&7 的名称修改为了 {2}&7.'\nNAME_BLACKLISTED: '&c&l错误 | &7你不能使用该名称.'\nNAME_CHAT_FORMAT: '&8[&e{0}&8] &r'\nNAME_SAME_AS_PLAYER: '&c&l错误 | &7你不能将玩家名称作为岛屿名称.'\nNAME_TOO_LONG: '&c&l错误 | &7岛屿名称不能超过 {0} 个字符.'\nNAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 {0} 个字符.'\nNO_BAN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可封禁玩家.'\nNO_CLOSE_BYPASS: '&c&l错误 | &7该岛屿不对公众开放.'\nNO_CLOSE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.'\nNO_COMMAND_PERMISSION: '&c&l错误 | &7你没有权限使用该命令. ({0})'\nNO_COOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家添加为合作成员.'\nNO_DELETE_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可删除传送点.'\nNO_DEMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可降职玩家.'\nNO_DEPOSIT_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可向岛屿银行存款.'\nNO_DISBAND_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可解散你的岛屿.'\nNO_EXPEL_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可从岛屿中开除玩家.'\nNO_INVITE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可邀请玩家.'\nNO_ISLAND_CHEST_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可打开岛屿仓库.'\nNO_ISLAND_INVITE: '&c&l错误 | &7找不到任何该岛屿的请求.'\nNO_ISLANDS_TO_PURGE: '&c&l错误 | &7没有可清除的岛屿.'\nNO_KICK_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可踢出玩家.'\nNO_MORE_DISBANDS: '&c&l错误 | &7你不能再解散更多岛屿了.'\nNO_MORE_WARPS: '&c&l错误 | &7你的岛屿不能拥有更多传送点了.'\nNO_NAME_PERMISSION: '&c&l错误 | &7你不能修改岛屿的名称.'\nNO_OPEN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.'\nNO_PERMISSION_CHECK_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可获取权限的有关信息.'\nNO_PROMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可升职玩家.'\nNO_RANKUP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可提升功能等级.'\nNO_RATINGS_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可浏览评分.'\nNO_SET_BIOME_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿生物群系.'\nNO_SET_DISCORD_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿的 Discord.'\nNO_SET_HOME_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置岛屿的传送位置.'\nNO_SET_PAYPAL_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿的 Paypal 邮箱.'\nNO_SET_ROLE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置玩家的角色.'\nNO_SET_SETTINGS_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿设置.'\nNO_SET_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置岛屿传送点.'\nNO_TRANSFER_PERMISSION: '&c&l错误 | &7你必须为岛屿的领袖才可转移拥有权.'\nNO_UNCOOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家的合作成员身份去除.'\nNO_UPGRADE_PERMISSION: '&c&l错误 | &7你缺少升级该功能的权限.'\nNO_WITHDRAW_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可从岛屿银行中取出存款.'\nNOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&l错误 | &7你没有足够的钱将 ${0} 存入岛屿银行.'\nNOT_ENOUGH_MONEY_TO_UPGRADE: '&c&l错误 | &7你没有足够的钱.'\nNOT_ENOUGH_MONEY_TO_WARP: '&c&l错误 | &7你没有足够的钱使用岛屿传送点.'\nOPEN_MENU_WHILE_SLEEPING: '&7&o你太累了, 不能和菜单交易, 你不这么觉得嘛?'\nPANEL_TOGGLE_OFF: |-\n  &e&lPanel | &7岛屿控制面板已 &c关闭&7.\n  &e&lPanel | &7输入命令 /is 将会把你传送回岛屿.\nPANEL_TOGGLE_ON: |-\n  &e&lPanel | &7岛屿控制面板已 &a开启&7.\n  &e&lPanel | &7输入命令 /is 将会打开岛屿控制面板.\nPERMISSION_CHANGED: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿的权限 {0}.'\nPERMISSION_CHANGED_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的权限 {0}.'\nPERMISSION_CHANGED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的权限 {0}.'\nPERSISTENT_DATA_EMPTY: '&c&l错误 | &7请求中未找到你所需要的数据.'\nPERSISTENT_DATA_MODIFY: '&e&l数据 | &7成功将 {0} 的数据 {1} 值设置为了: {2}'\nPERSISTENT_DATA_SHOW: '&e&l数据 | &7{0} 的数据值: &f{{1}}'\nPERSISTENT_DATA_SHOW_PATH: '&b{0}&f: '\nPERSISTENT_DATA_SHOW_SPACER: '&f, '\nPERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f'\nPERSISTENT_DATA_REMOVED: '&e&l数据 | &7成功删除了路径 {1} 下的数据 {0}.'\nPERMISSIONS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿所有权限重置为默认值!'\nPERMISSIONS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有权限重置为默认值!'\nPERMISSIONS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有权限重置为默认值!'\nPERMISSIONS_RESET_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 的权限重置回默认状态!'\nPERMISSIONS_RESET_ROLES: '&e&l岛屿 | &7成功将该岛屿上的所有权限重置为默认状态!'\nPLACEHOLDER_NO: '否'\nPLACEHOLDER_YES: '是'\nPLAYER_ALREADY_BANNED: '&c&l错误 | &7该玩家已被封禁.'\nPLAYER_ALREADY_COOP: '&c&l错误 | &7该玩家已为合作成员.'\nPLAYER_ALREADY_IN_ISLAND: '&c&l错误 | &7该玩家已经属于一个岛屿.'\nPLAYER_ALREADY_IN_ROLE: '&c&l错误 | &7{0} 的职位已为 {1}.'\nPLAYER_EXPEL_BYPASS: '&c&l错误 | &7该玩家不能从岛上被开除.'\nPLAYER_JOIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了服务器.'\nPLAYER_NOT_BANNED: '&c&l错误 | &7该玩家尚未被封禁.'\nPLAYER_NOT_COOP: '&c&l错误 | &7该玩家不是合作成员.'\nPLAYER_NOT_INSIDE_ISLAND: '&c&l错误 | &7该玩家不在你的岛屿内.'\nPLAYER_NOT_ONLINE: '&c&l错误 | &7该玩家不在线!'\nPLAYER_QUIT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了服务器.'\nPROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能升职职位低于你的玩家.'\nPROMOTED_MEMBER: '&e&l岛屿 | &7你将玩家 {0} 的职位提升到了 {1}.'\nPURGE_CLEAR: '&e&l岛屿 | &7成功清除了位于队列中的所有岛屿.'\nPURGED_ISLANDS: |-\n  &e&l岛屿 | &7{0} 在服务器重启后将会被删除.\n  &e&l岛屿 | &7可使用命令 /is admin purge cancel 取消清理过程.\nRANKUP_SUCCESS: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿功能 {0} 等级.'\nRANKUP_SUCCESS_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的功能 {0} 等级.'\nRANKUP_SUCCESS_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的功能 {0} 等级.'\nRATE_ALREADY_GIVEN: '&c&l错误 | &7你已经为该岛屿评过分了.'\nRATE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 为你的岛屿评分 {1}, 满分为 5!.'\nRATE_CHANGE_OTHER: '&e&l岛屿 | &7你将 {0} 的评分修改为了 {1}.'\nRATE_OWN_ISLAND: '&c&l错误 | &7你不能对着自己的岛屿评分.'\nRATE_REMOVE_ALL: '&e&l岛屿 | &7成功了删除了岛屿 {0} 的所有评价.'\nRATE_REMOVE_ALL_ISLANDS: '&e&l岛屿 | &7成功删除了所有岛屿的所有评价.'\nREACHED_ENTITY_LIMIT: '&e&l升级 | &7你已到达了最多 {0} 个的实体限制.'\nRATE_SUCCESS: '&e&l岛屿 | &7你对该岛屿给出了 {0} 星的评价!'\nREACHED_BLOCK_LIMIT: '&e&l升级 | &7你已经到达了岛屿 {0} 的放置数量限制.'\nRECALC_ALREADY_RUNNING: '&c&l错误 | &7你的岛屿正在重新计算.'\nRECALC_ALREADY_RUNNING_OTHER: '&c&l错误 | &7该岛屿正在重新计算.'\nRECALC_ALL_ISLANDS: '&e&l岛屿 | &7正在对所有岛屿进行重新计算...'\nRECALC_ALL_ISLANDS_DONE: '&e&l岛屿 | &7成功完成了对所有岛屿的重新计算.'\nRECALC_PROCCESS_REQUEST: '&e&l岛屿 | &7正在处理你的请求...'\nRELOAD_COMPLETED: '&e&l岛屿 | &7重载完毕!'\nRELOAD_PROCCESS_REQUEST: '&e&l岛屿 | &7正在准备重载...'\nREVOKE_INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 撤回了对玩家 {1} 的邀请.'\nRESET_WORLD_SUCCEED: '&e&l岛屿 | &7成功重置了玩家 {1} 的岛屿世界 {0}.'\nRESET_WORLD_SUCCEED_ALL: '&e&l岛屿 | &7成功为所有岛屿重置了世界 {0}.'\nRESET_WORLD_SUCCEED_NAME: '&e&l岛屿 | &7成功为岛屿 {1} 重置了世界 {0}.'\nRESET_SETTINGS: '&e&l岛屿 | &7成功重置了玩家 {0} 的岛屿设置.'\nRESET_SETTINGS_ALL: '&e&l岛屿 | &7成功重置了所有岛屿的设置.'\nRESET_SETTINGS_NAME: '&e&l岛屿 | &7成功重置了岛屿 {0} 的设置.'\nSAME_NAME_CHANGE: '&c&l错误 | &7你必须输入一个不与当前岛屿名称重复的名称.'\nSCHEMATIC_LEFT_SELECT: '&e&l结构 | &7已选中 #2 位点 ({0})'\nSCHEMATIC_NOT_ADDED: '&c&l错误 | &7服务器尚未添加 {0} 的结构文件. 请联系管理员解决此问题. {0} 结构文件的格式为 \"{1}\".'\nSCHEMATIC_NOT_READY: '&c&l错误 | &7你尚未选中两点.'\nSCHEMATIC_PROCCESS_REQUEST: '&e&l结构 | &7正在处理你的请求...'\nSCHEMATIC_READY_TO_CREATE: |\n  &e&l结构 | &7你已选择两个点. 输入命令 /is admin schematic <名称> 可创建一个新的结构.\n  &e&l结构 | &7确保你输入命令时站在了你所需设置的传送点.\nSCHEMATIC_RIGHT_SELECT: '&e&l结构 | &7已选中 #1 位点 ({0})'\nSCHEMATIC_SAVED: '&e&l结构 | &7结构文件成功保存!'\nSELF_ROLE_CHANGE: '&c&l错误 | &7你不能修改自己的职位.'\nSET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0}.'\nSET_UPGRADE_LEVEL_ALL: '&e&l升级 | &7成功更新了所有岛屿的等级 {0}.'\nSET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.'\nSET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.'\nSET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.'\nSETTINGS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿的所有设置重置为默认值!'\nSETTINGS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有设置重置为默认值!'\nSETTINGS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有设置重置为默认值!'\nSETTINGS_RESET_SELF: '&e&l岛屿 | &7成功将该岛屿的所有设置重置为默认值!'\nSETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}.'\nSETTINGS_UPDATED_NAME: '&e&l岛屿 | &7成功修改了岛屿 {1} 的设置 {0}.'\nSETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.'\nSIZE_BIGGER_MAX: '&c&l错误 | &7你不能将大小设置为超出岛屿最大大小的数值.'\nSPAWN_PROTECTED: '&c&l错误 | &7出生点受到保护.'\nSPAWN_PROTECTED_OPPED: '&7&o你可通过输入命令 \"/is admin bypass\" 来绕过该限制.'\nSPAWN_TELEPORT_SUCCESS: '&e&l主城 | &7成功将玩家 {0} 传送至主城.'\nSPAWN_SET_SUCCESS: '&e&l主城 | &7成功将出生点位置设置为了 {0}.'\nSPY_TEAM_CHAT_FORMAT: '&7[窃听] &e[{0}] {1}&f: &7{2}'\nSYNC_UPGRADES: '&e&l升级 | &7成功同步了玩家 {0} 岛屿上所有功能的升级数值.'\nSYNC_UPGRADES_ALL: '&e&l升级 | &7成功同步了岛屿上所有功能的升级数值.'\nSYNC_UPGRADES_NAME: '&e&l升级 | &7成功同步了功能 {0} 的所有数值.'\nTEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}'\nTELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&l错误 | &7你未处于你的岛屿中.'\nTELEPORT_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护区域外进行传送.'\nTELEPORT_WARMUP: '&7&o你将会在 {0} 秒内传送... 请勿移动!'\nTELEPORT_WARMUP_CANCEL: '&7&o待处理的传送请求已取消.'\nTITLE_SENT: '&e&l岛屿 | &7成功向玩家 {0} 发送了标题信息!'\nTELEPORTED_FAILED: '&e&l岛屿 | &7该岛屿似乎不存在安全的落脚点. 请联系管理员.'\nTELEPORTED_SUCCESS: '&e&l岛屿 | &7你已被传送至你的岛屿.'\nTELEPORTED_TO_WARP: '&e&l岛屿 | &7成功传送至了该传送点.'\nTELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&l岛屿 | &7玩家 {0} 传送至了岛屿传送点 {1}.'\nTOGGLED_BYPASS_OFF: '&e&l绕过 | &7绕过模式已 &c关闭&7.'\nTOGGLED_BYPASS_ON: '&e&l绕过 | &7绕过模式已 &a开启&7.'\nTOGGLED_FLY_OFF: '&e&l飞行 | &7岛屿飞行已 &c关闭&7.'\nTOGGLED_FLY_ON: '&e&l飞行 | &7岛屿飞行已 &a开启&7.'\nTOGGLED_FLY_OFF_OTHER: '&e&l飞行 | &7已为 {0} &c关闭&7岛屿飞行.'\nTOGGLED_FLY_ON_OTHER: '&e&l飞行 | &7已为 {0} &a开启&7岛屿飞行.'\nTOGGLED_SCHEMATIC_OFF: '&e&l结构 | &7结构模式已 &c关闭&7.'\nTOGGLED_SCHEMATIC_ON: |-\n  &e&l结构 | &7结构模式已 &a开启&7.\n  &e&l结构 | &7使用金斧圈定选区.\nTOGGLED_SPY_OFF: '&e&l窃听 | &7聊天窃听已 &c关闭&7.'\nTOGGLED_SPY_ON: '&e&l窃听 | &7聊天窃听已 &a开启&7.'\nTOGGLED_STACKED_BLOCKS_OFF: '&e&l堆叠 | &7方块堆叠已 &c关闭&7.'\nTOGGLED_STACKED_BLOCKS_ON: '&e&l堆叠 | &7方块堆叠已 &a开启&7.'\nTOGGLED_TEAM_CHAT_OFF: '&e&l聊天 | &7团队聊天已 &c关闭&7.'\nTOGGLED_TEAM_CHAT_ON: '&e&l聊天 | &7团队聊天已 &a开启&7.'\nTOGGLED_WORLD_BORDER_OFF: '&e&l边界 | &7世界边界已 &c关闭&7.'\nTOGGLED_WORLD_BORDER_ON: '&e&l边界 | &7世界边界已 &a开启&7.'\nTRANSFER_ADMIN: '&e&l岛屿 | &7你将岛屿 {0} 的拥有权转移给了玩家 {1}.'\nTRANSFER_ADMIN_ALREADY_LEADER: '&c&l错误 | &7{0} 已经是该岛屿的领袖了.'\nTRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&l错误 | &7这些玩家不在同一岛屿中.'\nTRANSFER_ADMIN_NOT_LEADER: '&c&l错误 | &7这些玩家不是任何岛屿的领袖.'\nTRANSFER_ALREADY_LEADER: '&c&l错误 | &7你已经是该岛屿的领袖了.'\nTRANSFER_BROADCAST: '&e&l岛屿 | &7该岛屿的拥有权已转移给了玩家 {0}.'\nUNBAN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 已被玩家 {1} 从该岛屿解除封禁.'\nUNCOOP_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 解除了玩家 {1} 的合作成员关系.'\nUNCOOP_AUTO_ANNOUNCEMENT: '&e&l岛屿 | &7没有岛屿成员在线, 你已被自动解除合作关系.'\nUNCOOP_LEFT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了游戏, 自动取消其成员关系.'\nUNIGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已重新参与岛屿排行榜计算.'\nUNIGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已重新参与岛屿排行榜计算.'\nUNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿解锁!'\nUNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 解锁!'\nUNLOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿解锁!'\nUNSAFE_WARP: '&e&l岛屿 | &7&o看起来该传送点不安全. 请尝试使用其他传送点.'\nUPDATED_PERMISSION: '&e&l岛屿 | &7更新了 {0} 的权限.'\nUPDATED_SETTINGS: '&e&l岛屿 | &7更新了岛屿设置 {0}.'\nUPGRADE_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 之后才可继续进行升级操作.'\nVAULT_NOT_INSTALLED: '&c&l错误 | &7服务器未安装 Vault 插件, 交易功能已禁用.'\nVISITOR_BLOCK_COMMAND: '&c&l错误 | &7你不能对其他岛屿使用该命令.'\nWARP_ALREADY_EXIST: '&c&l错误 | &7已存在同名传送点.'\nWARP_CATEGORY_ICON_NEW_LORE: |\n  &e&l传送 | &7输入一行新的描述 (输入 \"-cancel\" 取消本次操作):\n  &e&l传送 | &7可使用符号 \"\\n\" 进行换行.\nWARP_CATEGORY_ICON_NEW_NAME: '&e&l传送 | &7输入新的分类图标名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_CATEGORY_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_CATEGORY_ICON_UPDATED: '&e&l传送 | &7成功更新了分类图标的样式.'\nWARP_CATEGORY_ILLEGAL_NAME: '&c&l错误 | &7传送点分类名称不能为空.'\nWARP_CATEGORY_NAME_TOO_LONG: '&c&l错误 | &7传送点分类名称长度不能大于 255 个字符.'\nWARP_CATEGORY_SLOT: '&e&l传送 | &7输入一个新的格子位置 (输入 \"-cancel\" 取消本次操作):'\nWARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&l错误 | &7该槽位已有其他分类图标占用.'\nWARP_CATEGORY_SLOT_SUCCESS: '&e&l传送 | &7成功将该分类的位置转移至 {0}.'\nWARP_CATEGORY_RENAME: '&e&l传送 | &7输入新的名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的分类名称.'\nWARP_CATEGORY_RENAME_SUCCESS: '&e&l传送 | &7成功将分类重命名为 {0}.'\nWARP_ICON_NEW_LORE: |\n  &e&l传送 | &7输入一行新的描述 (输入 \"-cancel\" 取消本次操作):\n  &e&l传送 | &7可使用符号 \"\\n\" 进行换行.\nWARP_ICON_NEW_NAME: '&e&l传送 | &7输入新的名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_ICON_UPDATED: '&e&l传送 | &7成功更新了传送点的图标样式.'\nWARP_ILLEGAL_NAME: '&c&l错误 | &7传送点名称不能为空.'\nWARP_LOCATION_UPDATE: '&e&l传送 | &7成功将传送点的位置转移至你当前的位置.'\nWARP_NAME_TOO_LONG: '&c&l错误 | &7传送点名称长度不能大于 255 个字符.'\nWARP_PUBLIC_UPDATE: '&e&l传送 | &7成功将传送点设置为对公众开放.'\nWARP_PRIVATE_UPDATE: '&e&l传送 | &7成功将传送点设置为不对公众开放.'\nWARP_RENAME: '&e&l传送 | &7输入传送点的新名称 (输入 \"-cancel\" 取消本次操作):'\nWARP_RENAME_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的其他传送点.'\nWARP_RENAME_SUCCESS: '&e&l传送 | &7成功将传送点重命名为 {0}.'\nWITHDRAW_ALL_MONEY: |-\n  &e&l银行 | &7岛屿银行余额为 ${0}.\n  &e&l银行 | &7&o正在取出所有钱...\nWITHDRAW_ANNOUNCEMENT: '&e&l银行 | &7玩家 {0} 从岛屿银行中取出了 ${1}!'\nWITHDRAW_ERROR: '&c&l错误 | &7{0}.'\nWITHDRAWN_MONEY: '&e&l银行 | &7你从玩家 {1} 的岛屿银行中取出 ${0}!'\nWITHDRAWN_MONEY_NAME: '&e&l银行 | &7你从岛屿 {1} 的银行中取出 ${0}!'\nWORLD_NOT_ENABLED: '&e&l世界 | &7世界 {0} 未在服务器上启用.'\nWORLD_NOT_UNLOCKED: '&e&l世界 | &7世界 {0} 尚未解锁!'\n"
  },
  {
    "path": "src/main/resources/menus/bank-logs.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTransaction Logs &r{0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ ! $ - $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\ntime-sort: '!'\nmoney-sort: '-'\n\nitems:\n  '@':\n    type: PAPER\n    name: '&eTransaction #{0}'\n    lore:\n      - '&7Player: {1}'\n      - '&7Status: {2}'\n      - '&7Time: {3}'\n      - '&7Amount: ${4}'\n      - ''\n      - '&7Click to filter transactions by this player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '!':\n    type: WATCH\n    name: '&6Sort by creation time'\n  '-':\n    type: EMERALD\n    name: '&6Sort by money'\n\nsounds:\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/bank-logs1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTransaction Logs &r{0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ ! $ - $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\ntime-sort: '!'\nmoney-sort: '-'\n\nitems:\n  '@':\n    type: PAPER\n    name: '&eTransaction #{0}'\n    lore:\n      - '&7Player: {1}'\n      - '&7Status: {2}'\n      - '&7Time: {3}'\n      - '&7Amount: ${4}'\n      - ''\n      - '&7Click to filter transactions by this player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '!':\n    type: WATCH\n    name: '&6Sort by creation time'\n  '-':\n    type: EMERALD\n    name: '&6Sort by money'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/bank-logs1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTransaction Logs &r{0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ ! $ - $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\ntime-sort: '!'\nmoney-sort: '-'\n\nitems:\n  '@':\n    type: PAPER\n    name: '&eTransaction #{0}'\n    lore:\n      - '&7Player: {1}'\n      - '&7Status: {2}'\n      - '&7Time: {3}'\n      - '&7Amount: ${4}'\n      - ''\n      - '&7Click to filter transactions by this player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '!':\n    type: CLOCK\n    name: '&6Sort by creation time'\n  '-':\n    type: EMERALD\n    name: '&6Sort by money'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/banned-players.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Banned Players ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Click to unban the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/banned-players1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Banned Players ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Click to unban the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/banned-players1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Banned Players ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '&7Click to unban the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/biomes.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect a biome'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# ! # % # & # ~ #'\n  - '# # @ # ^ # * # #'\n  - '$ $ $ $ $ $ $ $ $'\n\n# Should the current biome be glowing?\ncurrent-biome-glow: false\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '!':\n    biome: PLAINS\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to plains.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to plains.'\n  '@':\n    biome: JUNGLE\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to jungle.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to jungle.'\n  '%':\n    biome: TAIGA\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to taiga.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to taiga.'\n  '^':\n    biome: DESERT\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n  '&':\n    biome: HELL\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice, snow and water must go!'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice snow, and water must go!'\n  '*':\n    biome: SWAMPLAND\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to swamp.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to swamp.'\n  '~':\n    biome: MESA\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eMesa Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to Mesa.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eMesa Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to Mesa.'\n\nsounds:\n  '!':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '@':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '*':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    access:\n      type: ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/biomes1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect a biome'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# ! # % # & # ~ #'\n  - '# # @ # ^ # * # #'\n  - '$ $ $ $ $ $ $ $ $'\n\n# Should the current biome be glowing?\ncurrent-biome-glow: false\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '!':\n    biome: PLAINS\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to plains.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to plains.'\n  '@':\n    biome: JUNGLE\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to jungle.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to jungle.'\n  '%':\n    biome: TAIGA\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to taiga.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to taiga.'\n  '^':\n    biome: DESERT\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n  '&':\n    biome: HELL\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice, snow and water must go!'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice snow, and water must go!'\n  '*':\n    biome: SWAMPLAND\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to swamp.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to swamp.'\n  '~':\n    biome: MESA\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eMesa Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to Mesa.'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eMesa Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to Mesa.'\n\nsounds:\n  '!':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '@':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '*':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/biomes1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect a biome'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# ! # % # & # ~ #'\n  - '# # @ # ^ # * # #'\n  - '$ $ $ $ $ $ $ $ $'\n\n# Should the current biome be glowing?\ncurrent-biome-glow: false\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '!':\n    biome: PLAINS\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to plains.'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&ePlains Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to plains.'\n  '@':\n    biome: JUNGLE\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to jungle.'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0='\n      name: '&eJungle Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to jungle.'\n  '%':\n    biome: TAIGA\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to taiga.'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ=='\n      name: '&eTaiga Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to taiga.'\n  '^':\n    biome: DESERT\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0='\n      name: '&eDesert Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to desert.'\n        - '&cWarning ice and snow must go!'\n  '&':\n    biome: NETHER_WASTES\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice, snow and water must go!'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19'\n      name: '&eNether Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to nether.'\n        - '&cWarning ice snow, and water must go!'\n  '*':\n    biome: SWAMP\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to swamp.'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0='\n      name: '&eSwamp Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to swamp.'\n  '~':\n    biome: BADLANDS\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eBadlands Biome &a(Available)'\n      lore:\n        - '&7Change your island biome to Badlands.'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19'\n      name: '&eBadlands Biome &c(Unavailable)'\n      lore:\n        - '&7Change your island biome to Badlands.'\n\nsounds:\n  '!':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '@':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '*':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    access:\n      type: ENTITY_ENDERMAN_TELEPORT\n      volume: 0.8\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/border-color.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l        Border Color'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '~ # @ ^ $'\n\ngreen-color: '@'\nred-color: '^'\nblue-color: '$'\n\nitems:\n  '~':\n    enable-border:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&aEnable Border'\n    disable-border:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&cDisable Border'\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aGreen Color'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&cRed Color'\n  '$':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0='\n    name: '&bBlue Color'\n\nsounds:\n  '~':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/border-color1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l        Border Color'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '~ # @ ^ $'\n\ngreen-color: '@'\nred-color: '^'\nblue-color: '$'\n\nitems:\n  '~':\n    enable-border:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&aEnable Border'\n    disable-border:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&cDisable Border'\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aGreen Color'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&cRed Color'\n  '$':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0='\n    name: '&bBlue Color'\n\nsounds:\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/border-color1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l        Border Color'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '~ # @ ^ $'\n\ngreen-color: '@'\nred-color: '^'\nblue-color: '$'\n\nitems:\n  '~':\n    enable-border:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&aEnable Border'\n    disable-border:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0='\n      name: '&cDisable Border'\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aGreen Color'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&cRed Color'\n  '$':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0='\n    name: '&bBlue Color'\n\nsounds:\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-ban.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Ban'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to ban that player?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ANVIL_LAND\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-ban1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Ban'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to ban that player?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-ban1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Ban'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to ban that player?'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-disband.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Disband'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to delete your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ANVIL_LAND\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-disband1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Disband'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to delete your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-disband1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Disband'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to delete your island?'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-kick.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Kick'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to kick that player?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ANVIL_LAND\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-kick1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Kick'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to kick that player?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-kick1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Kick'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to kick that player?'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-leave.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Leave'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to leave your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ANVIL_LAND\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-leave1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Leave'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to leave your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-leave1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Leave'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to leave your island?'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-transfer.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Transfer'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to transfer your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ANVIL_LAND\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-transfer1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Transfer'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to transfer your island?'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/confirm-transfer1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l      Confirm Transfer'\nprevious-menu: true\ntype: HOPPER\n\npattern:\n  - '# @ # ^ #'\n\nconfirm: '@'\ncancel: '^'\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0='\n    name: '&aConfirm'\n    lore:\n      - '&7Are you sure you want to transfer your island?'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0='\n    name: '&4Cancel'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: BLOCK_ANVIL_PLACE\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/control-panel.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Panel'\nprevious-menu: true\n\npattern:\n  - '2 2 2 2 2 2 2 2 2'\n  - '# ! # @ # $ # % #'\n  - '_ # ^ # & # * # 1'\n  - '# ~ # = # - # + #'\n  - '2 2 2 2 2 2 2 2 2'\n\nmembers: '+'\nsettings: '@'\nvisitors: '-'\n\nitems:\n  '!':\n    type: SIGN\n    name: '&eTeleport'\n    lore:\n      - '&7Teleport back to your island.'\n  '@':\n    type: DIODE\n    name: '&eIsland Settings'\n    lore:\n      - '&7Manage settings regarding your island.'\n  '$':\n    type: ENDER_PEARL\n    name: '&eIsland Permissions'\n    lore:\n      - '&7Manage permissions in your island.'\n  '%':\n    type: GRASS\n    name: '&eIsland Biomes'\n    lore:\n      - '&7Change the biome of your island.'\n  '_':\n    type: EMERALD\n    name: '&eIsland Bank'\n    lore:\n      - '&7Open the bank of your island.'\n  '^':\n    type: GOLD_INGOT\n    name: '&eIsland Upgrades'\n    lore:\n      - '&7Upgrade your island statistics!'\n  '&':\n    type: BEACON\n    name: '&eTop Islands'\n    lore:\n      - '&7Check which island is the best on the server!'\n  '*':\n    type: PAPER\n    name: '&eIsland Missions'\n    lore:\n      - '&7Complete missions and get rewarded!'\n  '1':\n    type: SMOOTH_BRICK\n    name: '&eIsland Counts'\n    lore:\n      - '&7See all the blocks on your island!'\n  '~':\n    type: BARRIER\n    name: '&eIsland Disband'\n    lore:\n      - '&7Disband your island.'\n      - '&cThis action cannot be restored!'\n  '=':\n    type: CHEST\n    name: '&eIsland Chest'\n    lore:\n      - '&7Open the community chest of the island.'\n  '-':\n    type: SKULL_ITEM\n    name: '&eIsland Visitors'\n    lore:\n      - '&7Check all the visitors of the island.'\n  '+':\n    type: SKULL_ITEM\n    data: 3\n    name: '&eIsland Members'\n    lore:\n      - '&7Manage the members of the island.'\n  '2':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '!':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '_':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '1':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '~':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '-':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '=':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '+':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n\ncommands:\n  '!':\n    - '[player] is tp'\n  '$':\n    - '[player] is permissions'\n  '%':\n    - '[player] is biome'\n  '_':\n    - '[player] is bank'\n  '^':\n    - '[player] is upgrade'\n  '&':\n    - '[player] is top'\n  '*':\n    - '[player] is missions'\n  '1':\n    - '[player] is counts'\n  '~':\n    - '[player] is disband'\n  '=':\n    - '[player] is chest'"
  },
  {
    "path": "src/main/resources/menus/control-panel1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Panel'\nprevious-menu: true\n\npattern:\n  - '2 2 2 2 2 2 2 2 2'\n  - '# ! # @ # $ # % #'\n  - '_ # ^ # & # * # 1'\n  - '# ~ # = # - # + #'\n  - '2 2 2 2 2 2 2 2 2'\n\nmembers: '+'\nsettings: '@'\nvisitors: '-'\n\nitems:\n  '!':\n    type: SIGN\n    name: '&eTeleport'\n    lore:\n      - '&7Teleport back to your island.'\n  '@':\n    type: DIODE\n    name: '&eIsland Settings'\n    lore:\n      - '&7Manage settings regarding your island.'\n  '$':\n    type: ENDER_PEARL\n    name: '&eIsland Permissions'\n    lore:\n      - '&7Manage permissions in your island.'\n  '%':\n    type: GRASS\n    name: '&eIsland Biomes'\n    lore:\n      - '&7Change the biome of your island.'\n  '_':\n    type: EMERALD\n    name: '&eIsland Bank'\n    lore:\n      - '&7Open the bank of your island.'\n  '^':\n    type: GOLD_INGOT\n    name: '&eIsland Upgrades'\n    lore:\n      - '&7Upgrade your island statistics!'\n  '&':\n    type: BEACON\n    name: '&eTop Islands'\n    lore:\n      - '&7Check which island is the best on the server!'\n  '*':\n    type: PAPER\n    name: '&eIsland Missions'\n    lore:\n      - '&7Complete missions and get rewarded!'\n  '1':\n    type: SMOOTH_BRICK\n    name: '&eIsland Counts'\n    lore:\n      - '&7See all the blocks on your island!'\n  '~':\n    type: BARRIER\n    name: '&eIsland Disband'\n    lore:\n      - '&7Disband your island.'\n      - '&cThis action cannot be restored!'\n  '=':\n    type: CHEST\n    name: '&eIsland Chest'\n    lore:\n      - '&7Open the community chest of the island.'\n  '-':\n    type: SKULL_ITEM\n    name: '&eIsland Visitors'\n    lore:\n      - '&7Check all the visitors of the island.'\n  '+':\n    type: SKULL_ITEM\n    data: 3\n    name: '&eIsland Members'\n    lore:\n      - '&7Manage the members of the island.'\n  '2':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '!':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '_':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '1':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '-':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '=':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '+':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n\ncommands:\n  '!':\n    - '[player] is tp'\n  '$':\n    - '[player] is permissions'\n  '%':\n    - '[player] is biome'\n  '_':\n    - '[player] is bank'\n  '^':\n    - '[player] is upgrade'\n  '&':\n    - '[player] is top'\n  '*':\n    - '[player] is missions'\n  '1':\n    - '[player] is counts'\n  '~':\n    - '[player] is disband'\n  '=':\n    - '[player] is chest'"
  },
  {
    "path": "src/main/resources/menus/control-panel1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Panel'\nprevious-menu: true\n\npattern:\n  - '2 2 2 2 2 2 2 2 2'\n  - '# ! # @ # $ # % #'\n  - '_ # ^ # & # * # 1'\n  - '# ~ # = # - # + #'\n  - '2 2 2 2 2 2 2 2 2'\n\nmembers: '+'\nsettings: '@'\nvisitors: '-'\n\nitems:\n  '!':\n    type: OAK_SIGN\n    name: '&eTeleport'\n    lore:\n      - '&7Teleport back to your island.'\n  '@':\n    type: REPEATER\n    name: '&eIsland Settings'\n    lore:\n      - '&7Manage settings regarding your island.'\n  '$':\n    type: ENDER_PEARL\n    name: '&eIsland Permissions'\n    lore:\n      - '&7Manage permissions in your island.'\n  '%':\n    type: GRASS_BLOCK\n    name: '&eIsland Biomes'\n    lore:\n      - '&7Change the biome of your island.'\n  '_':\n    type: EMERALD\n    name: '&eIsland Bank'\n    lore:\n      - '&7Open the bank of your island.'\n  '^':\n    type: GOLD_INGOT\n    name: '&eIsland Upgrades'\n    lore:\n      - '&7Upgrade your island statistics!'\n  '&':\n    type: BEACON\n    name: '&eTop Islands'\n    lore:\n      - '&7Check which island is the best on the server!'\n  '*':\n    type: PAPER\n    name: '&eIsland Missions'\n    lore:\n      - '&7Complete missions and get rewarded!'\n  '1':\n    type: STONE_BRICKS\n    name: '&eIsland Counts'\n    lore:\n      - '&7See all the blocks on your island!'\n  '~':\n    type: BARRIER\n    name: '&eIsland Disband'\n    lore:\n      - '&7Disband your island.'\n      - '&cThis action cannot be restored!'\n  '=':\n    type: CHEST\n    name: '&eIsland Chest'\n    lore:\n      - '&7Open the community chest of the island.'\n  '-':\n    type: SKELETON_SKULL\n    name: '&eIsland Visitors'\n    lore:\n      - '&7Check all the visitors of the island.'\n  '+':\n    type: PLAYER_HEAD\n    name: '&eIsland Members'\n    lore:\n      - '&7Manage the members of the island.'\n  '2':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '!':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '$':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '_':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '1':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '-':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '=':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '+':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n\ncommands:\n  '!':\n    - '[player] is tp'\n  '$':\n    - '[player] is permissions'\n  '%':\n    - '[player] is biome'\n  '_':\n    - '[player] is bank'\n  '^':\n    - '[player] is upgrade'\n  '&':\n    - '[player] is top'\n  '*':\n    - '[player] is missions'\n  '1':\n    - '[player] is counts'\n  '~':\n    - '[player] is disband'\n  '=':\n    - '[player] is chest'"
  },
  {
    "path": "src/main/resources/menus/coops.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Coop Players ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Click to uncoop the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/coops1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Coop Players ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Click to uncoop the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/coops1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Coop Players ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '&7Click to uncoop the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/counts.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Block Counts'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: STONE\n    name: '&e{0}'\n    lore:\n      - '&6&l* &e&lQuantity &fx{1}'\n      - '&6&l* &e&lWorth: &f${2}'\n      - '&6&l* &e&lLevel: &f${3}'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/counts1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Block Counts'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: STONE\n    name: '&e{0}'\n    lore:\n      - '&6&l* &e&lQuantity &fx{1}'\n      - '&6&l* &e&lWorth: &f${2}'\n      - '&6&l* &e&lLevel: &f${3}'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/counts1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Block Counts'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: STONE\n    name: '&e{0}'\n    lore:\n      - '&6&l* &e&lQuantity &fx{1}'\n      - '&6&l* &e&lWorth: &f${2}'\n      - '&6&l* &e&lLevel: &f${3}'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/counts1_20.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Block Counts'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: STONE\n    name: '&e{0}'\n    lore:\n      - '&6&l* &e&lQuantity &fx{1}'\n      - '&6&l* &e&lWorth: &f${2}'\n      - '&6&l* &e&lLevel: &f${3}'\n    flags:\n      - HIDE_ADDITIONAL_TOOLTIP\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/global-warps.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nwarps: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# When enabled, instead of showing warps, the visitor warp locations will be shown.\n# To show the description, use the {1} placeholder.\nvisitor-warps: false\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}''s Island'\n    lore:\n      - '&7Click to see all warps of this island.'\n      - '&8>> &7This island has {2} warps.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/global-warps1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nwarps: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# When enabled, instead of showing warps, the visitor warp locations will be shown.\n# To show the description, use the {1} placeholder.\nvisitor-warps: false\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}''s Island'\n    lore:\n      - '&7Click to see all warps of this island.'\n      - '&8>> &7This island has {2} warps.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/global-warps1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nwarps: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# When enabled, instead of showing warps, the visitor warp locations will be shown.\n# To show the description, use the {1} placeholder.\nvisitor-warps: false\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}''s Island'\n    lore:\n      - '&7Click to see all warps of this island.'\n      - '&8>> &7This island has {2} warps.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-bank.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Bank'\nprevious-menu: true\n\npattern:\n  - '= - @ @ @ @ @ - ='\n  - '- @ ! @ @ @ % @ -'\n  - '@ # @ @ * @ @ ^ @'\n  - '- @ $ @ @ @ & @ -'\n  - '= - @ @ ~ @ @ - ='\n\nbalance: '*'\nlogs: '~'\n\nitems:\n  '!':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit Half Money'\n    lore:\n      - '&7Deposit half of your money into the bank.'\n    bank-action:\n      deposit: 50.0\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit Money'\n    lore:\n      - '&7Deposit money into the bank.'\n    bank-action:\n      deposit: 0.0\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit All Money'\n    lore:\n      - '&7Deposit all of your money into the bank.'\n    bank-action:\n      deposit: 100.0\n  '%':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw Half Money'\n    lore:\n      - '&7Withdraw half of the money from the bank.'\n    bank-action:\n      withdraw: 50.0\n  '^':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw Money'\n    lore:\n      - '&7Withdraw money from the bank.'\n    bank-action:\n      withdraw: 0.0\n  '&':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw All Money'\n    lore:\n      - '&7Withdraw all of the money from the bank.'\n    bank-action:\n      withdraw: 100.0\n  '*':\n    type: PAPER\n    name: '&6Balance'\n    lore:\n      - '&7Your bank currently has ${2}'\n      - '&7Next interest on {7}'\n  '=':\n    type: EMERALD_BLOCK\n    name: '&f '\n  '-':\n    type: EMERALD\n    name: '&f '\n  '~':\n    type: EXP_BOTTLE\n    name: '&6Transaction Logs'\n\nsounds:\n  '!':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '#':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    success-sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-bank1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Bank'\nprevious-menu: true\n\npattern:\n  - '= - @ @ @ @ @ - ='\n  - '- @ ! @ @ @ % @ -'\n  - '@ # @ @ * @ @ ^ @'\n  - '- @ $ @ @ @ & @ -'\n  - '= - @ @ ~ @ @ - ='\n\nbalance: '*'\nlogs: '~'\n\nitems:\n  '!':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit Half Money'\n    lore:\n      - '&7Deposit half of your money into the bank.'\n    bank-action:\n      deposit: 50.0\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit Money'\n    lore:\n      - '&7Deposit money into the bank.'\n    bank-action:\n      deposit: 0.0\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 5\n    name: '&aDeposit All Money'\n    lore:\n      - '&7Deposit all of your money into the bank.'\n    bank-action:\n      deposit: 100.0\n  '%':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw Half Money'\n    lore:\n      - '&7Withdraw half of the money from the bank.'\n    bank-action:\n      withdraw: 50.0\n  '^':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw Money'\n    lore:\n      - '&7Withdraw money from the bank.'\n    bank-action:\n      withdraw: 0.0\n  '&':\n    type: STAINED_GLASS_PANE\n    data: 14\n    name: '&aWithdraw All Money'\n    lore:\n      - '&7Withdraw all of the money from the bank.'\n    bank-action:\n      withdraw: 100.0\n  '*':\n    type: PAPER\n    name: '&6Balance'\n    lore:\n      - '&7Your bank currently has ${2}'\n      - '&7Next interest on {7}'\n  '=':\n    type: EMERALD_BLOCK\n    name: '&f '\n  '-':\n    type: EMERALD\n    name: '&f '\n  '~':\n    type: EXP_BOTTLE\n    name: '&6Transaction Logs'\n\nsounds:\n  '!':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '#':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-bank1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Bank'\nprevious-menu: true\n\npattern:\n  - '= - @ @ @ @ @ - ='\n  - '- @ ! @ @ @ % @ -'\n  - '@ # @ @ * @ @ ^ @'\n  - '- @ $ @ @ @ & @ -'\n  - '= - @ @ ~ @ @ - ='\n\nbalance: '*'\nlogs: '~'\n\nitems:\n  '!':\n    type: LIME_STAINED_GLASS_PANE\n    name: '&aDeposit Half Money'\n    lore:\n      - '&7Deposit half of your money into the bank.'\n    bank-action:\n      deposit: 50.0\n  '#':\n    type: LIME_STAINED_GLASS_PANE\n    name: '&aDeposit Money'\n    lore:\n      - '&7Deposit money into the bank.'\n    bank-action:\n      deposit: 0.0\n  '$':\n    type: LIME_STAINED_GLASS_PANE\n    name: '&aDeposit All Money'\n    lore:\n      - '&7Deposit all of your money into the bank.'\n    bank-action:\n      deposit: 100.0\n  '%':\n    type: RED_STAINED_GLASS_PANE\n    name: '&aWithdraw Half Money'\n    lore:\n      - '&7Withdraw half of the money from the bank.'\n    bank-action:\n      withdraw: 50.0\n  '^':\n    type: RED_STAINED_GLASS_PANE\n    name: '&aWithdraw Money'\n    lore:\n      - '&7Withdraw money from the bank.'\n    bank-action:\n      withdraw: 0.0\n  '&':\n    type: RED_STAINED_GLASS_PANE\n    name: '&aWithdraw All Money'\n    lore:\n      - '&7Withdraw all of the money from the bank.'\n    bank-action:\n      withdraw: 100.0\n  '*':\n    type: PAPER\n    name: '&6Balance'\n    lore:\n      - '&7Your bank currently has ${2}'\n      - '&7Next interest on {7}'\n  '=':\n    type: EMERALD_BLOCK\n    name: '&f '\n  '-':\n    type: EMERALD\n    name: '&f '\n  '~':\n    type: EXPERIENCE_BOTTLE\n    name: '&6Transaction Logs'\n\nsounds:\n  '!':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '#':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '%':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '&':\n    success-sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n    fail-sound:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-chest.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Chest'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    valid-page:\n      type: STORAGE_MINECART\n      name: '&ePage #{0}'\n      lore:\n        - '&eSize: &7{1}'\n    invalid-page:\n      type: MINECART\n      name: '&f '\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '#':\n    type: RAILS\n    name: '&f '\n\nsounds:\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/island-chest1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Chest'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    valid-page:\n      type: STORAGE_MINECART\n      name: '&ePage #{0}'\n      lore:\n        - '&eSize: &7{1}'\n    invalid-page:\n      type: MINECART\n      name: '&f '\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '#':\n    type: RAILS\n    name: '&f '\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/island-chest1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Chest'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# $ @ @ @ @ @ $ #'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    valid-page:\n      type: CHEST_MINECART\n      name: '&ePage #{0}'\n      lore:\n        - '&eSize: &7{1}'\n    invalid-page:\n      type: MINECART\n      name: '&f '\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '#':\n    type: RAIL\n    name: '&f '\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/island-creation.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCreate a new island...'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '# @ # # ^ # # $ #'\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n\nitems:\n  '@':\n    schematic: 'normal'\n    biome: PLAINS\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &a(Available)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &c(Unavailable)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '^':\n    schematic: 'mycel'\n    biome: MUSHROOM_ISLAND\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '$':\n    schematic: 'desert'\n    biome: DESERT\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '~':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    access:\n      type: PORTAL_TRIGGER\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: PORTAL_TRIGGER\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    access:\n      type: PORTAL_TRIGGER\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-creation1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCreate a new island...'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '# @ # # ^ # # $ #'\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n\nitems:\n  '@':\n    schematic: 'normal'\n    biome: PLAINS\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &a(Available)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &c(Unavailable)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '^':\n    schematic: 'mycel'\n    biome: MUSHROOM_ISLAND\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '$':\n    schematic: 'desert'\n    biome: DESERT\n    spawn-offset: '0, 0, 0'\n    access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '~':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-creation1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCreate a new island...'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '# @ # # ^ # # $ #'\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n\nitems:\n  '@':\n    schematic: 'normal'\n    biome: PLAINS\n    spawn-offset: '0, 0, 0'\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &a(Available)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19'\n      name: '&eNormal Island &c(Unavailable)'\n      lore:\n        - '&7Simple island with trees and a mining area!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '^':\n    schematic: 'mycel'\n    biome: MUSHROOM_FIELDS\n    spawn-offset: '0, 0, 0'\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19'\n      name: '&eMycelium Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of mycelium!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '$':\n    schematic: 'desert'\n    biome: DESERT\n    spawn-offset: '0, 0, 0'\n    access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &a(Available)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n    no-access:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0='\n      name: '&eDesert Island &c(Unavailable)'\n      lore:\n        - '&7Customized island with lots of sand!'\n        - '&7 '\n        - '&7&o(( &f&oRight-Click &7&oto preview the island. ))'\n  '~':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '^':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n  '$':\n    access:\n      type: BLOCK_PORTAL_AMBIENT\n      volume: 1\n      pitch: 0.2\n    no-access:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-rate.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lRate Island'\nprevious-menu: true\n\npattern:\n  - '# ~ @ % # * ^ & #'\n\nzero-stars: '~'\none-star: '@'\ntwo-stars: '%'\nthree-stars: '*'\nfour-stars: '^'\nfive-stars: '&'\n\nitems:\n  '~':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ=='\n    name: '&4Horrible (0/5)'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ=='\n    name: '&6Ugly (1/5)'\n  '%':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19'\n    name: '&eNice (2/5)'\n  '*':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0='\n    name: '&aGood (3/5)'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0='\n    name: '&2Beautiful (4/5)'\n  '&':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19'\n    name: '&5Fabulous (5/5)'\n\nsounds:\n  '~':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-rate1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lRate Island'\nprevious-menu: true\n\npattern:\n  - '# ~ @ % # * ^ & #'\n\nzero-stars: '~'\none-star: '@'\ntwo-stars: '%'\nthree-stars: '*'\nfour-stars: '^'\nfive-stars: '&'\n\nitems:\n  '~':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ=='\n    name: '&4Horrible (0/5)'\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ=='\n    name: '&6Ugly (1/5)'\n  '%':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19'\n    name: '&eNice (2/5)'\n  '*':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0='\n    name: '&aGood (3/5)'\n  '^':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0='\n    name: '&2Beautiful (4/5)'\n  '&':\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19'\n    name: '&5Fabulous (5/5)'\n\nsounds:\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-rate1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lRate Island'\nprevious-menu: true\n\npattern:\n  - '# ~ @ % # * ^ & #'\n\nzero-stars: '~'\none-star: '@'\ntwo-stars: '%'\nthree-stars: '*'\nfour-stars: '^'\nfive-stars: '&'\n\nitems:\n  '~':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ=='\n    name: '&4Horrible (0/5)'\n  '@':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ=='\n    name: '&6Ugly (1/5)'\n  '%':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19'\n    name: '&eNice (2/5)'\n  '*':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0='\n    name: '&aGood (3/5)'\n  '^':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0='\n    name: '&2Beautiful (4/5)'\n  '&':\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19'\n    name: '&5Fabulous (5/5)'\n\nsounds:\n  '~':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/island-ratings.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Ratings ({0}/5)'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '{1}'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/island-ratings1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Ratings ({0}/5)'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '{1}'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/member-manage.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ # @ # % # ^ # $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nroles: '@'\nban: '%'\nkick: '^'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: DIAMOND_CHESTPLATE\n    name: '&ePlayer Role'\n    lore:\n      - '&7Click to edit player''s role.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: BARRIER\n    name: '&eBan Player'\n    lore:\n      - '&7Click to ban the player from the island.'\n  '^':\n    type: SKULL_ITEM\n    name: '&eKick Player'\n    lore:\n      - '&7Click to kick the player from the island.'\n\nsounds:\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/member-manage1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ # @ # % # ^ # $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nroles: '@'\nban: '%'\nkick: '^'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    type: DIAMOND_CHESTPLATE\n    name: '&ePlayer Role'\n    lore:\n      - '&7Click to edit player''s role.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: BARRIER\n    name: '&eBan Player'\n    lore:\n      - '&7Click to ban the player from the island.'\n  '^':\n    type: SKULL_ITEM\n    name: '&eKick Player'\n    lore:\n      - '&7Click to kick the player from the island.'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/member-manage1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ # @ # % # ^ # $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nroles: '@'\nban: '%'\nkick: '^'\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    type: DIAMOND_CHESTPLATE\n    name: '&ePlayer Role'\n    lore:\n      - '&7Click to edit player''s role.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    type: BARRIER\n    name: '&eBan Player'\n    lore:\n      - '&7Click to ban the player from the island.'\n  '^':\n    type: SKELETON_SKULL\n    name: '&eKick Player'\n    lore:\n      - '&7Click to kick the player from the island.'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/member-role.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ @ # % # & # * $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    role: Member\n    type: LEATHER_CHESTPLATE\n    name: '&eMember'\n    lore:\n      - '&7Click to set player''s role to member.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    role: Moderator\n    type: GOLD_CHESTPLATE\n    name: '&eModerator'\n    lore:\n      - '&7Click to set player''s role to moderator.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '&':\n    role: Admin\n    type: IRON_CHESTPLATE\n    name: '&eAdmin'\n    lore:\n      - '&7Click to set player''s role to admin.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '*':\n    role: Leader\n    type: DIAMOND_CHESTPLATE\n    name: '&eLeader'\n    lore:\n      - '&7Click to transfer leadership to player.'\n    flags:\n      - HIDE_ATTRIBUTES\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/member-role1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ @ # % # & # * $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '@':\n    role: Member\n    type: LEATHER_CHESTPLATE\n    name: '&eMember'\n    lore:\n      - '&7Click to set player''s role to member.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    role: Moderator\n    type: GOLD_CHESTPLATE\n    name: '&eModerator'\n    lore:\n      - '&7Click to set player''s role to moderator.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '&':\n    role: Admin\n    type: IRON_CHESTPLATE\n    name: '&eAdmin'\n    lore:\n      - '&7Click to set player''s role to admin.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '*':\n    role: Leader\n    type: DIAMOND_CHESTPLATE\n    name: '&eLeader'\n    lore:\n      - '&7Click to transfer leadership to player.'\n    flags:\n      - HIDE_ATTRIBUTES\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/member-role1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&8&l{}'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ # # # # # # # $'\n  - '$ @ # % # & # * $'\n  - '$ # # # # # # # $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '@':\n    role: Member\n    type: LEATHER_CHESTPLATE\n    name: '&eMember'\n    lore:\n      - '&7Click to set player''s role to member.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '%':\n    role: Moderator\n    type: GOLDEN_CHESTPLATE\n    name: '&eModerator'\n    lore:\n      - '&7Click to set player''s role to moderator.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '&':\n    role: Admin\n    type: IRON_CHESTPLATE\n    name: '&eAdmin'\n    lore:\n      - '&7Click to set player''s role to admin.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '*':\n    role: Leader\n    type: DIAMOND_CHESTPLATE\n    name: '&eLeader'\n    lore:\n      - '&7Click to transfer leadership to player.'\n    flags:\n      - HIDE_ATTRIBUTES\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '&':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '*':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/members.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Members ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&eRole: &7{1}'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/members1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Members ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&eRole: &7{1}'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/members1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Members ({0}/{1})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '&eRole: &7{1}'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/missions-category.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l{0} Missions'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# # @ @ @ @ @ # #'\n  - '# # # # # # # # #'\n\nslots: '@'\nprevious-page: '*'\ncurrent-page: '*'\nnext-page: '*'\n\n# Should missions be sorted by their completion status?\n# Not completed -> Can complete -> Completed\nsort-by-completion: false\n\n# Should completed missions not be displayed in the menu?\nremove-completed: false\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    locked:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n    completed:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n    not-completed:\n      type: ANVIL_LAND\n      volume: 0.2\n      pitch: 0.2\n    can-complete:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/missions-category1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l{0} Missions'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# # @ @ @ @ @ # #'\n  - '# # # # # # # # #'\n\nslots: '@'\nprevious-page: '*'\ncurrent-page: '*'\nnext-page: '*'\n\n# Should missions be sorted by their completion status?\n# Not completed -> Can complete -> Completed\nsort-by-completion: false\n\n# Should completed missions not be displayed in the menu?\nremove-completed: false\n\nitems:\n  '#':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    locked:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    completed:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    not-completed:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    can-complete:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/missions-category1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&l{0} Missions'\nprevious-menu: true\n\npattern:\n  - '# # # # # # # # #'\n  - '# # @ @ @ @ @ # #'\n  - '# # # # # # # # #'\n\nslots: '@'\nprevious-page: '*'\ncurrent-page: '*'\nnext-page: '*'\n\n# Should missions be sorted by their completion status?\n# Not completed -> Can complete -> Completed\nsort-by-completion: false\n\n# Should completed missions not be displayed in the menu?\nremove-completed: false\n\nitems:\n  '#':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    locked:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    completed:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    not-completed:\n      type: BLOCK_ANVIL_PLACE\n      volume: 0.2\n      pitch: 0.2\n    can-complete:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/missions.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lMissions'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ * * * * * * * $'\n  - '$ * # @ % ^ & * $'\n  - '$ * * * * * * * $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '#':\n    type: DIAMOND_PICKAXE\n    name: '&eMiner Missions'\n    lore:\n      - '&7Click to start your adventure as a Miner.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '@':\n    type: SKULL_ITEM\n    data: 2\n    name: '&eSlayer Missions'\n    lore:\n      - '&7Click to start your adventure as a Slayer.'\n  '%':\n    type: WHEAT\n    name: '&eFarmer Missions'\n    lore:\n      - '&7Click to start your adventure as a Farmer.'\n  '^':\n    type: FISHING_ROD\n    name: '&eFisherman Missions'\n    lore:\n      - '&7Click to start your adventure as a Fisherman.'\n  '&':\n    type: MAP\n    name: '&eExplorer Missions'\n    lore:\n      - '&7Click to start your adventure as an Explorer.'\n\nsounds:\n  '#':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '@':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '^':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '&':\n    type: CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/missions1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lMissions'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ * * * * * * * $'\n  - '$ * # @ % ^ & * $'\n  - '$ * * * * * * * $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '#':\n    type: DIAMOND_PICKAXE\n    name: '&eMiner Missions'\n    lore:\n      - '&7Click to start your adventure as a Miner.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '@':\n    type: SKULL_ITEM\n    data: 2\n    name: '&eSlayer Missions'\n    lore:\n      - '&7Click to start your adventure as a Slayer.'\n  '%':\n    type: WHEAT\n    name: '&eFarmer Missions'\n    lore:\n      - '&7Click to start your adventure as a Farmer.'\n  '^':\n    type: FISHING_ROD\n    name: '&eFisherman Missions'\n    lore:\n      - '&7Click to start your adventure as a Fisherman.'\n  '&':\n    type: MAP\n    name: '&eExplorer Missions'\n    lore:\n      - '&7Click to start your adventure as an Explorer.'\n\nsounds:\n  '#':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '^':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '&':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/missions1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lMissions'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ * * * * * * * $'\n  - '$ * # @ % ^ & * $'\n  - '$ * * * * * * * $'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '#':\n    type: DIAMOND_PICKAXE\n    name: '&eMiner Missions'\n    lore:\n      - '&7Click to start your adventure as a Miner.'\n    flags:\n      - HIDE_ATTRIBUTES\n  '@':\n    type: ZOMBIE_HEAD\n    name: '&eSlayer Missions'\n    lore:\n      - '&7Click to start your adventure as a Slayer.'\n  '%':\n    type: WHEAT\n    name: '&eFarmer Missions'\n    lore:\n      - '&7Click to start your adventure as a Farmer.'\n  '^':\n    type: FISHING_ROD\n    name: '&eFisherman Missions'\n    lore:\n      - '&7Click to start your adventure as a Fisherman.'\n  '&':\n    type: MAP\n    name: '&eExplorer Missions'\n    lore:\n      - '&7Click to start your adventure as an Explorer.'\n\nsounds:\n  '#':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '@':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '%':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '^':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1\n  '&':\n    type: BLOCK_CHEST_OPEN\n    volume: 0.8\n    pitch: 1"
  },
  {
    "path": "src/main/resources/menus/permissions.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 3\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 3\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      data: 93\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: SHEEP\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SOIL\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: INK_SACK\n      data: 15\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: HORSE\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      entity: CREEPER\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON_BASE\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEASH\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EXPLOSIVE_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STORAGE_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 2\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MONSTER_EGG\n      data: 59\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH_ON\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: WOOL\n      data: 11\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: WOOL\n      data: 11\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIODE\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EYE_OF_ENDER\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MOB_SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKULL_ITEM\n      data: 3\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_16.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_fish:\n    display-menu: true\n    permission-enabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_lectern_book:\n    display-menu: true\n    permission-enabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  turtle_egg_tramping:\n    display-menu: true\n    permission-enabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_17.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_axolotl:\n    display-menu: true\n    permission-enabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_fish:\n    display-menu: true\n    permission-enabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_lectern_book:\n    display-menu: true\n    permission-enabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sculk_sensor:\n    display-menu: true\n    permission-enabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  turtle_egg_tramping:\n    display-menu: true\n    permission-enabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_19.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  allay_interact:\n    display-menu: true\n    permission-enabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  brush:\n    display-menu: true\n    permission-enabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_axolotl:\n    display-menu: true\n    permission-enabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_fish:\n    display-menu: true\n    permission-enabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_lectern_book:\n    display-menu: true\n    permission-enabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sculk_sensor:\n    display-menu: true\n    permission-enabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    permission-disabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    role-permission:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  turtle_egg_tramping:\n    display-menu: true\n    permission-enabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_20.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  allay_interact:\n    display-menu: true\n    permission-enabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  brush:\n    display-menu: true\n    permission-enabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_axolotl:\n    display-menu: true\n    permission-enabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_fish:\n    display-menu: true\n    permission-enabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_lectern_book:\n    display-menu: true\n    permission-enabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sculk_sensor:\n    display-menu: true\n    permission-enabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    permission-disabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    role-permission:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  turtle_egg_tramping:\n    display-menu: true\n    permission-enabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/permissions1_21.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lPermissions Controller'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nmessages:\n  no-role-permission: '&8 - &c{}'\n  exact-role-permission: '&8 - &2{}'\n  higher-role-permission: '&8 - &a{}'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\npermissions:\n  all:\n    display-menu: true\n    permission-enabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BEDROCK\n      name: '&6All'\n      lore:\n        - '&7Access to all the abilities of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  allay_interact:\n    display-menu: true\n    permission-enabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ALLAY_SPAWN_EGG\n      name: '&6Allay Interact'\n      lore:\n        - '&7Access to interact with allays inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_breed:\n    display-menu: true\n    permission-enabled:\n      type: WHEAT\n      name: '&6Animal Breed'\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      name: '&6Animal Breed'\n      type: WHEAT\n      lore:\n        - '&7Access to breed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_SWORD\n      name: '&6Animal Damage'\n      lore:\n        - '&7Access to damage animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_shear:\n    display-menu: true\n    permission-enabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEARS\n      name: '&6Animal Shear'\n      lore:\n        - '&7Access to shear animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  animal_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHICKEN_SPAWN_EGG\n      name: '&6Animal Spawn'\n      lore:\n        - '&7Access to spawn animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ban_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Ban Member'\n      lore:\n        - '&7Access to ban members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  break:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_PICKAXE\n      name: '&6Break'\n      lore:\n        - '&7Access to break blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  brush:\n    display-menu: true\n    permission-enabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BRUSH\n      name: '&6Brush'\n      lore:\n        - '&7Access to brush suspicious blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  build:\n    display-menu: true\n    permission-enabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COBBLESTONE\n      name: '&6Build'\n      lore:\n        - '&7Access to place blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  change_name:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Change Name'\n      lore:\n        - '&7Access to change the island''s name.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chest_access:\n    display-menu: true\n    permission-enabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST\n      name: '&6Chest Access'\n      lore:\n        - '&7Access to open chests inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  chorus_fruit:\n    display-menu: true\n    permission-enabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHORUS_FRUIT\n      name: '&6Chorus Fruit'\n      lore:\n        - '&7Access to consume chorus fruits inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_bypass:\n    display-menu: true\n    permission-enabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TRIPWIRE_HOOK\n      name: '&6Locked Bypass'\n      lore:\n        - '&7Access to bypass the island''s lock.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  close_island:\n    display-menu: true\n    permission-enabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BARRIER\n      name: '&6Lock Island'\n      lore:\n        - '&7Access to lock the island from public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  coop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Coop Member'\n      lore:\n        - '&7Access to add a player as a co-op member.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  copper_golem_interact:\n    display-menu: true\n    permission-enabled:\n      type: COPPER_GOLEM_STATUE\n      name: '&6Copper Golem Interact'\n      lore:\n        - '&7Access to take items from copper golems.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COPPER_GOLEM_STATUE\n      name: '&6Copper Golem Interact'\n      lore:\n        - '&7Access to take items from copper golems.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COPPER_GOLEM_STATUE\n      name: '&6Copper Golem Interact'\n      lore:\n        - '&7Access to take items from copper golems.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  delete_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Delete Warp'\n      lore:\n        - '&7Access to delete island warps.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  demote_members:\n    display-menu: true\n    permission-enabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: IRON_INGOT\n      name: '&6Demote Members'\n      lore:\n        - '&7Access to demote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  deposit_money:\n    display-menu: true\n    permission-enabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MAP\n      name: '&6Deposit Money'\n      lore:\n        - '&7Access to deposit money into the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  disband_island:\n    display-menu: true\n    permission-enabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT\n      name: '&6Disband Island'\n      lore:\n        - '&7Access to disband the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  discord_show:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Discord Show'\n      lore:\n        - '&7Access to check the island''s linked discord.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  drop_items:\n    display-menu: true\n    permission-enabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ARROW\n      name: '&6Drop Items'\n      lore:\n        - '&7Access to drop items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  dye_sheep:\n    display-menu: true\n    permission-enabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SHEEP_SPAWN_EGG\n      name: '&6Dye Sheep'\n      lore:\n        - '&7Access to dye sheep inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ender_pearl:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_PEARL\n      name: '&6Ender Pearl'\n      lore:\n        - '&7Access to use ender pearls inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  entity_ride:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Entity Ride'\n      lore:\n        - '&7Access to ride entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_bypass:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Expel Bypass'\n      lore:\n        - '&7Access to bypass from being expelled.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  expel_players:\n    display-menu: true\n    permission-enabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DISPENSER\n      name: '&6Expel Players'\n      lore:\n        - '&7Access to expel players from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  farm_tramping:\n    display-menu: true\n    permission-enabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FARMLAND\n      name: '&6Farm Tramping'\n      lore:\n        - '&7Access to tramp farmlands inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fertilize:\n    display-menu: true\n    permission-enabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE_MEAL\n      name: '&6Fertilize'\n      lore:\n        - '&7Access to fertilize blocks around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fish:\n    display-menu: true\n    permission-enabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FISHING_ROD\n      name: '&6Fish'\n      lore:\n        - '&7Access fishing around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  fly:\n    display-menu: true\n    permission-enabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: FEATHER\n      name: '&6Fly'\n      lore:\n        - '&7Access fly around the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  horse_interact:\n    display-menu: true\n    permission-enabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HORSE_SPAWN_EGG\n      name: '&6Horse Interact'\n      lore:\n        - '&7Access to interact with horses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ignite_creeper:\n    display-menu: true\n    permission-enabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CREEPER_SPAWN_EGG\n      name: '&6Ignite Creepers'\n      lore:\n        - '&7Access to ignite creepers with flint and steel inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  interact:\n    display-menu: true\n    permission-enabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PISTON\n      name: '&6Interact'\n      lore:\n        - '&7Access to interact with blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  invite_member:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      data: 3\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      name: '&6Invite Member'\n      lore:\n        - '&7Access to invite new members to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  island_chest:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_CHEST\n      name: '&6Community Chest'\n      lore:\n        - '&7Access to the community chest of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  item_frame:\n    display-menu: true\n    permission-enabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ITEM_FRAME\n      name: '&6Item Frame'\n      lore:\n        - '&7Access to interact with item frames inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  kick_member:\n    display-menu: true\n    permission-enabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SKELETON_SKULL\n      name: '&6Kick Member'\n      lore:\n        - '&7Access to kick members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  leash:\n    display-menu: true\n    permission-enabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEAD\n      name: '&6Leash Mobs'\n      lore:\n        - '&7Access to leash mobs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_damage:\n    display-menu: true\n    permission-enabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TNT_MINECART\n      name: '&6Minecart Damage'\n      lore:\n        - '&7Access to damage minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_enter:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER_MINECART\n      name: '&6Minecart Enter'\n      lore:\n        - '&7Access to enter minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_open:\n    display-menu: true\n    permission-enabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CHEST_MINECART\n      name: '&6Minecart Open'\n      lore:\n        - '&7Access to open minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  minecart_place:\n    display-menu: true\n    permission-enabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: MINECART\n      name: '&6Minecart Place'\n      lore:\n        - '&7Access to place minecarts inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_damage:\n    display-menu: true\n    permission-enabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ZOMBIE_HEAD\n      name: '&6Monster Damage'\n      lore:\n        - '&7Access to damage monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  monster_spawn:\n    display-menu: true\n    permission-enabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: CAVE_SPIDER_SPAWN_EGG\n      name: '&6Monster Spawn'\n      lore:\n        - '&7Access to spawn monsters inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  nautilus_interact:\n    display-menu: true\n    permission-enabled:\n      type: NAUTILUS_SHELL\n      name: '&6Nautilus Interact'\n      lore:\n        - '&7Access to interact with nautiluses inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAUTILUS_SHELL\n      name: '&6Nautilus Interact'\n      lore:\n        - '&7Access to interact with nautiluses inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAUTILUS_SHELL\n      name: '&6Nautilus Interact'\n      lore:\n        - '&7Access to interact with nautiluses inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  name_entity:\n    display-menu: true\n    permission-enabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NAME_TAG\n      name: '&6Name Entity'\n      lore:\n        - '&7Access to name-tag entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  open_island:\n    display-menu: true\n    permission-enabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REDSTONE_TORCH\n      name: '&6Open Island'\n      lore:\n        - '&7Access to open the island to the public.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  painting:\n    display-menu: true\n    permission-enabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PAINTING\n      name: '&6Painting'\n      lore:\n        - '&7Access to interact with paintings inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  paypal_show:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Paypal Show'\n      lore:\n        - '&7Access to check the island''s linked paypal.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_axolotl:\n    display-menu: true\n    permission-enabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: AXOLOTL_SPAWN_EGG\n      name: '&6Pickup Axolotls'\n      lore:\n        - '&7Access to pickup axolotls using a water bucket inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_drops:\n    display-menu: true\n    permission-enabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: HOPPER\n      name: '&6Pickup Drops'\n      lore:\n        - '&7Access to pickup items inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_fish:\n    display-menu: true\n    permission-enabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: COD\n      name: '&6Pickup Fish'\n      lore:\n        - '&7Access to pickup fish using buckets inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  pickup_lectern_book:\n    display-menu: true\n    permission-enabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LECTERN\n      name: '&6Pickup Lectern Book'\n      lore:\n        - '&7Access to pickup books out of lecterns inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  promote_members:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: DIAMOND\n      name: '&6Promote Members'\n      lore:\n        - '&7Access to promote members inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  rankup:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Upgrades Rankup'\n      lore:\n        - '&7Access to rankup island''s upgrades.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  ratings_show:\n    display-menu: true\n    permission-enabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: NETHER_STAR\n      name: '&6Ratings Show'\n      lore:\n        - '&7Access to see all island''s ratings.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  saddle_entity:\n    display-menu: true\n    permission-enabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SADDLE\n      name: '&6Saddle Entity'\n      lore:\n        - '&7Access to add saddle to entities inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sculk_sensor:\n    display-menu: true\n    permission-enabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: SCULK_SENSOR\n      name: '&6Sculk Sensor'\n      lore:\n        - '&7Access to trigger sculk sensors inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_biome:\n    display-menu: true\n    permission-enabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GRASS_BLOCK\n      name: '&6Set Biome'\n      lore:\n        - '&7Access to change the island''s biome.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_discord:\n    display-menu: true\n    permission-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Set Discord'\n      lore:\n        - '&7Access to change the discord linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_home:\n    display-menu: true\n    permission-enabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: RED_BED\n      name: '&6Set Home'\n      lore:\n        - '&7Access to change the home location of the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_paypal:\n    display-menu: true\n    permission-enabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BLUE_WOOL\n      name: '&6Set Paypal'\n      lore:\n        - '&7Access to change the paypal linked to the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_permission:\n    display-menu: true\n    permission-enabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: REPEATER\n      name: '&6Set Permission'\n      lore:\n        - '&7Access to change permissions for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_role:\n    display-menu: true\n    permission-enabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    permission-disabled:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    role-permission:\n      type: DIAMOND_CHESTPLATE\n      name: '&6Set Role'\n      lore:\n        - '&7Access to change roles for island members.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ATTRIBUTES\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_settings:\n    display-menu: true\n    permission-enabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: LEVER\n      name: '&6Set Settings'\n      lore:\n        - '&7Access to change settings for islands.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  set_warp:\n    display-menu: true\n    permission-enabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: ENDER_EYE\n      name: '&6Set Warp'\n      lore:\n        - '&7Access to set new warps for the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  sign_interact:\n    display-menu: true\n    permission-enabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: OAK_SIGN\n      name: '&6Sign Interact'\n      lore:\n        - '&7Access to interact with signs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  spawner_break:\n    display-menu: true\n    permission-enabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    permission-disabled:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    role-permission:\n      type: SPAWNER\n      name: '&6Spawner Break'\n      lore:\n        - '&7Access to break spawners inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  turtle_egg_tramping:\n    display-menu: true\n    permission-enabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: TURTLE_EGG\n      name: '&6Turtle Eggs Tramping'\n      lore:\n        - '&7Access to tramp turtle eggs inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  tamed_animal_damage:\n    display-menu: true\n    permission-enabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: BONE\n      name: '&6Tamed Animal Damage'\n      lore:\n        - '&7Access to damage tamed animals inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: ANVIL_LAND\n        volume: 0.2\n        pitch: 0.2\n\n  uncoop_member:\n    display-menu: true\n    permission-enabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLDEN_APPLE\n      name: '&6Uncoop Member'\n      lore:\n        - '&7Access to remove co-op members from the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  use:\n    display-menu: true\n    permission-enabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: STONE_BUTTON\n      name: '&6Use'\n      lore:\n        - '&7Access to use different blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  valuable_break:\n    display-menu: true\n    permission-enabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: GOLD_INGOT\n      name: '&6Valuable Blocks Break'\n      lore:\n        - '&7Access to break valuable blocks inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  villager_trading:\n    display-menu: true\n    permission-enabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: PLAYER_HEAD\n      skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19'\n      name: '&6Villagers Trading'\n      lore:\n        - '&7Access to trade with villagers inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  wind_charge:\n    display-menu: true\n    permission-enabled:\n      type: WIND_CHARGE\n      name: '&6Wind Charge'\n      lore:\n        - '&7Access to use wind charges inside the island.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: WIND_CHARGE\n      name: '&6Wind Charge'\n      lore:\n        - '&7Access to use wind charges inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: WIND_CHARGE\n      name: '&6Wind Charge'\n      lore:\n        - '&7Access to use wind charges inside the island.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2\n\n  withdraw_money:\n    display-menu: true\n    permission-enabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &aENABLED&7.'\n    permission-disabled:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Currently &cDISABLED&7.'\n    role-permission:\n      type: EMERALD\n      name: '&6Withdraw Money'\n      lore:\n        - '&7Access to withdraw money from the island''s bank.'\n        - '&7Role: &e{}&7.'\n        - ''\n        - '{0}'\n    has-access:\n      sound:\n        type: ENTITY_EXPERIENCE_ORB_PICKUP\n        volume: 0.2\n        pitch: 0.2\n    no-access:\n      sound:\n        type: BLOCK_ANVIL_PLACE\n        volume: 0.2\n        pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/player-language.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect Language...'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ # % * + ^ ~ 1 @'\n  - '@ @ - = ! 2 3 @ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nitems:\n  '#':\n    language: 'en-US'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19'\n    name: '&eEnglish'\n    lore:\n      - '&7Change language to English.'\n  '%':\n    language: 'iw-IL'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ=='\n    name: '&eHebrew'\n    lore:\n      - '&7Change language to Hebrew.'\n  '*':\n    language: 'vi-VN'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0='\n    name: '&eVietnamese'\n    lore:\n      - '&7Change language to Vietnamese.'\n  '+':\n    language: 'pl-PL'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19'\n    name: '&ePolish'\n    lore:\n      - '&7Change language to Polish.'\n  '2':\n    language: 'pt-BR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0='\n    name: '&eBrazilian Portuguese'\n    lore:\n      - '&7Change language to Brazilian Portuguese.'\n  '^':\n    language: 'it-IT'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0='\n    name: '&eItalian'\n    lore:\n      - '&7Change language to Italian.'\n  '~':\n    language: 'zh-CN'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0='\n    name: '&eSimplified Chinese'\n    lore:\n      - '&7Change language to Simplified Chinese.'\n  '1':\n    language: 'ru-RU'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ=='\n    name: '&eRussian'\n    lore:\n      - '&7Change language to Russian.'\n  '-':\n    language: 'fr-FR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ=='\n    name: '&eFrench'\n    lore:\n      - '&7Change language to French.'\n  '=':\n    language: 'es-ES'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0='\n    name: '&eSpanish'\n    lore:\n      - '&7Change language to Spanish.'\n  '!':\n    language: 'de-DE'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ=='\n    name: '&eGerman'\n    lore:\n      - '&7Change language to German.'\n  '3':\n    language: 'tr-TR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ=='\n    name: '&eTurkish'\n    lore:\n      - '&7Change language to Turkish.'\n\nsounds:\n  '#':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/player-language1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect Language...'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ # % * + ^ ~ 1 @'\n  - '@ @ - = ! 2 3 @ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nitems:\n  '#':\n    language: 'en-US'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19'\n    name: '&eEnglish'\n    lore:\n      - '&7Change language to English.'\n  '%':\n    language: 'iw-IL'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ=='\n    name: '&eHebrew'\n    lore:\n      - '&7Change language to Hebrew.'\n  '*':\n    language: 'vi-VN'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0='\n    name: '&eVietnamese'\n    lore:\n      - '&7Change language to Vietnamese.'\n  '+':\n    language: 'pl-PL'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19'\n    name: '&ePolish'\n    lore:\n      - '&7Change language to Polish.'\n  '2':\n    language: 'pt-BR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0='\n    name: '&eBrazilian Portuguese'\n    lore:\n      - '&7Change language to Brazilian Portuguese.'\n  '^':\n    language: 'it-IT'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0='\n    name: '&eItalian'\n    lore:\n      - '&7Change language to Italian.'\n  '~':\n    language: 'zh-CN'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0='\n    name: '&eSimplified Chinese'\n    lore:\n      - '&7Change language to Simplified Chinese.'\n  '1':\n    language: 'ru-RU'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ=='\n    name: '&eRussian'\n    lore:\n      - '&7Change language to Russian.'\n  '-':\n    language: 'fr-FR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ=='\n    name: '&eFrench'\n    lore:\n      - '&7Change language to French.'\n  '=':\n    language: 'es-ES'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0='\n    name: '&eSpanish'\n    lore:\n      - '&7Change language to Spanish.'\n  '!':\n    language: 'de-DE'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ=='\n    name: '&eGerman'\n    lore:\n      - '&7Change language to German.'\n  '3':\n    language: 'tr-TR'\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ=='\n    name: '&eTurkish'\n    lore:\n      - '&7Change language to Turkish.'\n\nsounds:\n  '#':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/player-language1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lSelect Language...'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ # % * + ^ ~ 1 @'\n  - '@ @ - = ! 2 3 @ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nitems:\n  '#':\n    language: 'en-US'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19'\n    name: '&eEnglish'\n    lore:\n      - '&7Change language to English.'\n  '%':\n    language: 'iw-IL'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ=='\n    name: '&eHebrew'\n    lore:\n      - '&7Change language to Hebrew.'\n  '*':\n    language: 'vi-VN'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0='\n    name: '&eVietnamese'\n    lore:\n      - '&7Change language to Vietnamese.'\n  '+':\n    language: 'pl-PL'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19'\n    name: '&ePolish'\n    lore:\n      - '&7Change language to Polish.'\n  '2':\n    language: 'pt-BR'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0='\n    name: '&eBrazilian Portuguese'\n    lore:\n      - '&7Change language to Brazilian Portuguese.'\n  '^':\n    language: 'it-IT'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0='\n    name: '&eItalian'\n    lore:\n      - '&7Change language to Italian.'\n  '~':\n    language: 'zh-CN'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0='\n    name: '&eSimplified Chinese'\n    lore:\n      - '&7Change language to Simplified Chinese.'\n  '1':\n    language: 'ru-RU'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ=='\n    name: '&eRussian'\n    lore:\n      - '&7Change language to Russian.'\n  '-':\n    language: 'fr-FR'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ=='\n    name: '&eFrench'\n    lore:\n      - '&7Change language to French.'\n  '=':\n    language: 'es-ES'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0='\n    name: '&eSpanish'\n    lore:\n      - '&7Change language to Spanish.'\n  '!':\n    language: 'de-DE'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ=='\n    name: '&eGerman'\n    lore:\n      - '&7Change language to German.'\n  '3':\n    language: 'tr-TR'\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ=='\n    name: '&eTurkish'\n    lore:\n      - '&7Change language to Turkish.'\n\nsounds:\n  '#':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2\n  '^':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/settings.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Settings'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 3\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\nsettings:\n  always_day:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 4\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 4\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_day:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 1\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 1\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_night:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_night:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 11\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 11\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_rain:\n    display-menu: true\n    settings-enabled:\n      type: WATER_LILY\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_LILY\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_shiny:\n    display-menu: true\n    settings-enabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  creeper_explosion:\n    display-menu: true\n    settings-enabled:\n      type: SKULL_ITEM\n      data: 4\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SKULL_ITEM\n      data: 4\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  crops_growth:\n    display-menu: true\n    settings-enabled:\n      type: SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  egg_lay:\n    display-menu: true\n    settings-enabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  enderman_grief:\n    display-menu: true\n    settings-enabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  fire_spread:\n    display-menu: true\n    settings-enabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  ghast_fireball:\n    display-menu: true\n    settings-enabled:\n      type: FIREBALL\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FIREBALL\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  lava_flow:\n    display-menu: true\n    settings-enabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MONSTER_EGG\n      data: 90\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MONSTER_EGG\n      data: 90\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MONSTER_EGG\n      data: 54\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MONSTER_EGG\n      data: 54\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  pvp:\n    display-menu: true\n    settings-enabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    settings-disabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tnt_explosion:\n    display-menu: true\n    settings-enabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tree_growth:\n    display-menu: true\n    settings-enabled:\n      type: SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  water_flow:\n    display-menu: true\n    settings-enabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  wither_explosion:\n    display-menu: true\n    settings-enabled:\n      type: SKULL_ITEM\n      data: 1\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SKULL_ITEM\n      data: 1\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/settings1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Settings'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 3\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\nsettings:\n  always_day:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 4\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 4\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_day:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 1\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 1\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_night:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 3\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_night:\n    display-menu: true\n    settings-enabled:\n      type: STAINED_CLAY\n      data: 11\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: STAINED_CLAY\n      data: 11\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_rain:\n    display-menu: true\n    settings-enabled:\n      type: WATER_LILY\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_LILY\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_shiny:\n    display-menu: true\n    settings-enabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  creeper_explosion:\n    display-menu: true\n    settings-enabled:\n      type: SKULL_ITEM\n      data: 4\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SKULL_ITEM\n      data: 4\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  crops_growth:\n    display-menu: true\n    settings-enabled:\n      type: SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  egg_lay:\n    display-menu: true\n    settings-enabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  enderman_grief:\n    display-menu: true\n    settings-enabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  fire_spread:\n    display-menu: true\n    settings-enabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  ghast_fireball:\n    display-menu: true\n    settings-enabled:\n      type: FIREBALL\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FIREBALL\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  lava_flow:\n    display-menu: true\n    settings-enabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MONSTER_EGG\n      data: 90\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MONSTER_EGG\n      data: 90\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MONSTER_EGG\n      data: 54\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MONSTER_EGG\n      data: 54\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  pvp:\n    display-menu: true\n    settings-enabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    settings-disabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: MOB_SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tnt_explosion:\n    display-menu: true\n    settings-enabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tree_growth:\n    display-menu: true\n    settings-enabled:\n      type: SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  water_flow:\n    display-menu: true\n    settings-enabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  wither_explosion:\n    display-menu: true\n    settings-enabled:\n      type: SKULL_ITEM\n      data: 1\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SKULL_ITEM\n      data: 1\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/settings1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Settings'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\nsettings:\n  always_day:\n    display-menu: true\n    settings-enabled:\n      type: YELLOW_TERRACOTTA\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: YELLOW_TERRACOTTA\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_day:\n    display-menu: true\n    settings-enabled:\n      type: ORANGE_TERRACOTTA\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ORANGE_TERRACOTTA\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_night:\n    display-menu: true\n    settings-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_night:\n    display-menu: true\n    settings-enabled:\n      type: BLUE_TERRACOTTA\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: BLUE_TERRACOTTA\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_rain:\n    display-menu: true\n    settings-enabled:\n      type: LILY_PAD\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LILY_PAD\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_shiny:\n    display-menu: true\n    settings-enabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  creeper_explosion:\n    display-menu: true\n    settings-enabled:\n      type: CREEPER_HEAD\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: CREEPER_HEAD\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  crops_growth:\n    display-menu: true\n    settings-enabled:\n      type: WHEAT_SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WHEAT_SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  egg_lay:\n    display-menu: true\n    settings-enabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  enderman_grief:\n    display-menu: true\n    settings-enabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  fire_spread:\n    display-menu: true\n    settings-enabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  ghast_fireball:\n    display-menu: true\n    settings-enabled:\n      type: FIRE_CHARGE\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FIRE_CHARGE\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  lava_flow:\n    display-menu: true\n    settings-enabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: PIG_SPAWN_EGG\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: PIG_SPAWN_EGG\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: ZOMBIE_SPAWN_EGG\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ZOMBIE_SPAWN_EGG\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  pvp:\n    display-menu: true\n    settings-enabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    settings-disabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tnt_explosion:\n    display-menu: true\n    settings-enabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tree_growth:\n    display-menu: true\n    settings-enabled:\n      type: OAK_SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: OAK_SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  water_flow:\n    display-menu: true\n    settings-enabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  wither_explosion:\n    display-menu: true\n    settings-enabled:\n      type: WITHER_SKELETON_SKULL\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WITHER_SKELETON_SKULL\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/settings1_20.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Settings'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ @ @ @ @ @ @ @ $'\n  - '$ $ % $ * $ ^ $ $'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '$':\n    type: CYAN_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n\nsettings:\n  always_day:\n    display-menu: true\n    settings-enabled:\n      type: YELLOW_TERRACOTTA\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: YELLOW_TERRACOTTA\n      name: '&6Always Day'\n      lore:\n        - '&7Set a day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_day:\n    display-menu: true\n    settings-enabled:\n      type: ORANGE_TERRACOTTA\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ORANGE_TERRACOTTA\n      name: '&6Always Middle Day'\n      lore:\n        - '&7Set a middle day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_night:\n    display-menu: true\n    settings-enabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LIGHT_BLUE_TERRACOTTA\n      name: '&6Always Night'\n      lore:\n        - '&7Set a night time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_middle_night:\n    display-menu: true\n    settings-enabled:\n      type: BLUE_TERRACOTTA\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: BLUE_TERRACOTTA\n      name: '&6Always Middle Night'\n      lore:\n        - '&7Set a middle night day time on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_rain:\n    display-menu: true\n    settings-enabled:\n      type: LILY_PAD\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LILY_PAD\n      name: '&6Always Rain'\n      lore:\n        - '&7Set a rainy weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  always_shiny:\n    display-menu: true\n    settings-enabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: DEAD_BUSH\n      name: '&6Always Shiny'\n      lore:\n        - '&7Set a shiny weather on your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  creeper_explosion:\n    display-menu: true\n    settings-enabled:\n      type: CREEPER_HEAD\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: CREEPER_HEAD\n      name: '&6Creeper Explosion'\n      lore:\n        - '&7Allow creepers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  crops_growth:\n    display-menu: true\n    settings-enabled:\n      type: WHEAT_SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WHEAT_SEEDS\n      name: '&6Crops Growth'\n      lore:\n        - '&7Allow growth of crops inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  egg_lay:\n    display-menu: true\n    settings-enabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: EGG\n      name: '&6Egg Lay'\n      lore:\n        - '&7Allow chickens to lay eggs inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  enderman_grief:\n    display-menu: true\n    settings-enabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ENDER_PEARL\n      name: '&6Enderman Grief'\n      lore:\n        - '&7Allow enderman to grief blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  fire_spread:\n    display-menu: true\n    settings-enabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FLINT_AND_STEEL\n      name: '&6Fire Spread'\n      lore:\n        - '&7Allow fire to spread inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  ghast_fireball:\n    display-menu: true\n    settings-enabled:\n      type: FIRE_CHARGE\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: FIRE_CHARGE\n      name: '&6Ghast Fireball'\n      lore:\n        - '&7Allow fireballs to break blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  lava_flow:\n    display-menu: true\n    settings-enabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: LAVA_BUCKET\n      name: '&6Lava Flow'\n      lore:\n        - '&7Allow lava to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: PIG_SPAWN_EGG\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: PIG_SPAWN_EGG\n      name: '&6Natural Animals Spawn'\n      lore:\n        - '&7Allow natural spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  natural_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: ZOMBIE_SPAWN_EGG\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: ZOMBIE_SPAWN_EGG\n      name: '&6Natural Monster Spawn'\n      lore:\n        - '&7Allow natural spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  pvp:\n    display-menu: true\n    settings-enabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    settings-disabled:\n      type: DIAMOND_SWORD\n      name: '&6PvP'\n      lore:\n        - '&7Allow players to pvp inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ATTRIBUTES\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_animals_spawn:\n    display-menu: true\n    settings-enabled:\n      type: SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    settings-disabled:\n      type: SPAWNER\n      name: '&6Spawner Animals Spawn'\n      lore:\n        - '&7Allow spawner spawning of animals inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  spawner_monster_spawn:\n    display-menu: true\n    settings-enabled:\n      type: SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &aENABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    settings-disabled:\n      type: SPAWNER\n      name: '&6Spawner Monster Spawn'\n      lore:\n        - '&7Allow spawner spawning of monsters inside the island.'\n        - '&7Currently &cDISABLED&7.'\n      flags:\n        - HIDE_ADDITIONAL_TOOLTIP\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tnt_explosion:\n    display-menu: true\n    settings-enabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: TNT\n      name: '&6TNT Explosion'\n      lore:\n        - '&7Allow TNT to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  tree_growth:\n    display-menu: true\n    settings-enabled:\n      type: OAK_SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: OAK_SAPLING\n      name: '&6Tree Growth'\n      lore:\n        - '&7Allow growth of trees inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  water_flow:\n    display-menu: true\n    settings-enabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WATER_BUCKET\n      name: '&6Water Flow'\n      lore:\n        - '&7Allow water to flow inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2\n\n  wither_explosion:\n    display-menu: true\n    settings-enabled:\n      type: WITHER_SKELETON_SKULL\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &aENABLED&7.'\n    settings-disabled:\n      type: WITHER_SKELETON_SKULL\n      name: '&6Wither Explosion'\n      lore:\n        - '&7Allow withers to explode blocks inside your island.'\n        - '&7Currently &cDISABLED&7.'\n    sound:\n      type: ENTITY_EXPERIENCE_ORB_PICKUP\n      volume: 0.2\n      pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/top-islands.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTop Islands'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '@ % @ @ @ # @ @ @'\n  - '@ * @ @ # # # @ @'\n  - '@ ^ @ # # # # # @'\n  - '@ & @ @ @ $ @ @ @'\n  - '~ ~ ! ~ - ~ + ~ ~'\n\nslots: '#'\nprevious-page: '!'\ncurrent-page: '-'\nnext-page: '+'\n\nplayer-island: '$'\nsort-glow-when-selected: true\n\nitems:\n  '#':\n    island:\n      type: SKULL_ITEM\n      data: 3\n      name: '&e&l[!] Island: &6&n{0}&7 (#{1})'\n      lore:\n        - '&7'\n        - '&6&l* &e&lIsland Level &7{2}'\n        - '&7'\n        - '&6&l* &e&lPlace &7#{1}'\n        - '&6&l* &e&lWorth &7${3}'\n        - '&6&l* &e&lRating {8} &7({9})'\n        - '&6&l* &e&lPlayers &7{10}'\n        - '&7'\n        - '&6&l* &e&lMembers:'\n        - '{4}:&f  - &7{}'\n        - '&7'\n        - '&7&o(( &f&oLeft-Click &7&oto view their items. ))'\n        - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))'\n    no-island:\n      type: SKULL_ITEM\n      data: 3\n      name: '&cInvalid Island'\n  '%':\n    type: DIAMOND\n    sorting-type: 'WORTH'\n    name: '&6Sort by Worth'\n  '*':\n    type: GOLD_INGOT\n    sorting-type: 'LEVEL'\n    name: '&6Sort by Level'\n  '^':\n    type: EMERALD\n    sorting-type: 'RATING'\n    name: '&6Sort by Rating'\n  '&':\n    type: SKULL_ITEM\n    data: 3\n    sorting-type: 'PLAYERS'\n    name: '&6Sort by Players'\n  '!':\n    type: PAPER\n    name: '{0}Previous Page'\n  '-':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '+':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/top-islands1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTop Islands'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '@ % @ @ @ # @ @ @'\n  - '@ * @ @ # # # @ @'\n  - '@ ^ @ # # # # # @'\n  - '@ & @ @ @ $ @ @ @'\n  - '~ ~ ! ~ - ~ + ~ ~'\n\nslots: '#'\nprevious-page: '!'\ncurrent-page: '-'\nnext-page: '+'\n\nplayer-island: '$'\nsort-glow-when-selected: true\n\nitems:\n  '#':\n    island:\n      type: SKULL_ITEM\n      data: 3\n      name: '&e&l[!] Island: &6&n{0}&7 (#{1})'\n      lore:\n        - '&7'\n        - '&6&l* &e&lIsland Level &7{2}'\n        - '&7'\n        - '&6&l* &e&lPlace &7#{1}'\n        - '&6&l* &e&lWorth &7${3}'\n        - '&6&l* &e&lRating {8} &7({9})'\n        - '&6&l* &e&lPlayers &7{10}'\n        - '&7'\n        - '&6&l* &e&lMembers:'\n        - '{4}:&f  - &7{}'\n        - '&7'\n        - '&7&o(( &f&oLeft-Click &7&oto view their items. ))'\n        - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))'\n    no-island:\n      type: SKULL_ITEM\n      data: 3\n      name: '&cInvalid Island'\n  '%':\n    type: DIAMOND\n    sorting-type: 'WORTH'\n    name: '&6Sort by Worth'\n  '*':\n    type: GOLD_INGOT\n    sorting-type: 'LEVEL'\n    name: '&6Sort by Level'\n  '^':\n    type: EMERALD\n    sorting-type: 'RATING'\n    name: '&6Sort by Rating'\n  '&':\n    type: SKULL_ITEM\n    data: 3\n    sorting-type: 'PLAYERS'\n    name: '&6Sort by Players'\n  '!':\n    type: PAPER\n    name: '{0}Previous Page'\n  '-':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '+':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/top-islands1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lTop Islands'\nprevious-menu: true\n\npattern:\n  - '~ ~ ~ ~ ~ ~ ~ ~ ~'\n  - '@ % @ @ @ # @ @ @'\n  - '@ * @ @ # # # @ @'\n  - '@ ^ @ # # # # # @'\n  - '@ & @ @ @ $ @ @ @'\n  - '~ ~ ! ~ - ~ + ~ ~'\n\nslots: '#'\nprevious-page: '!'\ncurrent-page: '-'\nnext-page: '+'\n\nplayer-island: '$'\nsort-glow-when-selected: true\n\nitems:\n  '#':\n    island:\n      type: PLAYER_HEAD\n      name: '&e&l[!] Island: &6&n{0}&7 (#{1})'\n      lore:\n        - '&7'\n        - '&6&l* &e&lIsland Level &7{2}'\n        - '&7'\n        - '&6&l* &e&lPlace &7#{1}'\n        - '&6&l* &e&lWorth &7${3}'\n        - '&6&l* &e&lRating {8} &7({9})'\n        - '&6&l* &e&lPlayers &7{10}'\n        - '&7'\n        - '&6&l* &e&lMembers:'\n        - '{4}:&f  - &7{}'\n        - '&7'\n        - '&7&o(( &f&oLeft-Click &7&oto view their items. ))'\n        - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))'\n    no-island:\n      type: PLAYER_HEAD\n      name: '&cInvalid Island'\n  '%':\n    type: DIAMOND\n    sorting-type: 'WORTH'\n    name: '&6Sort by Worth'\n  '*':\n    type: GOLD_INGOT\n    sorting-type: 'LEVEL'\n    name: '&6Sort by Level'\n  '^':\n    type: EMERALD\n    sorting-type: 'RATING'\n    name: '&6Sort by Rating'\n  '&':\n    type: PLAYER_HEAD\n    sorting-type: 'PLAYERS'\n    name: '&6Sort by Players'\n  '!':\n    type: PAPER\n    name: '{0}Previous Page'\n  '-':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '+':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/unique-visitors.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Unique Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - '&7Last Time Joined: {3}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/unique-visitors1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Unique Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - '&7Last Time Joined: {3}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/unique-visitors1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Unique Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - '&7Last Time Joined: {3}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/upgrades.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Upgrades'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # @ # % # ^ # #'\n  - '# # # ! # + # # #'\n  - '# # * # ~ # & # #'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nupgrades:\n  hoppers-limit:\n    item: '@'\n    '1':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  crop-growth:\n    item: '%'\n    '1':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  spawner-rates:\n    item: '^'\n    '1':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  mob-drops:\n    item: '*'\n    '1':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  members-limit:\n    item: '~'\n    '1':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  border-size:\n    item: '!'\n    '1':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  generator-rates:\n    item: '+'\n    '1':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n  minecarts-limit:\n    item: '&'\n    '1':\n      has-next-level:\n        type: MINECART\n        name: '&d&lMinecart Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: ANVIL_LAND\n          volume: 0.2\n          pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/upgrades1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Upgrades'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # @ # % # ^ # #'\n  - '# # # ! # + # # #'\n  - '# # * # ~ # & # #'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nupgrades:\n  hoppers-limit:\n    item: '@'\n    '1':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  crop-growth:\n    item: '%'\n    '1':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  spawner-rates:\n    item: '^'\n    '1':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MOB_SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MOB_SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  mob-drops:\n    item: '*'\n    '1':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  members-limit:\n    item: '~'\n    '1':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SKULL_ITEM\n        data: 3\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  border-size:\n    item: '!'\n    '1':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  generator-rates:\n    item: '+'\n    '1':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  minecarts-limit:\n    item: '&'\n    '1':\n      has-next-level:\n        type: MINECART\n        name: '&d&lMinecart Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/upgrades1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Upgrades'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # @ # % # ^ # #'\n  - '# # # ! # + # # #'\n  - '# # * # ~ # & # #'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nupgrades:\n  hoppers-limit:\n    item: '@'\n    '1':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  crop-growth:\n    item: '%'\n    '1':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  spawner-rates:\n    item: '^'\n    '1':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  mob-drops:\n    item: '*'\n    '1':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  members-limit:\n    item: '~'\n    '1':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  border-size:\n    item: '!'\n    '1':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  generator-rates:\n    item: '+'\n    '1':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  minecarts-limit:\n    item: '&'\n    '1':\n      has-next-level:\n        type: MINECART\n        name: '&d&lMinecart Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/upgrades1_20.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Upgrades'\nprevious-menu: true\n\npattern:\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # @ # % # ^ # #'\n  - '# # # ! # + # # #'\n  - '# # * # ~ # & # #'\n  - '$ $ $ $ $ $ $ $ $'\n\nitems:\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nupgrades:\n  hoppers-limit:\n    item: '@'\n    '1':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f16x Hoppers'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f32x Hoppers'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the hopper upgrade'\n          - '&7will increase your island''s'\n          - '&7max hoppers limit.'\n          - '&7'\n          - '&dAmount: &f64x Hoppers'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: HOPPER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the hoppers limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  crop-growth:\n    item: '%'\n    '1':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 2'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx2 Speed'\n          - '&ePrice: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 3'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx3 Speed'\n          - '&ePrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &a(Available)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&e&lCrop Growth &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&eNext Level: 4'\n          - '&7'\n          - '&7Purchasing the growth upgrade'\n          - '&7gives all crops within your island'\n          - '&7increased growth speed.'\n          - '&7'\n          - '&eGrowth: &fx4 Speed'\n          - '&ePrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: DIAMOND_HOE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the crop growth!'\n        flags:\n          - HIDE_ATTRIBUTES\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  spawner-rates:\n    item: '^'\n    '1':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx2 Speed'\n          - '&bPrice: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx3 Speed'\n          - '&bPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&b&lSpawner Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&bNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the spawner upgrade'\n          - '&7gives all spawners within your island'\n          - '&7increased spawn speed.'\n          - '&7'\n          - '&bBoost: &fx4 Speed'\n          - '&bPrice: &f$2,500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: SPAWNER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the spawner rates!'\n        flags:\n          - HIDE_ADDITIONAL_TOOLTIP\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  mob-drops:\n    item: '*'\n    '1':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx2 Drops'\n          - '&4Price: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx3 Drops'\n          - '&4Price: &f$2,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &a(Available)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&4&lPremium Drops &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&4Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the drops upgrade'\n          - '&7gives all mobs within your island'\n          - '&7increased loot drops.'\n          - '&7'\n          - '&4Amount: &fx4 Drops'\n          - '&4Price: &f$5,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: ROTTEN_FLESH\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the mob drops!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  members-limit:\n    item: '~'\n    '1':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f8 Members'\n          - '&2Price: &f$100,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f16 Members'\n          - '&2Price: &f$300,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &a(Available)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&2&lMembers Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&2Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the members upgrade'\n          - '&7will increase the maximum allowed'\n          - '&7members in your island.'\n          - '&7'\n          - '&2Amount: &f32 Members'\n          - '&2Price: &f$500,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: PLAYER_HEAD\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: PLAYER_HEAD\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the members limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  border-size:\n    item: '!'\n    '1':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f50 Blocks'\n          - '&9Price: &f$30,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f75 Blocks'\n          - '&9Price: &f$80,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &a(Available)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&9&lBorder Size &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&9Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the border upgrade'\n          - '&7will increase the radius'\n          - '&7of your island.'\n          - '&7'\n          - '&9Radius: &f125 Blocks'\n          - '&9Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: BARRIER\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the border size!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  generator-rates:\n    item: '+'\n    '1':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e2'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f92% Stone'\n          - ' &7 - &f5% Coal Ore'\n          - ' &7 - &f3% Redstone Ore'\n          - '&7'\n          - '&3Price: &f$25,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e3'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f80% Stone'\n          - ' &7 - &f8% Coal Ore'\n          - ' &7 - &f6% Redstone Ore'\n          - ' &7 - &f4% Lapis Ore'\n          - ' &7 - &f2% Iron Ore'\n          - '&7'\n          - '&3Price: &f$75,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &a(Available)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&3&lGenerator Boost &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&3Next Level: &e4'\n          - '&7'\n          - '&7Purchasing the generator upgrade'\n          - '&7will increase rates of ores from'\n          - '&7cobblestone generators in your island.'\n          - '&7'\n          - '&3Rates:'\n          - ' &7 - &f65% Stone'\n          - ' &7 - &f10% Coal Ore'\n          - ' &7 - &f9% Redstone Ore'\n          - ' &7 - &f6% Lapis Ore'\n          - ' &7 - &f4% Iron Ore'\n          - ' &7 - &f3% Gold Ore'\n          - ' &7 - &f2% Diamond Ore'\n          - ' &7 - &f1% Emerald Ore'\n          - '&7'\n          - '&3Price: &f$150,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: COBBLESTONE\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the generator rates!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n  minecarts-limit:\n    item: '&'\n    '1':\n      has-next-level:\n        type: MINECART\n        name: '&d&lMinecart Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e2'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f8x Minecarts'\n          - '&dPrice: &f$1,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '2':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e3'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f16x Minecarts'\n          - '&dPrice: &f$3,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '3':\n      has-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &a(Available)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: ENTITY_EXPERIENCE_ORB_PICKUP\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&d&lHopper Increase &c(Unavailable)'\n        lore:\n          - '&7'\n          - '&dNext Level: &e4'\n          - '&7'\n          - '&7Purchasing the minecart upgrade'\n          - '&7will increase your island''s'\n          - '&7max minecarts limit.'\n          - '&7'\n          - '&dAmount: &f32x Minecarts'\n          - '&dPrice: &f$9,000,000'\n          - '&7'\n          - '&aClick to purchase upgrade.'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n    '4':\n      has-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2\n      no-next-level:\n        type: MINECART\n        name: '&c&lMAX LEVEL'\n        lore:\n          - '&7You have reached the maximum'\n          - '&7level of the minecarts limit!'\n        sound:\n          type: BLOCK_ANVIL_PLACE\n          volume: 0.2\n          pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/values.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '{0} &n${1}'\nprevious-menu: true\n\npattern:\n  - '& & & & & & & & &'\n  - '% $ A B C D E F %'\n  - '% % G H I J K L %'\n  - '% * M N O P Q R %'\n  - '% % S T U V W X %'\n  - '& & & & & & & & &'\n\nitems:\n  '&':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '$':\n    type: MOB_SPAWNER\n    name: '&e&lSPAWNERS ->'\n    flags:\n      - HIDE_ATTRIBUTES\n  '*':\n    type: BOOK_AND_QUILL\n    name: '&e&lITEMS ->'\n  'A':\n    block: MOB_SPAWNER:IRON_GOLEM\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19'\n    name: '&e&l[!] &7Iron Golem Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'B':\n    block: MOB_SPAWNER:BLAZE\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=='\n    name: '&e&l[!] &7Blaze Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'C':\n    block: MOB_SPAWNER:SPIDER\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19'\n    name: '&e&l[!] &7Spider Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'D':\n    block: MOB_SPAWNER:COW\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19'\n    name: '&e&l[!] &7Cow Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'E':\n    block: MOB_SPAWNER:ZOMBIE\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ=='\n    name: '&e&l[!] &7Zombie Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'F':\n    block: MOB_SPAWNER:SKELETON\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ=='\n    name: '&e&l[!] &7Skeleton Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'G':\n    block: MOB_SPAWNER:CREEPER\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0='\n    name: '&e&l[!] &7Creeper Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'H':\n    block: MOB_SPAWNER:PIG_ZOMBIE\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ=='\n    name: '&e&l[!] &7Zombie Pigman Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'I':\n    block: MOB_SPAWNER:GHAST\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19'\n    name: '&e&l[!] &7Ghast Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'J':\n    block: MOB_SPAWNER:SLIME\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ=='\n    name: '&e&l[!] &7Slime Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'K':\n    block: MOB_SPAWNER:GUARDIAN\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ=='\n    name: '&e&l[!] &7Guardian Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'L':\n    block: MOB_SPAWNER:SQUID\n    type: SKULL_ITEM\n    data: 3\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ=='\n    name: '&e&l[!] &7Squid Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'M':\n    block: HOPPER\n    type: HOPPER\n    name: '&e&l[!] &7Hopper'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'N':\n    block: BEACON\n    type: BEACON\n    name: '&e&l[!] &7Beacon'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'O':\n    block: IRON_BLOCK\n    type: IRON_BLOCK\n    name: '&e&l[!] &7Iron Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'P':\n    block: GOLD_BLOCK\n    type: GOLD_BLOCK\n    name: '&e&l[!] &7Gold Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'Q':\n    block: DIAMOND_BLOCK\n    type: DIAMOND_BLOCK\n    name: '&e&l[!] &7Diamond Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'R':\n    block: EMERALD_BLOCK\n    type: EMERALD_BLOCK\n    name: '&e&l[!] &7Emerald Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'S':\n    block: BEDROCK\n    type: BEDROCK\n    name: '&e&l[!] &7Bedrock'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'T':\n    block: ENDER_CHEST\n    type: ENDER_CHEST\n    name: '&e&l[!] &7Ender Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'U':\n    block: DRAGON_EGG\n    type: DRAGON_EGG\n    name: '&e&l[!] &7Dragon Egg'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'V':\n    block: CHEST\n    type: CHEST\n    name: '&e&l[!] &7Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'W':\n    block: TRAPPED_CHEST\n    type: TRAPPED_CHEST\n    name: '&e&l[!] &7Trapped Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'X':\n    block: ENCHANTMENT_TABLE\n    type: ENCHANTMENT_TABLE\n    name: '&e&l[!] &7Enchantment Table'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'"
  },
  {
    "path": "src/main/resources/menus/values1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '{0} &n${1}'\nprevious-menu: true\n\npattern:\n  - '& & & & & & & & &'\n  - '% $ A B C D E F %'\n  - '% % G H I J K L %'\n  - '% * M N O P Q R %'\n  - '% % S T U V W X %'\n  - '& & & & & & & & &'\n\nitems:\n  '&':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '$':\n    type: SPAWNER\n    name: '&e&lSPAWNERS ->'\n    flags:\n      - HIDE_ATTRIBUTES\n  '*':\n    type: WRITABLE_BOOK\n    name: '&e&lITEMS ->'\n  'A':\n    block: SPAWNER:IRON_GOLEM\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19'\n    name: '&e&l[!] &7Iron Golem Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'B':\n    block: SPAWNER:BLAZE\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=='\n    name: '&e&l[!] &7Blaze Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'C':\n    block: SPAWNER:SPIDER\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19'\n    name: '&e&l[!] &7Spider Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'D':\n    block: SPAWNER:COW\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19'\n    name: '&e&l[!] &7Cow Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'E':\n    block: SPAWNER:ZOMBIE\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ=='\n    name: '&e&l[!] &7Zombie Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'F':\n    block: SPAWNER:SKELETON\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ=='\n    name: '&e&l[!] &7Skeleton Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'G':\n    block: SPAWNER:CREEPER\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0='\n    name: '&e&l[!] &7Creeper Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'H':\n    block: SPAWNER:ZOMBIFIED_PIGLIN\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0='\n    name: '&e&l[!] &7Zombified Piglin Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'I':\n    block: SPAWNER:GHAST\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19'\n    name: '&e&l[!] &7Ghast Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'J':\n    block: SPAWNER:SLIME\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ=='\n    name: '&e&l[!] &7Slime Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'K':\n    block: SPAWNER:GUARDIAN\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ=='\n    name: '&e&l[!] &7Guardian Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'L':\n    block: SPAWNER:SQUID\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ=='\n    name: '&e&l[!] &7Squid Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'M':\n    block: HOPPER\n    type: HOPPER\n    name: '&e&l[!] &7Hopper'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'N':\n    block: BEACON\n    type: BEACON\n    name: '&e&l[!] &7Beacon'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'O':\n    block: IRON_BLOCK\n    type: IRON_BLOCK\n    name: '&e&l[!] &7Iron Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'P':\n    block: GOLD_BLOCK\n    type: GOLD_BLOCK\n    name: '&e&l[!] &7Gold Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'Q':\n    block: DIAMOND_BLOCK\n    type: DIAMOND_BLOCK\n    name: '&e&l[!] &7Diamond Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'R':\n    block: EMERALD_BLOCK\n    type: EMERALD_BLOCK\n    name: '&e&l[!] &7Emerald Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'S':\n    block: BEDROCK\n    type: BEDROCK\n    name: '&e&l[!] &7Bedrock'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'T':\n    block: ENDER_CHEST\n    type: ENDER_CHEST\n    name: '&e&l[!] &7Ender Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'U':\n    block: DRAGON_EGG\n    type: DRAGON_EGG\n    name: '&e&l[!] &7Dragon Egg'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'V':\n    block: CHEST\n    type: CHEST\n    name: '&e&l[!] &7Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'W':\n    block: TRAPPED_CHEST\n    type: TRAPPED_CHEST\n    name: '&e&l[!] &7Trapped Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'X':\n    block: ENCHANTING_TABLE\n    type: ENCHANTING_TABLE\n    name: '&e&l[!] &7Enchantment Table'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'"
  },
  {
    "path": "src/main/resources/menus/values1_20.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '{0} &n${1}'\nprevious-menu: true\n\npattern:\n  - '& & & & & & & & &'\n  - '% $ A B C D E F %'\n  - '% % G H I J K L %'\n  - '% * M N O P Q R %'\n  - '% % S T U V W X %'\n  - '& & & & & & & & &'\n\nitems:\n  '&':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '$':\n    type: SPAWNER\n    name: '&e&lSPAWNERS ->'\n    flags:\n      - HIDE_ADDITIONAL_TOOLTIP\n  '*':\n    type: WRITABLE_BOOK\n    name: '&e&lITEMS ->'\n  'A':\n    block: SPAWNER:IRON_GOLEM\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19'\n    name: '&e&l[!] &7Iron Golem Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'B':\n    block: SPAWNER:BLAZE\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=='\n    name: '&e&l[!] &7Blaze Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'C':\n    block: SPAWNER:SPIDER\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19'\n    name: '&e&l[!] &7Spider Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'D':\n    block: SPAWNER:COW\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19'\n    name: '&e&l[!] &7Cow Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'E':\n    block: SPAWNER:ZOMBIE\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ=='\n    name: '&e&l[!] &7Zombie Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'F':\n    block: SPAWNER:SKELETON\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ=='\n    name: '&e&l[!] &7Skeleton Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'G':\n    block: SPAWNER:CREEPER\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0='\n    name: '&e&l[!] &7Creeper Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'H':\n    block: SPAWNER:ZOMBIFIED_PIGLIN\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0='\n    name: '&e&l[!] &7Zombified Piglin Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'I':\n    block: SPAWNER:GHAST\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19'\n    name: '&e&l[!] &7Ghast Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'J':\n    block: SPAWNER:SLIME\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ=='\n    name: '&e&l[!] &7Slime Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'K':\n    block: SPAWNER:GUARDIAN\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ=='\n    name: '&e&l[!] &7Guardian Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'L':\n    block: SPAWNER:SQUID\n    type: PLAYER_HEAD\n    skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ=='\n    name: '&e&l[!] &7Squid Spawner'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'M':\n    block: HOPPER\n    type: HOPPER\n    name: '&e&l[!] &7Hopper'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'N':\n    block: BEACON\n    type: BEACON\n    name: '&e&l[!] &7Beacon'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'O':\n    block: IRON_BLOCK\n    type: IRON_BLOCK\n    name: '&e&l[!] &7Iron Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'P':\n    block: GOLD_BLOCK\n    type: GOLD_BLOCK\n    name: '&e&l[!] &7Gold Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'Q':\n    block: DIAMOND_BLOCK\n    type: DIAMOND_BLOCK\n    name: '&e&l[!] &7Diamond Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'R':\n    block: EMERALD_BLOCK\n    type: EMERALD_BLOCK\n    name: '&e&l[!] &7Emerald Block'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'S':\n    block: BEDROCK\n    type: BEDROCK\n    name: '&e&l[!] &7Bedrock'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'T':\n    block: ENDER_CHEST\n    type: ENDER_CHEST\n    name: '&e&l[!] &7Ender Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'U':\n    block: DRAGON_EGG\n    type: DRAGON_EGG\n    name: '&e&l[!] &7Dragon Egg'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'V':\n    block: CHEST\n    type: CHEST\n    name: '&e&l[!] &7Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'W':\n    block: TRAPPED_CHEST\n    type: TRAPPED_CHEST\n    name: '&e&l[!] &7Trapped Chest'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'\n  'X':\n    block: ENCHANTING_TABLE\n    type: ENCHANTING_TABLE\n    name: '&e&l[!] &7Enchantment Table'\n    lore:\n      - '&6&l* &e&lQuantity &fx{0}'\n      - '&6&l* &e&lWorth: &f${1}'\n      - '&6&l* &e&lLevel: &f${2}'"
  },
  {
    "path": "src/main/resources/menus/visitors.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ ~ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\nunique-visitors: '~'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: SKULL_ITEM\n    name: '&eUnique Visitors'\n    lore:\n      - '&7Click to open all-time visitors menu.'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/visitors1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ ~ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\nunique-visitors: '~'\n\nitems:\n  '@':\n    type: SKULL_ITEM\n    data: 3\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: SKULL_ITEM\n    name: '&eUnique Visitors'\n    lore:\n      - '&7Click to open all-time visitors menu.'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/visitors1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Visitors ({0})'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ ~ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\nunique-visitors: '~'\n\nitems:\n  '@':\n    type: PLAYER_HEAD\n    name: '&e{0}'\n    lore:\n      - '&7Island Owner: {1}'\n      - ''\n      - '&7Left-Click to expel the player.'\n      - '&7Right-Click to invite the player.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '~':\n    type: SKELETON_SKULL\n    name: '&eUnique Visitors'\n    lore:\n      - '&7Click to open all-time visitors menu.'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warp-categories.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp Categories'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# This lore is added to category icons.\nedit-lore:\n  - '&f '\n  - '&f '\n  - '&7&o(( &f&oLeft-Click &7&oto see island warps. ))'\n  - '&7&o(( &f&oRight-Click &7&oto edit the category. ))'\n\nitems:\n  '@':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '&cPrevious Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page 1'\n  '^':\n    type: PAPER\n    name: '&cNext Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/warp-categories1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp Categories'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# This lore is added to category icons.\nedit-lore:\n  - '&f '\n  - '&f '\n  - '&7&o(( &f&oLeft-Click &7&oto see island warps. ))'\n  - '&7&o(( &f&oRight-Click &7&oto edit the category. ))'\n\nitems:\n  '@':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n  '%':\n    type: PAPER\n    name: '&cPrevious Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page 1'\n  '^':\n    type: PAPER\n    name: '&cNext Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'"
  },
  {
    "path": "src/main/resources/menus/warp-category-icon-edit.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCategory: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ @ @ @ ~ @'\n  - '@ @ @ @ ^ @ @ @ @'\n  - '@ $ @ @ @ @ @ % @'\n  - '@ @ @ @ @ @ @ @ @'\n\nicon-type: '!'\nicon-rename: '~'\nicon-relore: '$'\nicon-confirm: '%'\nicon-slots: '^'\n\nitems:\n  '!':\n    type: DIAMOND\n    name: '&6Set Type'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item type. ))'\n  '~':\n    type: ANVIL\n    name: '&6Set Name'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item name. ))'\n  '$':\n    type: PAPER\n    name: '&6Set Lore'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item lore. ))'\n  '%':\n    type: EMERALD\n    name: '&6Confirm Changes'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto confirm all changes. ))'\n  '^':\n    type: STONE\n\nsounds:\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warp-category-icon-edit1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCategory: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ @ @ @ ~ @'\n  - '@ @ @ @ ^ @ @ @ @'\n  - '@ $ @ @ @ @ @ % @'\n  - '@ @ @ @ @ @ @ @ @'\n\nicon-type: '!'\nicon-rename: '~'\nicon-relore: '$'\nicon-confirm: '%'\nicon-slots: '^'\n\nitems:\n  '!':\n    type: DIAMOND\n    name: '&6Set Type'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item type. ))'\n  '~':\n    type: ANVIL\n    name: '&6Set Name'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item name. ))'\n  '$':\n    type: PAPER\n    name: '&6Set Lore'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item lore. ))'\n  '%':\n    type: EMERALD\n    name: '&6Confirm Changes'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto confirm all changes. ))'\n  '^':\n    type: STONE\n\nsounds:\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warp-category-manage.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCategory: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ ~ @ @ $ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nsuccess-update-sound:\n  type: ORB_PICKUP\n  volume: 0.2\n  pitch: 0.2\n\ncategory-rename: '!'\ncategory-icon: '~'\ncategory-warps: '$'\n\nitems:\n  '!':\n    type: BOOK\n    name: '&6Rename Category'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto rename the category. ))'\n  '~':\n    type: STONE\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&oYou can use the following placeholders:'\n      - '&7&o{0} is used for the warp''s name.'\n      - '&7&o{1} is used for the warp''s location.'\n      - '&7&o{2} is used for the warp''s public status.'\n      - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))'\n      - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))'\n  '$':\n    type: ENDER_PEARL\n    name: '&6Island Warps'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the category warps. ))'"
  },
  {
    "path": "src/main/resources/menus/warp-category-manage1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lCategory: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ ~ @ @ $ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nsuccess-update-sound:\n  type: ENTITY_EXPERIENCE_ORB_PICKUP\n  volume: 0.2\n  pitch: 0.2\n\ncategory-rename: '!'\ncategory-icon: '~'\ncategory-warps: '$'\n\nitems:\n  '!':\n    type: BOOK\n    name: '&6Rename Category'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto rename the category. ))'\n  '~':\n    type: STONE\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&oYou can use the following placeholders:'\n      - '&7&o{0} is used for the warp''s name.'\n      - '&7&o{1} is used for the warp''s location.'\n      - '&7&o{2} is used for the warp''s public status.'\n      - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))'\n      - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))'\n  '$':\n    type: ENDER_PEARL\n    name: '&6Island Warps'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the category warps. ))'"
  },
  {
    "path": "src/main/resources/menus/warp-icon-edit.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ @ @ @ ~ @'\n  - '@ @ @ @ ^ @ @ @ @'\n  - '@ $ @ @ @ @ @ % @'\n  - '@ @ @ @ @ @ @ @ @'\n\nicon-type: '!'\nicon-rename: '~'\nicon-relore: '$'\nicon-confirm: '%'\nicon-slots: '^'\n\nitems:\n  '!':\n    type: DIAMOND\n    name: '&6Set Type'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item type. ))'\n  '~':\n    type: ANVIL\n    name: '&6Set Name'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item name. ))'\n  '$':\n    type: PAPER\n    name: '&6Set Lore'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item lore. ))'\n  '%':\n    type: EMERALD\n    name: '&6Confirm Changes'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto confirm all changes. ))'\n  '^':\n    type: STONE\n\nsounds:\n  '%':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warp-icon-edit1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ ! @ @ @ @ @ ~ @'\n  - '@ @ @ @ ^ @ @ @ @'\n  - '@ $ @ @ @ @ @ % @'\n  - '@ @ @ @ @ @ @ @ @'\n\nicon-type: '!'\nicon-rename: '~'\nicon-relore: '$'\nicon-confirm: '%'\nicon-slots: '^'\n\nitems:\n  '!':\n    type: DIAMOND\n    name: '&6Set Type'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item type. ))'\n  '~':\n    type: ANVIL\n    name: '&6Set Name'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item name. ))'\n  '$':\n    type: PAPER\n    name: '&6Set Lore'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto edit the item lore. ))'\n  '%':\n    type: EMERALD\n    name: '&6Confirm Changes'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto confirm all changes. ))'\n  '^':\n    type: STONE\n\nsounds:\n  '%':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warp-manage.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ ! @ % @ $ @ @'\n  - '@ @ @ @ ~ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nsuccess-update-sound:\n  type: ORB_PICKUP\n  volume: 0.2\n  pitch: 0.2\n\nwarp-rename: '!'\nwarp-icon: '~'\nwarp-location: '$'\nwarp-private: '%'\n\nitems:\n  '!':\n    type: BOOK\n    name: '&6Rename Warp'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto rename the warp. ))'\n  '~':\n    type: STONE\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&oYou can use the following placeholders:'\n      - '&7&o{0} is used for the warp''s name.'\n      - '&7&o{1} is used for the warp''s location.'\n      - '&7&o{2} is used for the warp''s public status.'\n      - '&7&o(( &f&oClick &7&oto edit the icon. ))'\n  '$':\n    type: ENDER_PEARL\n    name: '&6Warp Location'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto update the warp location. ))'\n  '%':\n    type: FEATHER\n    name: '&6Private Warp'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))'"
  },
  {
    "path": "src/main/resources/menus/warp-manage1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lWarp: {0}'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ ! @ % @ $ @ @'\n  - '@ @ @ @ ~ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n\nsuccess-update-sound:\n  type: ENTITY_EXPERIENCE_ORB_PICKUP\n  volume: 0.2\n  pitch: 0.2\n\nwarp-rename: '!'\nwarp-icon: '~'\nwarp-location: '$'\nwarp-private: '%'\n\nitems:\n  '!':\n    type: BOOK\n    name: '&6Rename Warp'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto rename the warp. ))'\n  '~':\n    type: STONE\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&oYou can use the following placeholders:'\n      - '&7&o{0} is used for the warp''s name.'\n      - '&7&o{1} is used for the warp''s location.'\n      - '&7&o{2} is used for the warp''s public status.'\n      - '&7&o(( &f&oClick &7&oto edit the icon. ))'\n  '$':\n    type: ENDER_PEARL\n    name: '&6Warp Location'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto update the warp location. ))'\n  '%':\n    type: FEATHER\n    name: '&6Private Warp'\n    lore:\n      - '&f '\n      - '&f '\n      - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))'"
  },
  {
    "path": "src/main/resources/menus/warps.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# This lore is added to warp icons.\nedit-lore:\n  - '&f '\n  - '&f '\n  - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))'\n  - '&7&o(( &f&oRight-Click &7&oto edit warp. ))'\n\nitems:\n  '@':\n    type: BOOK\n    name: '&e{0} {2}'\n    lore:\n      - '&7Located at {1}.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warps1_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# This lore is added to warp icons.\nedit-lore:\n  - '&f '\n  - '&f '\n  - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))'\n  - '&7&o(( &f&oRight-Click &7&oto edit warp. ))'\n\nitems:\n  '@':\n    type: BOOK\n    name: '&e{0} {2}'\n    lore:\n      - '&7Located at {1}.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: DOUBLE_PLANT\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: STAINED_GLASS_PANE\n    data: 15\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/menus/warps1_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\ntitle: '&lIsland Warps'\nprevious-menu: true\n\npattern:\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '@ @ @ @ @ @ @ @ @'\n  - '$ $ $ $ $ $ $ $ $'\n  - '# # % # * # ^ # #'\n\nslots: '@'\nprevious-page: '%'\ncurrent-page: '*'\nnext-page: '^'\n\n# This lore is added to warp icons.\nedit-lore:\n  - '&f '\n  - '&f '\n  - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))'\n  - '&7&o(( &f&oRight-Click &7&oto edit warp. ))'\n\nitems:\n  '@':\n    type: BOOK\n    name: '&e{0} {2}'\n    lore:\n      - '&7Located at {1}.'\n  '%':\n    type: PAPER\n    name: '{0}Previous Page'\n  '*':\n    type: SUNFLOWER\n    name: '&aCurrent Page'\n    lore:\n      - '&7Page {0}'\n  '^':\n    type: PAPER\n    name: '{0}Next Page'\n  '$':\n    type: BLACK_STAINED_GLASS_PANE\n    name: '&f'\n\nsounds:\n  '@':\n    type: ENTITY_EXPERIENCE_ORB_PICKUP\n    volume: 0.2\n    pitch: 0.2"
  },
  {
    "path": "src/main/resources/modules/bank/config.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Whether the module should be enabled.\n# When disabled, all module commands and features will also be disabled.\nenabled: true\n\n# Set the divider for the island bank money in the total island worth.\n# You can set it to 0 to disable island bank money to be calculated in island worth.\nbank-worth-rate: 1000\n\n# Should island bank balance be refunded upon island disband?\n# When set to 100, all the balance will be refunded.\n# When set to 0, no balance will be refunded.\ndisband-refund: 0\n\n# Should transaction logs of the island bank be saved to database?\n# Warning: There may be a lot of transactions, and can increase database.\nbank-logs: true\n\n# If bank-logs is enabled, whether to cache all logs to ram or not.\n# When set to true, all bank logs will be loaded when server starts and be cached on ram (Improved runtime performance).\n# When set to false, bank logs will be loaded only when needed, and get cached for 10 minutes before removed from\n# ram. May drop performance a little, however should help when there are a lot of logged bank transactions.\ncache-logs: true\n\n# All settings related to bank interest.\n# This feature is a money-generator for the islands.\n# As long as the island members are online, they will earn money.\nbank-interest:\n  # Should the feature be enabled?\n  enabled: true\n  # The interval to give the interest reward (in seconds).\n  interval: 86400\n  # The percentage out of the bank that will be given.\n  # If it's 10, then 10% out of the bank balance will be given.\n  percentage: 10\n  # The maximum time that the island owner can be offline in order to be rewarded (in seconds).\n  # Can be -1 in order to disable this restriction.\n  recent-active: 86400"
  },
  {
    "path": "src/main/resources/modules/generators/config.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Whether the module should be enabled.\n# When disabled, all module commands and features will also be disabled.\nenabled: true\n\n# Whether generators should match their intended world instead of the world they actually generate in.\n# Right now, toggling this to true will make the basalt generator to always generate nether rates, no matter\n# in which world it's generating blocks.\nmatch-generator-world: true"
  },
  {
    "path": "src/main/resources/modules/missions/categories/explorer/explorer_1.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: IslandMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 25000'\n    - 'is admin msg %player% &e&lExplorer | &7Successfully finished the mission Nether Explorer!'\n    - 'is admin msg %player% &e&lExplorer | &7Are you ready for the real challenge?'\n    - 'is admin msg %player% &e&lExplorer | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of events that will trigger the mission.\nevents:\n  - IslandSchematicPasteEvent\n\n# Requirement of the event to complete the mission.\nsuccess-check: 'event.getSchematic().endsWith(\"_nether\")'\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aNether Explorer'\n    lore:\n      - '&7Go to the Nether.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aNether Explorer'\n    lore:\n      - '&7Go to the Nether.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aNether Explorer'\n    lore:\n      - '&7Go to the Nether.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/explorer/explorer_2.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: IslandMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 150000'\n    - 'is admin msg %player% &e&lExplorer | &7Successfully finished the mission The-End Explorer!'\n    - 'is admin msg %player% &e&lExplorer | &7&oYou explored every single world on the server!'\n\n# List of events that will trigger the mission.\nevents:\n  - IslandSchematicPasteEvent\n\n# Requirement of the event to complete the mission.\nsuccess-check: 'event.getSchematic().endsWith(\"_the_end\")'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'explorer_1'\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aThe-End Explorer'\n    lore:\n      - '&7Go to The-End.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$150,000'\n      - ''\n      - '&c&l ✘ &7Locked'\n  not-completed:\n    type: PAPER\n    name: '&aThe-End Explorer'\n    lore:\n      - '&7Go to The-End.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$150,000'\n      - ''\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aThe-End Explorer'\n    lore:\n      - '&7Go to The-End.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$150,000'\n      - ''\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aThe-End Explorer'\n    lore:\n      - '&7Go to The-End.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$150,000'\n      - ''\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_1.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  items:\n    '1':\n      type: PUMPKIN_SEEDS\n      amount: 1\n    '2':\n      type: MELON_SEEDS\n      amount: 1\n  commands:\n    - 'eco give %player% 2500'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 10\n  '2':\n    types:\n      - 'POTATO'\n    amount: 10\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Carrots'\n      - '&8 - &7x10 Potatoes'\n      - '&8 - &7x10 Wheat'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/10'\n      - '&6Grown Potatoes: &7{value_potato}/10'\n      - '&6Grown Wheat: &7{value_wheat}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Carrots'\n      - '&8 - &7x10 Potatoes'\n      - '&8 - &7x10 Wheat'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &710/10'\n      - '&6Grown Potatoes: &710/10'\n      - '&6Grown Wheat: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &710/10'\n      - '&6Grown Potatoes: &710/10'\n      - '&6Grown Wheat: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  items:\n    '1':\n      type: BEETROOT_SEEDS\n      amount: 1\n    '2':\n      type: PUMPKIN_SEEDS\n      amount: 1\n    '3':\n      type: MELON_SEEDS\n      amount: 1\n  commands:\n    - 'eco give %player% 2500'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 10\n  '2':\n    types:\n      - 'POTATO'\n    amount: 10\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Carrots'\n      - '&8 - &7x10 Potatoes'\n      - '&8 - &7x10 Wheat'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Beetroot Seed'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/10'\n      - '&6Grown Potatoes: &7{value_potato}/10'\n      - '&6Grown Wheat: &7{value_wheat}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Carrots'\n      - '&8 - &7x10 Potatoes'\n      - '&8 - &7x10 Wheat'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Beetroot Seed'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &710/10'\n      - '&6Grown Potatoes: &710/10'\n      - '&6Grown Wheat: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer I'\n    lore:\n      - '&7Plant a small farm.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Beetroot Seed'\n      - '&8 - &7x1 Pumpkin Seed'\n      - '&8 - &7x1 Melon Seed'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Grown Carrots: &710/10'\n      - '&6Grown Potatoes: &710/10'\n      - '&6Grown Wheat: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_2.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  items:\n    '1':\n      type: SUGAR_CANE\n      amount: 1\n    '2':\n      type: CACTUS\n      amount: 1\n  commands:\n    - 'eco give %player% 5000'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer II!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'PUMPKIN'\n    amount: 10\n  '2':\n    types:\n      - 'MELON'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Pumpkins: &7{value_pumpkin}/10'\n      - '&6Grown Melons: &7{value_melon}/10'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Pumpkins: &7{value_pumpkin}/10'\n      - '&6Grown Melons: &7{value_melon}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Beetroots'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Pumpkins: &710/10'\n      - '&6Grown Melons: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with pumpkins and melons.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Pumpkins: &710/10'\n      - '&6Grown Melons: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  items:\n    '1':\n      type: SUGAR_CANE\n      amount: 1\n    '2':\n      type: CACTUS\n      amount: 1\n  commands:\n    - 'eco give %player% 5000'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer II!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'BEETROOT'\n    amount: 10\n  '2':\n    types:\n      - 'PUMPKIN'\n    amount: 10\n  '3':\n    types:\n      - 'MELON'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with beetroots, pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Beetroots'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Beetroots: &7{value_beetroot}/10'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/10'\n      - '&6Grown Melons: &7{value_melon}/10'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with beetroots, pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Beetroots'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Beetroots: &7{value_beetroot}/10'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/10'\n      - '&6Grown Melons: &7{value_melon}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with beetroots, pumpkins and melons.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Beetroots'\n      - '&8 - &7x10 Pumpkins'\n      - '&8 - &7x10 Melons'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Beetroots: &710/10'\n      - '&6Grown Pumpkins: &710/10'\n      - '&6Grown Melons: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer II'\n    lore:\n      - '&7Expand your farm with beetroots, pumpkins and melons.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7x1 Sugar Cane'\n      - '&8 - &7x1 Cactus'\n      - '&8 - &7$5,000'\n      - ''\n      - '&6Grown Beetroots: &710/10'\n      - '&6Grown Pumpkins: &710/10'\n      - '&6Grown Melons: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_3.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'is admin rankup %player% crop-growth'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer III!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'SUGAR_CANE'\n    amount: 10\n  '2':\n    types:\n      - 'CACTUS'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/10'\n      - '&6Grown Cactus: &7{value_cactus}/10'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/10'\n      - '&6Grown Cactus: &7{value_cactus}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &710/10'\n      - '&6Grown Cactus: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &710/10'\n      - '&6Grown Cactus: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'is admin rankup %player% crop-growth'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer III!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'SUGAR_CANE'\n    amount: 10\n  '2':\n    types:\n      - 'CACTUS'\n    amount: 10\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/10'\n      - '&6Grown Cactus: &7{value_cactus}/10'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/10'\n      - '&6Grown Cactus: &7{value_cactus}/10'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7x10 Sugar Canes'\n      - '&8 - &7x10 Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &710/10'\n      - '&6Grown Cactus: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer III'\n    lore:\n      - '&7Expand your farm with sugar canes and cactus.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Sugar Canes: &710/10'\n      - '&6Grown Cactus: &710/10'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_4.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 25000'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer IV!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n  - 'farmer_3'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 64\n  '2':\n    types:\n      - 'POTATO'\n    amount: 64\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 64\n  '4':\n    types:\n      - 'PUMPKIN'\n    amount: 64\n  '5':\n    types:\n      - 'MELON'\n    amount: 64\n  '6':\n    types:\n      - 'SUGAR_CANE'\n    amount: 64\n  '7':\n    types:\n      - 'CACTUS'\n    amount: 64\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/64'\n      - '&6Grown Potatoes: &7{value_potato}/64'\n      - '&6Grown Wheat: &7{value_wheat}/64'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/64'\n      - '&6Grown Melons: &7{value_melon}/64'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/64'\n      - '&6Grown Cactus: &7{value_cactus}/64'\n      - '&c&l ✘ &7Locked'\n    amount: 4\n  not-completed:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/64'\n      - '&6Grown Potatoes: &7{value_potato}/64'\n      - '&6Grown Wheat: &7{value_wheat}/64'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/64'\n      - '&6Grown Melons: &7{value_melon}/64'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/64'\n      - '&6Grown Cactus: &7{value_cactus}/64'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 4\n  can-complete:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &764/64'\n      - '&6Grown Potatoes: &764/64'\n      - '&6Grown Wheat: &764/64'\n      - '&6Grown Pumpkins: &764/64'\n      - '&6Grown Melons: &764/64'\n      - '&6Grown Sugar Canes: &764/64'\n      - '&6Grown Cactus: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 4\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &764/64'\n      - '&6Grown Potatoes: &764/64'\n      - '&6Grown Wheat: &764/64'\n      - '&6Grown Pumpkins: &764/64'\n      - '&6Grown Melons: &764/64'\n      - '&6Grown Sugar Canes: &764/64'\n      - '&6Grown Cactus: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 4"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 25000'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer IV!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n  - 'farmer_3'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 64\n  '2':\n    types:\n      - 'POTATO'\n    amount: 64\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 64\n  '4':\n    types:\n      - 'BEETROOT'\n    amount: 64\n  '5':\n    types:\n      - 'PUMPKIN'\n    amount: 64\n  '6':\n    types:\n      - 'MELON'\n    amount: 64\n  '7':\n    types:\n      - 'SUGAR_CANE'\n    amount: 64\n  '8':\n    types:\n      - 'CACTUS'\n    amount: 64\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/64'\n      - '&6Grown Potatoes: &7{value_potato}/64'\n      - '&6Grown Wheat: &7{value_wheat}/64'\n      - '&6Grown Beetroots: &7{value_beetroot}/64'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/64'\n      - '&6Grown Melons: &7{value_melon}/64'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/64'\n      - '&6Grown Cactus: &7{value_cactus}/64'\n      - '&c&l ✘ &7Locked'\n    amount: 4\n  not-completed:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/64'\n      - '&6Grown Potatoes: &7{value_potato}/64'\n      - '&6Grown Wheat: &7{value_wheat}/64'\n      - '&6Grown Beetroots: &7{value_beetroot}/64'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/64'\n      - '&6Grown Melons: &7{value_melon}/64'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/64'\n      - '&6Grown Cactus: &7{value_cactus}/64'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 4\n  can-complete:\n    type: PAPER\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &764/64'\n      - '&6Grown Potatoes: &764/64'\n      - '&6Grown Wheat: &764/64'\n      - '&6Grown Beetroots: &764/64'\n      - '&6Grown Pumpkins: &764/64'\n      - '&6Grown Melons: &764/64'\n      - '&6Grown Sugar Canes: &764/64'\n      - '&6Grown Cactus: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 4\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer IV'\n    lore:\n      - '&7Now that you are a professional farmer,'\n      - '&7let''s get the hands dirty.'\n      - '&7Plant x64 of each crop.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Grown Carrots: &764/64'\n      - '&6Grown Potatoes: &764/64'\n      - '&6Grown Wheat: &764/64'\n      - '&6Grown Beetroots: &764/64'\n      - '&6Grown Pumpkins: &764/64'\n      - '&6Grown Melons: &764/64'\n      - '&6Grown Sugar Canes: &764/64'\n      - '&6Grown Cactus: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 4"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_5.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 1000000'\n    - 'is admin rankup %player% crop-growth'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!'\n    - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.'\n    - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n  - 'farmer_3'\n  - 'farmer_4'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 320\n  '2':\n    types:\n      - 'POTATO'\n    amount: 320\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 320\n  '4':\n    types:\n      - 'PUMPKIN'\n    amount: 320\n  '5':\n    types:\n      - 'MELON'\n    amount: 320\n  '6':\n    types:\n      - 'SUGAR_CANE'\n    amount: 320\n  '7':\n    types:\n      - 'CACTUS'\n    amount: 320\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/320'\n      - '&6Grown Potatoes: &7{value_potato}/320'\n      - '&6Grown Wheat: &7{value_wheat}/320'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/320'\n      - '&6Grown Melons: &7{value_melon}/320'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/320'\n      - '&6Grown Cactus: &7{value_cactus}/320'\n      - '&c&l ✘ &7Locked'\n    amount: 5\n  not-completed:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/320'\n      - '&6Grown Potatoes: &7{value_potato}/320'\n      - '&6Grown Wheat: &7{value_wheat}/320'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/320'\n      - '&6Grown Melons: &7{value_melon}/320'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/320'\n      - '&6Grown Cactus: &7{value_cactus}/320'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 5\n  can-complete:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins'\n      - '&8 - &7Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7320/320'\n      - '&6Grown Potatoes: &7320/320'\n      - '&6Grown Wheat: &7320/320'\n      - '&6Grown Pumpkins: &7320/320'\n      - '&6Grown Melons: &7320/320'\n      - '&6Grown Sugar Canes: &7320/320'\n      - '&6Grown Cactus: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 5\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7320/320'\n      - '&6Grown Potatoes: &7320/320'\n      - '&6Grown Wheat: &7320/320'\n      - '&6Grown Pumpkins: &7320/320'\n      - '&6Grown Melons: &7320/320'\n      - '&6Grown Sugar Canes: &7320/320'\n      - '&6Grown Cactus: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 5"
  },
  {
    "path": "src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FarmingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should plant counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 1000000'\n    - 'is admin rankup %player% crop-growth'\n    - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!'\n    - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.'\n    - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'farmer_1'\n  - 'farmer_2'\n  - 'farmer_3'\n  - 'farmer_4'\n\n# List of all required plants must be gathered in order to complete the mission.\nrequired-plants:\n  '1':\n    types:\n      - 'CARROT'\n    amount: 320\n  '2':\n    types:\n      - 'POTATO'\n    amount: 320\n  '3':\n    types:\n      - 'WHEAT'\n    amount: 320\n  '4':\n    types:\n      - 'BEETROOT'\n    amount: 320\n  '5':\n    types:\n      - 'PUMPKIN'\n    amount: 320\n  '6':\n    types:\n      - 'MELON'\n    amount: 320\n  '7':\n    types:\n      - 'SUGAR_CANE'\n    amount: 320\n  '8':\n    types:\n      - 'CACTUS'\n    amount: 320\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/320'\n      - '&6Grown Potatoes: &7{value_potato}/320'\n      - '&6Grown Wheat: &7{value_wheat}/320'\n      - '&6Grown Beetroots: &7{value_beetroot}/320'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/320'\n      - '&6Grown Melons: &7{value_melon}/320'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/320'\n      - '&6Grown Cactus: &7{value_cactus}/320'\n      - '&c&l ✘ &7Locked'\n    amount: 5\n  not-completed:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7{value_carrot}/320'\n      - '&6Grown Potatoes: &7{value_potato}/320'\n      - '&6Grown Wheat: &7{value_wheat}/320'\n      - '&6Grown Beetroots: &7{value_beetroot}/320'\n      - '&6Grown Pumpkins: &7{value_pumpkin}/320'\n      - '&6Grown Melons: &7{value_melon}/320'\n      - '&6Grown Sugar Canes: &7{value_sugar_cane}/320'\n      - '&6Grown Cactus: &7{value_cactus}/320'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 5\n  can-complete:\n    type: PAPER\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Required Plants:'\n      - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,'\n      - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7320/320'\n      - '&6Grown Potatoes: &7320/320'\n      - '&6Grown Wheat: &7320/320'\n      - '&6Grown Beetroots: &7320/320'\n      - '&6Grown Pumpkins: &7320/320'\n      - '&6Grown Melons: &7320/320'\n      - '&6Grown Sugar Canes: &7320/320'\n      - '&6Grown Cactus: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 5\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFarmer V'\n    lore:\n      - '&7Let''s go one step further,'\n      - '&7Plant 5 stacks of each crop.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000,000'\n      - '&8 - &7Crops Upgrade'\n      - ''\n      - '&6Grown Carrots: &7320/320'\n      - '&6Grown Potatoes: &7320/320'\n      - '&6Grown Wheat: &7320/320'\n      - '&6Grown Beetroots: &7320/320'\n      - '&6Grown Pumpkins: &7320/320'\n      - '&6Grown Melons: &7320/320'\n      - '&6Grown Sugar Canes: &7320/320'\n      - '&6Grown Cactus: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 5"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 2500'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman I!'\n    - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...'\n    - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'RAW_FISH'\n    amount: 5\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 5 fish.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Fish'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Fish Caught: &7{1}/5'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 5 fish.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Fish'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Fish Caught: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 5 fish.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Fish Caught: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 2500'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman I!'\n    - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...'\n    - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'COD'\n    amount: 1\n  '2':\n    types:\n      - 'SALMON'\n    amount: 1\n  '3':\n    types:\n      - 'TROPICAL_FISH'\n    amount: 1\n  '4':\n    types:\n      - 'PUFFERFISH'\n    amount: 1\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 1 fish of each type.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x1 Cod'\n      - '&8 - &7x1 Salmon'\n      - '&8 - &7x1 Tropical Fish'\n      - '&8 - &7x1 Pufferfish'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Cods Caught: &7{value_cod}/1'\n      - '&6Salmons Caught: &7{value_salmon}/1'\n      - '&6Tropical Fish Caught: &7{value_tropical_fish}/1'\n      - '&6Pufferfish Caught: &7{value_pufferfish}/1'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 1 fish of each type.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x1 Cod'\n      - '&8 - &7x1 Salmon'\n      - '&8 - &7x1 Tropical Fish'\n      - '&8 - &7x1 Pufferfish'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Cods Caught: &71/1'\n      - '&6Salmons Caught: &71/1'\n      - '&6Tropical Fish Caught: &71/1'\n      - '&6Pufferfish Caught: &71/1'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman I'\n    lore:\n      - '&7Let''s make a fish soup.'\n      - '&7Catch 1 fish of each type.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$2,500'\n      - ''\n      - '&6Cods Caught: &71/1'\n      - '&6Salmons Caught: &71/1'\n      - '&6Tropical Fish Caught: &71/1'\n      - '&6Pufferfish Caught: &71/1'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 15000'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman II!'\n    - 'is admin msg %player% &e&lFisherman | &7What about testing our luck?'\n    - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'fisherman_1'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'BOW'\n      - 'ENCHANTED_BOOK'\n      - 'FISHING_ROD'\n      - 'NAME_TAG'\n      - 'SADDLE'\n      - 'WATER_LILY'\n      - 'BOWL'\n      - 'LEATHER'\n      - 'LEATHER_BOOTS'\n      - 'ROTTEN_FLESH'\n      - 'STICK'\n      - 'STRING'\n      - 'GLASS_BOTTLE'\n      - 'BONE'\n      - 'INK_SACK'\n      - 'TRIPWIRE_HOOK'\n    amount: 5\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &7{1}/5'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &7{1}/5'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 15000'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman II!'\n    - 'is admin msg %player% &e&lFisherman | &7What about testing our luck?'\n    - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'fisherman_1'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'BOW'\n      - 'ENCHANTED_BOOK'\n      - 'FISHING_ROD'\n      - 'NAME_TAG'\n      - 'SADDLE'\n      - 'NAUTILUS_SHELL'\n      - 'LILY_PAD'\n      - 'BOWL'\n      - 'LEATHER'\n      - 'LEATHER_BOOTS'\n      - 'ROTTEN_FLESH'\n      - 'STICK'\n      - 'STRING'\n      - 'GLASS_BOTTLE'\n      - 'BONE'\n      - 'INK_SAC'\n      - 'TRIPWIRE_HOOK'\n    amount: 5\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &7{1}/5'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &7{1}/5'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x5 Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman II'\n    lore:\n      - '&7Cleaning the ocean from junk can be messy, but fun!'\n      - '&7Catch 5 items.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - ''\n      - '&6Items: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 50000'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman III!'\n    - 'is admin msg %player% &e&lFisherman | &7Now you know how fishing works!'\n    - 'is admin msg %player% &e&lFisherman | &7&oYou are now a professional Fisherman, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'fisherman_1'\n  - 'fisherman_2'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'BOW'\n      - 'ENCHANTED_BOOK'\n      - 'FISHING_ROD'\n      - 'NAME_TAG'\n      - 'SADDLE'\n    amount: 3\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &7{1}/3'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &7{1}/3'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &73/3'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &73/3'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: FishingMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 50000'\n    - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman III!'\n    - 'is admin msg %player% &e&lFisherman | &7Now you know how fishing works!'\n    - 'is admin msg %player% &e&lFisherman | &7&oYou are now a professional Fisherman, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'fisherman_1'\n  - 'fisherman_2'\n\n# List of all required caughts must be gathered in order to complete the mission.\nrequired-caughts:\n  '1':\n    types:\n      - 'BOW'\n      - 'ENCHANTED_BOOK'\n      - 'FISHING_ROD'\n      - 'NAME_TAG'\n      - 'SADDLE'\n      - 'NAUTILUS_SHELL'\n    amount: 3\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &7{1}/3'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &7{1}/3'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Required Caughts:'\n      - '&8 - &7x3 Treasure Items'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &73/3'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aFisherman III'\n    lore:\n      - '&7It''s possible to catch treasure in the ocean.'\n      - '&7Catch 3 treasure items.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$50,000'\n      - ''\n      - '&6Treasure Items: &73/3'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/miner/miner_1.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: BlocksMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should block counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Whether only naturally spawned blocks should be counted towards the mission or not.\nonly-natural-blocks: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 1000'\n    - 'is admin rankup %player% generator-rates'\n    - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner I!'\n    - 'is admin msg %player% &e&lMiner | &7Now that you are familiar with generators, mine some iron.'\n    - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of all required blocks must be gathered in order to complete the mission.\nrequired-blocks:\n  '1':\n    types:\n      - 'STONE'\n      - 'COBBLESTONE'\n    amount: 48\n  '2':\n    types:\n      - 'COAL_ORE'\n    amount: 16\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aMiner I'\n    lore:\n      - '&7Mine x48 cobblestone and x16 coal ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x48 Cobblestone'\n      - '&8 - &7x16 Coal Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &7{value_stone}/48'\n      - '&6Coal Ore Mined: &7{value_coal_ore}/16'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aMiner I'\n    lore:\n      - '&7Mine x48 cobblestone and x16 coal ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x48 Cobblestone'\n      - '&8 - &7x16 Coal Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &748/48'\n      - '&6Coal Ore Mined: &716/16'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aMiner I'\n    lore:\n      - '&7Mine x48 cobblestone and x16 coal ore.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &748/48'\n      - '&6Coal Ore Mined: &716/16'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/miner/miner_2.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: BlocksMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should block counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Whether only naturally spawned blocks should be counted towards the mission or not.\nonly-natural-blocks: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 5000'\n    - 'is admin rankup %player% generator-rates'\n    - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner II!'\n    - 'is admin msg %player% &e&lMiner | &7I like iron, mind getting more for me?'\n    - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'miner_1'\n\n# List of all required blocks must be gathered in order to complete the mission.\nrequired-blocks:\n  '1':\n    types:\n      - 'STONE'\n      - 'COBBLESTONE'\n    amount: 96\n  '2':\n    types:\n      - 'COAL_ORE'\n    amount: 32\n  '3':\n    types:\n      - 'IRON_ORE'\n    amount: 16\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aMiner II'\n    lore:\n      - '&7Continue mining for ores!'\n      - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x96 Cobblestone'\n      - '&8 - &7x32 Coal Ore'\n      - '&8 - &7x16 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$5,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &7{value_cobblestone}/96'\n      - '&6Coal Ore Mined: &7{value_coal_ore}/32'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/16'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aMiner II'\n    lore:\n      - '&7Continue mining for ores!'\n      - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x96 Cobblestone'\n      - '&8 - &7x32 Coal Ore'\n      - '&8 - &7x16 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$5,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &7{value_cobblestone}/96'\n      - '&6Coal Ore Mined: &7{value_coal_ore}/32'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/16'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aMiner II'\n    lore:\n      - '&7Continue mining for ores!'\n      - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x96 Cobblestone'\n      - '&8 - &7x32 Coal Ore'\n      - '&8 - &7x16 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$5,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &796/96'\n      - '&6Coal Ore Mined: &732/32'\n      - '&6Iron Ore Mined: &716/16'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aMiner II'\n    lore:\n      - '&7Continue mining for ores!'\n      - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$5,000'\n      - '&8 - &7Generator Upgrade'\n      - ''\n      - '&6Cobblestone Mined: &796/96'\n      - '&6Coal Ore Mined: &732/32'\n      - '&6Iron Ore Mined: &716/16'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/miner/miner_3.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: BlocksMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should block counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Whether only naturally spawned blocks should be counted towards the mission or not.\nonly-natural-blocks: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 25000'\n    - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner III!'\n    - 'is admin msg %player% &e&lMiner | &7Let''s turn you into a professional miner!'\n    - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'miner_1'\n  - 'miner_2'\n\n# List of all required blocks must be gathered in order to complete the mission.\nrequired-blocks:\n  '1':\n    types:\n      - 'COAL_ORE'\n    amount: 64\n  '2':\n    types:\n      - 'IRON_ORE'\n    amount: 64\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aMiner III'\n    lore:\n      - '&7I am willing to buy iron and coal from you.'\n      - '&7Mine x64 coal ore and x64 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x64 Coal Ore'\n      - '&8 - &7x64 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Coal Ore Mined: &7{value_coal_ore}/64'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/64'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aMiner III'\n    lore:\n      - '&7I am willing to buy iron and coal from you.'\n      - '&7Mine x64 coal ore and x64 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x64 Coal Ore'\n      - '&8 - &7x64 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Coal Ore Mined: &7{value_coal_ore}/64'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/64'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aMiner III'\n    lore:\n      - '&7I am willing to buy iron and coal from you.'\n      - '&7Mine x64 coal ore and x64 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x64 Coal Ore'\n      - '&8 - &7x64 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Coal Ore Mined: &764/64'\n      - '&6Iron Ore Mined: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aMiner III'\n    lore:\n      - '&7I am willing to buy iron and coal from you.'\n      - '&7Mine x64 coal ore and x64 iron ore.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$25,000'\n      - ''\n      - '&6Coal Ore Mined: &764/64'\n      - '&6Iron Ore Mined: &764/64'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/miner/miner_4.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: BlocksMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should block counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Whether only naturally spawned blocks should be counted towards the mission or not.\nonly-natural-blocks: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 125000'\n    - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner IV!'\n    - 'is admin msg %player% &e&lMiner | &7Are you ready for the ultimate test?'\n    - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'miner_1'\n  - 'miner_2'\n  - 'miner_3'\n\n# List of all required blocks must be gathered in order to complete the mission.\nrequired-blocks:\n  '1':\n    types:\n      - 'COAL_ORE'\n    amount: 320\n  '2':\n    types:\n      - 'IRON_ORE'\n    amount: 192\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aMiner IV'\n    lore:\n      - '&7I have more customers, I need more materials!'\n      - '&7Mine x192 coal ore and x320 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x192 Coal Ore'\n      - '&8 - &7x320 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$125,000'\n      - ''\n      - '&6Coal Ore Mined: &7{value_coal_ore}/192'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/320'\n      - '&c&l ✘ &7Locked'\n    amount: 4\n  not-completed:\n    type: PAPER\n    name: '&aMiner IV'\n    lore:\n      - '&7I have more customers, I need more materials!'\n      - '&7Mine x192 coal ore and x320 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x192 Coal Ore'\n      - '&8 - &7x320 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$125,000'\n      - ''\n      - '&6Coal Ore Mined: &7{value_coal_ore}/192'\n      - '&6Iron Ore Mined: &7{value_iron_ore}/320'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 4\n  can-complete:\n    type: PAPER\n    name: '&aMiner IV'\n    lore:\n      - '&7I have more customers, I need more materials!'\n      - '&7Mine x192 coal ore and x320 iron ore.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x192 Coal Ore'\n      - '&8 - &7x320 Iron Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$125,000'\n      - ''\n      - '&6Coal Ore Mined: &7192/192'\n      - '&6Iron Ore Mined: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 4\n    glow: true\n  completed:\n    type: MAP\n    name: '&aMiner IV'\n    lore:\n      - '&7I have more customers, I need more materials!'\n      - '&7Mine x192 coal ore and x320 iron ore.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$125,000'\n      - ''\n      - '&6Coal Ore Mined: &7192/192'\n      - '&6Iron Ore Mined: &7320/320'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 4"
  },
  {
    "path": "src/main/resources/modules/missions/categories/miner/miner_5.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: BlocksMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should block counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Whether only naturally spawned blocks should be counted towards the mission or not.\nonly-natural-blocks: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 250000'\n    - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner V!'\n    - 'is admin msg %player% &e&lMiner | &7Diamonds... diamonds... diamonds!'\n    - 'is admin msg %player% &e&lMiner | &7&oYou are now a professional Miner, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'miner_1'\n  - 'miner_2'\n  - 'miner_3'\n  - 'miner_4'\n\n# List of all required blocks must be gathered in order to complete the mission.\nrequired-blocks:\n  '1':\n    types:\n      - 'DIAMOND_ORE'\n    amount: 32\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aMiner V'\n    lore:\n      - '&7It''s time to buy the best goodies.'\n      - '&7Mine x32 diamond ores.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x32 Diamond Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - ''\n      - '&6Diamond Ore Mined: &7{1}/32'\n      - '&c&l ✘ &7Locked'\n    amount: 5\n  not-completed:\n    type: PAPER\n    name: '&aMiner V'\n    lore:\n      - '&7It''s time to buy the best goodies.'\n      - '&7Mine x32 diamond ores.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x32 Diamond Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - ''\n      - '&6Diamond Ore Mined: &7{1}/32'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 5\n  can-complete:\n    type: PAPER\n    name: '&aMiner V'\n    lore:\n      - '&7It''s time to buy the best goodies.'\n      - '&7Mine x32 diamond ores.'\n      - ''\n      - '&6Required Blocks:'\n      - '&8 - &7x32 Diamond Ore'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - ''\n      - '&6Diamond Ore Mined: &732/32'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 5\n    glow: true\n  completed:\n    type: MAP\n    name: '&aMiner V'\n    lore:\n      - '&7It''s time to buy the best goodies.'\n      - '&7Mine x32 diamond ores.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - ''\n      - '&6Diamond Ore Mined: &732/32'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 5"
  },
  {
    "path": "src/main/resources/modules/missions/categories/slayer/slayer_1.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: KillsMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should entity counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 1000'\n    - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer I!'\n    - 'is admin msg %player% &e&lSlayer | &7Your sword hasn''t seen blood yet... Kill more mobs!'\n    - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of all required entities must be gathered in order to complete the mission.\nrequired-entities:\n  '1':\n    types:\n      - 'SKELETON'\n      - 'CREEPER'\n      - 'ZOMBIE'\n      - 'SPIDER'\n    amount: 5\n\n# Icons used in the menus.\nicons:\n  not-completed:\n    type: PAPER\n    name: '&aSlayer I'\n    lore:\n      - '&7Kill 5 hostile mobs.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x5 Skeletons/Creepers/Zombies/Spiders'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - ''\n      - '&6Hostiles Killed: &7{1}/5'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n  can-complete:\n    type: PAPER\n    name: '&aSlayer I'\n    lore:\n      - '&7Kill 5 hostile mobs.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x5 Skeletons/Creepers/Zombies/Spiders'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - ''\n      - '&6Hostiles Killed: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    glow: true\n  completed:\n    type: MAP\n    name: '&aSlayer I'\n    lore:\n      - '&7Kill 5 hostile mobs.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$1,000'\n      - ''\n      - '&6Hostiles Killed: &75/5'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'"
  },
  {
    "path": "src/main/resources/modules/missions/categories/slayer/slayer_2.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: KillsMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should entity counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 15000'\n    - 'is admin unlockworld %player% nether true'\n    - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer II!'\n    - 'is admin msg %player% &e&lSlayer | &7Explore the nether, bring some goodies back home.'\n    - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'slayer_1'\n\n# List of all required entities must be gathered in order to complete the mission.\nrequired-entities:\n  '1':\n    types:\n      - 'SKELETON'\n    amount: 32\n  '2':\n    types:\n      - 'ZOMBIE'\n    amount: 32\n  '3':\n    types:\n      - 'SPIDER'\n    amount: 32\n  '4':\n    types:\n      - 'CREEPER'\n    amount: 24\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aSlayer II'\n    lore:\n      - '&7It is time you build a farm.'\n      - '&7Kill 120 hostile mobs.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x32 Skeletons'\n      - '&8 - &7x32 Zombies'\n      - '&8 - &7x32 Spiders'\n      - '&8 - &7x24 Creepers'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - '&8 - &7Unlock Nether'\n      - ''\n      - '&6Skeletons Killed: &7{value_skeleton}/32'\n      - '&6Zombies Killed: &7{value_zombie}/32'\n      - '&6Spiders Killed: &7{value_spider}/32'\n      - '&6Creepers Killed: &7{value_creeper}/24'\n      - '&c&l ✘ &7Locked'\n    amount: 2\n  not-completed:\n    type: PAPER\n    name: '&aSlayer II'\n    lore:\n      - '&7It is time you build a farm.'\n      - '&7Kill 120 hostile mobs.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x32 Skeletons'\n      - '&8 - &7x32 Zombies'\n      - '&8 - &7x32 Spiders'\n      - '&8 - &7x24 Creepers'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - '&8 - &7Unlock Nether'\n      - ''\n      - '&6Skeletons Killed: &7{value_skeleton}/32'\n      - '&6Zombies Killed: &7{value_zombie}/32'\n      - '&6Spiders Killed: &7{value_spider}/32'\n      - '&6Creepers Killed: &7{value_creeper}/24'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 2\n  can-complete:\n    type: PAPER\n    name: '&aSlayer II'\n    lore:\n      - '&7It is time you build a farm.'\n      - '&7Kill 120 hostile mobs.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x32 Skeletons'\n      - '&8 - &7x32 Zombies'\n      - '&8 - &7x32 Spiders'\n      - '&8 - &7x24 Creepers'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - '&8 - &7Unlock Nether'\n      - ''\n      - '&6Skeletons Killed: &732/32'\n      - '&6Zombies Killed: &732/32'\n      - '&6Spiders Killed: &732/32'\n      - '&6Creepers Killed: &724/24'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 2\n    glow: true\n  completed:\n    type: MAP\n    name: '&aSlayer II'\n    lore:\n      - '&7It is time you build a farm.'\n      - '&7Kill 120 hostile mobs.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$15,000'\n      - '&8 - &7Unlock Nether'\n      - ''\n      - '&6Skeletons Killed: &732/32'\n      - '&6Zombies Killed: &732/32'\n      - '&6Spiders Killed: &732/32'\n      - '&6Creepers Killed: &724/24'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 2"
  },
  {
    "path": "src/main/resources/modules/missions/categories/slayer/slayer_3.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: KillsMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should entity counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 75000'\n    - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer III!'\n    - 'is admin msg %player% &e&lSlayer | &7It is time to show who is the boss here.'\n    - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'slayer_1'\n  - 'slayer_2'\n\n# List of all required entities must be gathered in order to complete the mission.\nrequired-entities:\n  '1':\n    types:\n      - 'BLAZE'\n    amount: 12\n  '2':\n    types:\n      - 'ENDERMAN'\n    amount: 24\n  '3':\n    types:\n      - 'WITHER_SKELETON'\n    amount: 12\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aSlayer III'\n    lore:\n      - '&7It is time to prepare for the boss fights.'\n      - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x12 Blazes'\n      - '&8 - &7x12 Wither Skeletons'\n      - '&8 - &7x24 Endermans'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$75,000'\n      - ''\n      - '&6Blazes Killed: &7{value_blaze}/12'\n      - '&6Wither Skeletons Killed: &7{value_wither_skeleton}/12'\n      - '&6Endermans Killed: &7{value_enderman}/24'\n      - '&c&l ✘ &7Locked'\n    amount: 3\n  not-completed:\n    type: PAPER\n    name: '&aSlayer III'\n    lore:\n      - '&7It is time to prepare for the boss fights.'\n      - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x12 Blazes'\n      - '&8 - &7x12 Wither Skeletons'\n      - '&8 - &7x24 Endermans'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$75,000'\n      - ''\n      - '&6Blazes Killed: &7{value_blaze}/12'\n      - '&6Wither Skeletons Killed: &7{value_wither_skeleton}/12'\n      - '&6Endermans Killed: &7{value_enderman}/24'\n      - '&6Progress: &7{0}%'\n      - '&c&l ✘ &7Not Completed'\n    amount: 3\n  can-complete:\n    type: PAPER\n    name: '&aSlayer III'\n    lore:\n      - '&7It is time to prepare for the boss fights.'\n      - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x12 Blazes'\n      - '&8 - &7x12 Wither Skeletons'\n      - '&8 - &7x24 Endermans'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$75,000'\n      - ''\n      - '&6Blazes Killed: &712/12'\n      - '&6Wither Skeletons Killed: &712/12'\n      - '&6Endermans Killed: &724/24'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 3\n    glow: true\n  completed:\n    type: MAP\n    name: '&aSlayer III'\n    lore:\n      - '&7It is time to prepare for the boss fights.'\n      - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$75,000'\n      - ''\n      - '&6Blazes Killed: &712/12'\n      - '&6Wither Skeletons Killed: &712/12'\n      - '&6Endermans Killed: &724/24'\n      - '&6Progress: &7100%'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 3"
  },
  {
    "path": "src/main/resources/modules/missions/categories/slayer/slayer_4.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# The mission file to use\nmission-file: KillsMissions\n\n# Whether the mission should be given when completing all requirements.\nauto-reward: true\n\n# Should entity counts of players get reset when completing the mission?\nreset-after-finish: true\n\n# Rewards given when completing the mission.\nrewards:\n  commands:\n    - 'eco give %player% 250000'\n    - 'is admin unlockworld %player% the_end true'\n    - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer IV!'\n    - 'is admin msg %player% &e&lSlayer | &7You passed all the tests, you are ready now for the end...'\n    - 'is admin msg %player% &e&lSlayer | &7&oYou are now a professional Slayer, congratz!'\n\n# List of required missions that must be completed before completing this one.\nrequired-missions:\n  - 'slayer_1'\n  - 'slayer_2'\n  - 'slayer_3'\n\n# List of all required entities must be gathered in order to complete the mission.\nrequired-entities:\n  '1':\n    types:\n      - 'WITHER'\n    amount: 1\n\n# Icons used in the menus.\nicons:\n  locked:\n    type: PAPER\n    name: '&aSlayer IV'\n    lore:\n      - '&7Before the end, there is one mission left.'\n      - '&7Kill the wither.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x1 Wither'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - '&8 - &7Unlock The End'\n      - ''\n      - '&6Wither Killed: &c&l✘'\n      - '&c&l ✘ &7Locked'\n    amount: 4\n  not-completed:\n    type: PAPER\n    name: '&aSlayer IV'\n    lore:\n      - '&7Before the end, there is one mission left.'\n      - '&7Kill the wither.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x1 Wither'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - '&8 - &7Unlock The End'\n      - ''\n      - '&6Wither Killed: &c&l✘'\n      - '&c&l ✘ &7Not Completed'\n    amount: 4\n  can-complete:\n    type: PAPER\n    name: '&aSlayer IV'\n    lore:\n      - '&7Before the end, there is one mission left.'\n      - '&7Kill the wither.'\n      - ''\n      - '&6Required Kills:'\n      - '&8 - &7x1 Wither'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - '&8 - &7Unlock The End'\n      - ''\n      - '&6Wither Killed: &a&l✔'\n      - '&a&l ✔ &7Click to redeem your reward.'\n    amount: 4\n    glow: true\n  completed:\n    type: MAP\n    name: '&aSlayer IV'\n    lore:\n      - '&7Before the end, there is one mission left.'\n      - '&7Kill the wither.'\n      - ''\n      - '&6Rewards:'\n      - '&8 - &7$250,000'\n      - '&8 - &7Unlock The End'\n      - ''\n      - '&6Wither Killed: &a&l✔'\n      - '&a&l ✔ &7Already Claimed.'\n    amount: 4"
  },
  {
    "path": "src/main/resources/modules/missions/config.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Whether the module should be enabled.\n# When disabled, all module commands and features will also be disabled.\nenabled: true\n\n# Should mission rewards be automatically claimed outside island worlds?\n# When disabled, rewards for missions with auto-reward enabled will be\n# automatically claimed only in island worlds.\nauto-reward-outside-islands: false\n\n# Settings related to mission categories.\n# A tutorial about configuring missions can be found here:\n# https://wiki.bg-software.com/superiorskyblock/missions\ncategories:\n  miner:\n    name: 'Miner'\n    slot: 20\n\n  slayer:\n    name: 'Slayer'\n    slot: 21\n\n  farmer:\n    name: 'Farmer'\n    slot: 22\n\n  fisherman:\n    name: 'Fisherman'\n    slot: 23\n\n  explorer:\n    name: 'Explorer'\n    slot: 24"
  },
  {
    "path": "src/main/resources/modules/upgrades/config.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# Whether the module should be enabled.\n# When disabled, all module commands and features will also be disabled.\nenabled: true\n\n# Whether crop-growth should be enabled.\n# When disabled, the plugin will not alter crop growth.\ncrop-growth: true\n\n# Whether mob drops should be enabled.\n# When disabled, the plugin will not alter mob drops.\nmob-drops: true\n\n# Whether island-effects should be enabled.\n# When disabled, the plugin will not give any effects to any players.\nisland-effects: true\n\n# Whether spawner-rates should be enabled.\n# When disabled, the plugin will not alter spawner rates.\nspawner-rates: true\n\n# Whether block-limits should be enabled.\n# When disabled, the plugin will not limit placement of blocks.\nblock-limits: true\n\n# Whether entity-limits should be enabled.\n# When disabled, the plugin will not limit spawning of entities.\nentity-limits: true\n\n# All the upgrades of the plugin\n# https://wiki.bg-software.com/superiorskyblock/upgrades\nupgrades:\n  hoppers-limit:\n    '1':\n      price: 1000000.0\n      price-type: \"Money\"\n      block-limits:\n        HOPPER: 8\n      commands:\n        - 'island admin setupgrade %player% hoppers-limit 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 16!'\n    '2':\n      price: 3000000.0\n      price-type: \"Money\"\n      block-limits:\n        HOPPER: 16\n      commands:\n        - 'island admin setupgrade %player% hoppers-limit 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 32!'\n    '3':\n      price: 9000000.0\n      price-type: \"Money\"\n      block-limits:\n        HOPPER: 32\n      commands:\n        - 'island admin setupgrade %player% hoppers-limit 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 64!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      block-limits:\n        HOPPER: 64\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for hoppers limit.'\n  crop-growth:\n    '1':\n      price: 100000.0\n      price-type: \"Money\"\n      crop-growth: 1\n      commands:\n        - 'island admin setupgrade %player% crop-growth 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x2!'\n    '2':\n      price: 500000.0\n      price-type: \"Money\"\n      crop-growth: 15\n      commands:\n        - 'island admin setupgrade %player% crop-growth 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x3!'\n    '3':\n      price: 1000000.0\n      price-type: \"Money\"\n      crop-growth: 25\n      commands:\n        - 'island admin setupgrade %player% crop-growth 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x4!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      crop-growth: 40\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for crop growth.'\n  spawner-rates:\n    '1':\n      price: 500000.0\n      price-type: \"Money\"\n      spawner-rates: 1\n      commands:\n        - 'island admin setupgrade %player% spawner-rates 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x2!'\n    '2':\n      price: 1000000.0\n      price-type: \"Money\"\n      spawner-rates: 2\n      commands:\n        - 'island admin setupgrade %player% spawner-rates 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x3!'\n    '3':\n      price: 2500000.0\n      price-type: \"Money\"\n      spawner-rates: 3\n      commands:\n        - 'island admin setupgrade %player% spawner-rates 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x4!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      spawner-rates: 4\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for spawner-rates.'\n  mob-drops:\n    '1':\n      price: 1000000.0\n      price-type: \"Money\"\n      mob-drops: 1\n      commands:\n        - 'island admin setupgrade %player% mob-drops 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x2!'\n    '2':\n      price: 2000000.0\n      price-type: \"Money\"\n      mob-drops: 2\n      commands:\n        - 'island admin setupgrade %player% mob-drops 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x3!'\n    '3':\n      price: 5000000.0\n      price-type: \"Money\"\n      mob-drops: 3\n      commands:\n        - 'island admin setupgrade %player% mob-drops 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x4!'\n    '4':\n      price: 0.0\n      mob-drops: 4\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for mob-drops.'\n  members-limit:\n    '1':\n      price: 100000.0\n      price-type: \"Money\"\n      team-limit: 4\n      commands:\n        - 'island admin setupgrade %player% members-limit 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 8!'\n    '2':\n      price: 300000.0\n      price-type: \"Money\"\n      team-limit: 8\n      commands:\n        - 'island admin setupgrade %player% members-limit 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 16!'\n    '3':\n      price: 500000.0\n      price-type: \"Money\"\n      team-limit: 16\n      commands:\n        - 'island admin setupgrade %player% members-limit 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 32!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      team-limit: 32\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for members limit.'\n  border-size:\n    '1':\n      price: 30000.0\n      price-type: \"Money\"\n      border-size: 25\n      commands:\n        - 'island admin setupgrade %player% border-size 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 100x100 blocks!'\n    '2':\n      price: 80000.0\n      price-type: \"Money\"\n      border-size: 50\n      commands:\n        - 'island admin setupgrade %player% border-size 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 150x150 blocks!'\n    '3':\n      price: 150000.0\n      price-type: \"Money\"\n      border-size: 75\n      commands:\n        - 'island admin setupgrade %player% border-size 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 250x250 blocks!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      border-size: 125\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for border size.'\n  generator-rates:\n    '1':\n      price: 25000.0\n      price-type: \"Money\"\n      generator-rates:\n        normal:\n          STONE: 95\n          COAL_ORE: 5\n      commands:\n        - 'island admin setupgrade %player% generator-rates 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 2!'\n    '2':\n      price: 75000.0\n      price-type: \"Money\"\n      generator-rates:\n        normal:\n          STONE: 92\n          COAL_ORE: 5\n          REDSTONE_ORE: 3\n      commands:\n        - 'island admin setupgrade %player% generator-rates 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 3!'\n    '3':\n      price: 150000.0\n      price-type: \"Money\"\n      generator-rates:\n        normal:\n          STONE: 80\n          COAL_ORE: 8\n          REDSTONE_ORE: 6\n          LAPIS_ORE: 4\n          IRON_ORE: 2\n      commands:\n        - 'island admin setupgrade %player% generator-rates 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 4!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      generator-rates:\n        normal:\n          STONE: 65\n          COAL_ORE: 10\n          REDSTONE_ORE: 9\n          LAPIS_ORE: 6\n          IRON_ORE: 4\n          GOLD_ORE: 3\n          DIAMOND_ORE: 2\n          EMERALD_ORE: 1\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for generator.'\n  minecarts-limit:\n    '1':\n      price: 1000000.0\n      price-type: \"Money\"\n      entity-limits:\n        MINECART: 4\n      commands:\n        - 'island admin setupgrade %player% minecarts-limit 2'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 8!'\n    '2':\n      price: 3000000.0\n      price-type: \"Money\"\n      entity-limits:\n        MINECART: 8\n      commands:\n        - 'island admin setupgrade %player% minecarts-limit 3'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 16!'\n    '3':\n      price: 9000000.0\n      price-type: \"Money\"\n      entity-limits:\n        MINECART: 16\n      commands:\n        - 'island admin setupgrade %player% minecarts-limit 4'\n        - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 32!'\n    '4':\n      price: 0.0\n      price-type: \"Money\"\n      entity-limits:\n        MINECART: 32\n      commands:\n        - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for minecarts limit.'"
  },
  {
    "path": "src/main/resources/plugin.yml",
    "content": "name: SuperiorSkyblock2\nversion: ${project.version}\nmain: com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin\n\ndescription: Feature packed Skyblock core.\nwebsite: https://bg-software.com/\napi-version: '1.13'\nauthor: Ome_R\n\n# Custom section used by DependenciesManager, which replaces softdepend.\nclass-depends:\n  - AdvancedSpawners\n  - CMI\n  - ChangeSkin\n  - CoreProtect\n  - EpicSpawners\n  - Essentials\n  - FastAsyncWorldEdit\n  - ItemsAdder\n  - JetsMinions\n  - LuckPerms\n  - MergedSpawner\n  - MVdWPlaceholderAPI\n  - Oraxen\n  - PlaceholderAPI\n  - ProtocolLib\n  - PvpingSpawners\n  - RoseStacker\n  - ShopGUIPlus\n  - SilkSpawners\n  - SkinsRestorer\n  - SlimeWorldManager\n  - SuperVanish\n  - UltimateStacker\n  - VanishNoPacket\n  - Vault\n  - WildStacker\n  - WorldEdit\n\nloadbefore:\n  - Multiverse-Core\n  - Slimefun\n  - My_Worlds\n\nlibraries:\n  - org.openjdk.nashorn:nashorn-core:15.4\n\npermissions:\n  superior.*:\n    description: Permission for all admin & island commands\n    default: op\n    children:\n      superior.island.*:\n        description: Permission for all island commands\n        children:\n          superior.island.accept:\n            description: Accept an invitation from a player.\n          superior.island.balance:\n            description: Check the amount of money inside an island's bank.\n          superior.island.ban:\n            description: Ban a player from your island.\n          superior.island.bank:\n            description: Open the island's bank.\n          superior.island.bans:\n            description: Open the bans menu.\n          superior.island.biome:\n            description: Change the biome of the island.\n          superior.island.border:\n            description: Change the border color of the islands.\n          superior.island.chest:\n            description: Open the island's chest.\n          superior.island.close:\n            description: Close the island to the public.\n          superior.island.coop:\n            description: Add a player as a co-op to your island.\n          superior.island.coops:\n            description: Open the coops menu.\n          superior.island.counts:\n            description: See block counts in your island.\n          superior.island.create:\n            description: Create a new island.\n          superior.island.delwarp:\n            description: Delete an island warp.\n          superior.island.demote:\n            description: Demote a member in your island.\n          superior.island.deposit:\n            description: Deposit money from your personal account into the island's bank.\n          superior.island.disband:\n            description: Disband your island permanently.\n          superior.island.expel:\n            description: Kick a visitor from your island.\n          superior.island.fly:\n            description: Toggle island fly.\n          superior.island.help:\n            description: List of all commands.\n          superior.island.invite:\n            description: Invite a player to your island.\n          superior.island.kick:\n            description: Kick a player from your island.\n          superior.island.lang:\n            description: Change your personal language.\n          superior.island.leave:\n            description: Leave your island.\n          superior.island.mission:\n            description: Complete a mission.\n          superior.island.missions:\n            description: Open the missions menu.\n          superior.island.name:\n            description: Change the name of your island.\n          superior.island.open:\n            description: Open the island to the public.\n          superior.island.panel:\n            description: Open island panel.\n            children:\n              superior.island.visitors:\n                description: Open the visitors menu.\n              superior.island.members:\n                description: Open the members menu.\n          superior.island.pardon:\n            description: Unban a player from your island.\n          superior.island.permissions:\n            description: Get all permissions for an island role.\n          superior.island.promote:\n            description: Promote a member in your island.\n          superior.island.rankup:\n            description: Level up an upgrade.\n          superior.island.rate:\n            description: Rate an island.\n          superior.island.ratings:\n            description: Show all island ratings.\n          superior.island.recalc:\n            description: Re-calculates the island worth.\n          superior.island.setdiscord:\n            description: Set the discord of the island for island payouts.\n          superior.island.setpaypal:\n            description: Set the paypal email of the island for island payouts.\n          superior.island.setrole:\n            description: Change the role of a player in your island.\n          superior.island.setteleport:\n            description: Change the teleport location of your island.\n          superior.island.settings:\n            description: Open the settings menu.\n          superior.island.setwarp:\n            description: Create a new island warp.\n          superior.island.show:\n            description: Get information about an island.\n          superior.island.stacker.*:\n            description: Gives the ability to stack blocks.\n          superior.island.team:\n            description: Get information about island members status.\n          superior.island.teamchat:\n            description: Toggle team chat mode.\n          superior.island.teleport:\n            description: Teleport to your island.\n          superior.island.toggle:\n            description: Permission to use the /is toggle command.\n            children:\n              superior.island.toggle.border:\n                description: Toggle island borders.\n              superior.island.toggle.blocks:\n                description: Toggle stacked blocks placements.\n          superior.island.top:\n            description: Open top islands panel.\n          superior.island.transfer:\n            description: Transfer your island's leadership.\n          superior.island.uncoop:\n            description: Remove a player from being a co-op in your island.\n          superior.island.upgrade:\n            description: Open upgrades panel.\n          superior.island.value:\n            description: Get the worth value of a block.\n          superior.island.values:\n            description: Open the values menu.\n          superior.island.visit:\n            description: Teleport to the visitors location of an island.\n          superior.island.warp:\n            description: Warp to an island warp.\n          superior.island.warps:\n            description: List of island warps.\n          superior.island.withdraw:\n            description: Withdraw money from your island's bank into your personal account.\n      superior.admin.*:\n        description: Permission for all admin commands\n        default: op\n        children:\n          superior.admin:\n            description: Use the admin commands.\n          superior.admin.add:\n            description: Add a user to an island.\n          superior.admin.addbanklimit:\n            description: Increase the bank limit for another player's island.\n          superior.admin.addblocklimit:\n            description: Increase block limit for another player's island.\n          superior.admin.addbonus:\n            description: Add a bonus to a player.\n          superior.admin.addcooplimit:\n            description: Increase coop players limit for another player's island.\n          superior.admin.addcropgrowth:\n            description: Increase the crop growth multiplier for another player's island.\n          superior.admin.addeffect:\n            description: Add an island effect for another player's island.\n          superior.admin.addentitylimit:\n            description: Increase entity limit for another player's island.\n          superior.admin.addgenerator:\n            description: Add percentage of a material for the cobblestone generator.\n          superior.admin.addmobdrops:\n            description: Increase the mob drops multiplier for another player's island.\n          superior.admin.addsize:\n            description: Expand another player's island size.\n          superior.admin.addspawnerrates:\n            description: Increase the spawner rates multiplier for another player's island.\n          superior.admin.addteamlimit:\n            description: Increase members limit for another player's island.\n          superior.admin.addwarpslimit:\n            description: Increase the warps limit of an island.\n          superior.admin.bonus:\n            description: Grant a bonus to a player.\n          superior.admin.bypass:\n            description: Toggle bypass mode.\n          superior.admin.bypass.warmup:\n            description: Bypass teleport warmup\n          superior.admin.chest:\n            description: Open island's chest of another island.\n          superior.admin.cleargenerator:\n            description: Clear generator rates for a specific island.\n          superior.admin.close:\n            description: Close an island to the public.\n          superior.admin.count:\n            description: Check a block count on a specific island.\n          superior.admin.delwarp:\n            description: Delete a warp for an island.\n          superior.admin.demote:\n            description: Demote a member in another player's island.\n          superior.admin.deposit:\n            description: Deposit money into another player's island bank.\n          superior.admin.disband:\n            description: Disband another player's island permanently.\n          superior.admin.fly:\n            description: Toggle island fly for another player.\n          superior.admin.givedisbands:\n            description: Give disbands to a player.\n          superior.admin.ignore:\n            description: Ignore an island from top islands.\n          superior.admin.join:\n            description: Join an island without an invitation.\n          superior.admin.kick:\n            description: Kick a player from his island.\n          superior.admin.modules:\n            description: Manage modules of the plugin.\n          superior.admin.mission:\n            description: Change the status of a mission for a player.\n          superior.admin.msg:\n            description: Send a player a message without any prefixes.\n          superior.admin.msgall:\n            description: Send to all island members a message without any prefixes.\n          superior.admin.name:\n            description: Change the name of an island.\n          superior.admin.open:\n            description: Open an island to the public.\n          superior.admin.openmenu:\n            description: Open a custom menu for a player.\n          superior.admin.promote:\n            description: Promote a member in another player's island.\n          superior.admin.purge:\n            description: Purge islands from database.\n          superior.admin.rankup:\n            description: Rankup an upgrade for an island.\n          superior.admin.recalc:\n            description: Re-calculates the worth of an island.\n          superior.admin.reload:\n            description: Reload all configurations and tasks of the plugin.\n          superior.admin.removeblocklimit:\n            description: Remove a block limit for an island.\n          superior.admin.removeentitylimit:\n            description: Remove an entity limit for an island.\n          superior.admin.removeratings:\n            description: Remove all ratings given by a player.\n          superior.admin.resetpermissions:\n            description: Reset all island permissions for a specific island.\n          superior.admin.resetsettings:\n            description: Reset all island settings for a specific island.\n          superior.admin.resetworld:\n            description: Reset a world for an island.\n          superior.admin.schematic:\n            description: Create schematics for the plugin.\n          superior.admin.setbanklimit:\n            description: Set the bank limit for another player's island.\n          superior.admin.setbiome:\n            description: Set the biome of an island.\n          superior.admin.setblockamount:\n            description: Set the block amount in a specific location.\n          superior.admin.setblocklimit:\n            description: Set block limit for another player's island.\n          superior.admin.setchestrow:\n            description: Set the chest rows for another player's island.\n          superior.admin.setcooplimit:\n            description: Set coop players limit for another player's island.\n          superior.admin.setcropgrowth:\n            description: Set the crop growth multiplier for another player's island.\n          superior.admin.setdisbands:\n            description: Set a player's amount of island disbands.\n          superior.admin.seteffect:\n            description: Set the island effect level of another player's island.\n          superior.admin.setentitylimit:\n            description: Set entity limit for another player's island.\n          superior.admin.setgenerator:\n            description: Change percentage of a material for the cobblestone generator.\n          superior.admin.setislandpreview:\n            description: Set the preview location for an island.\n          superior.admin.setleader:\n            description: Transfer an island to someone else.\n          superior.admin.setmobdrops:\n            description: Set the mob drops multiplier for another player's island.\n          superior.admin.setpermission:\n            description: Set a required role for a permission for all the islands.\n          superior.admin.setrate:\n            description: Set the rating of another player.\n          superior.admin.setrolelimit:\n            description: Set role limit for another player's island.\n          superior.admin.setsettings:\n            description: Toggle settings for a specific island.\n          superior.admin.setsize:\n            description: Change another player's island size.\n          superior.admin.setspawn:\n            description: Set the spawn location of the server.\n          superior.admin.setspawnerrates:\n            description: Set the spawner rates multiplier for another player's island.\n          superior.admin.setteamlimit:\n            description: Set members limit for another player's island.\n          superior.admin.settings:\n            description: Open the plugin settings editor.\n          superior.admin.setupgrade:\n            description: Set the level of an upgrade for another player's island.\n          superior.admin.setwarpslimit:\n            description: Set the warps limit of an island.\n          superior.admin.show:\n            description: Get information about an island.\n          superior.admin.spawn:\n            description: Teleport to the spawn location.\n          superior.admin.spy:\n            description: Toggle chat spy mode.\n          superior.admin.stats:\n            description: Show stats about the plugin.\n          superior.admin.syncupgrades:\n            description: Sync upgrade values for an island.\n          superior.admin.teleport:\n            description: Teleport to other islands.\n          superior.admin.unignore:\n            description: Unignore an island from top islands.\n          superior.admin.withdraw:\n            description: Withdraw money from another player's island bank.\n          superior.admin.world:\n            description: Unlock a world for an island.\n      superior.chat.color:\n        description: Gives access to use colors within island chat."
  },
  {
    "path": "src/main/resources/safe_blocks.yml",
    "content": "######################################################\n##                                                  ##\n##                SuperiorSkyblock 2                ##\n##                Developed by Ome_R                ##\n##                                                  ##\n######################################################\n\n# A list of safe blocks.\n# Players can only get teleported (when teleporting to islands) on blocks from this list.\nsafe-blocks: [ ]"
  }
]